1

first of all I want to state that I'm fairly new to this JPA / Hibernate thing and also micronaut is new for me (I have much experience in for example PHP, Python, "Desktop Java", C++ and so on).

I cannot get rid of the feel that I'm misunderstanding something in the concept when I'm passing entities via the micronaut @Body annotation as they come in detached and I have to merge them into the persistence context manually using em.merge(entity).

Please consider the following example (shortened to just show the important portions):

MyEntity.java:

import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "entities")
@Getter
@Setter
@ToString
public class Entity{
    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;

    @Column
    protected String name;
}

MyController.java:

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.*;

@Controller("/entities")
public class EntitiyCrudController {

    @Inject
    private final EntityManager entityManager;

    @Post("/create")
    public HttpResponse create(@Body Entity entity) {
        try {
            entity = entityManager.merge(entity);
            return HttpResponse.ok(entity);
        } catch (ConstraintViolationException exception) {
            return HttpResponse.badRequest();
        }
    }

}

Please note that the samples are just copied together, so there might be some errors, but I think this is more a question that is about the right approach to choose.

During my research all examples I've seen so far are about persisting entities that are not detached. Sometimes I've seen people using DTOs (exact copies of the entity classes on the property level but without the jpa / hibernate annotations). I think this approach also have some smell as I have to build a whole new class which has the exact same properties.

I would have no big problem using DTOs if there weren't the transfering of the properties of the dto to the entity (calling dto getter, calling entity setter). Is there a "clean" way to do this without transfering every property manually (maybe some reflection based library or an annotation processor). Then I could load an entity from the persistence context via the dto id and then update my entity fields and trigger an update.

In summary my problems are: - Passing Entities directly is leading to the entities being detached (So for example the micronaut- data package cannot do updates this way) - Using DTOs one ends up copying property by property which is very verbose

So which is the right way posting an object via json to a webserver and saving or updating it?

If something isn't understandable I'm happy to clarify it!

kevdev
  • 13
  • 2
  • IMO the DTO approach is the correct one. Usually it also turns out that not all properties and not in the same form are passed from JPA into DTO. As for the conversion JPA -> DTO and back, several reflection-based approaches exists, but in the end it also turns out that manually copiyng the properties is the most robust approach in the long term. Note that it is also possible to populate the DTO directly with Hibernate query. – Michal Oct 11 '19 at 08:47

2 Answers2

1

IMO DTO approach is the way to go ahead when passing data to UI layer from persistence layer. Try using Dozer entity copier (https://www.baeldung.com/dozer). This will help you reduce lot of boiler-plate code of copying from one entity to another.

Abhishek Shinde
  • 101
  • 1
  • 3
  • Don't use Dozer since its very old, outdated and makes heavy use of reflection (Micronaut tries to remove all reflection). I recommend to use Mapstruct (https://mapstruct.org/) instead. It uses annotation processors such as Micronaut does. – saw303 Oct 11 '19 at 09:28
  • Mapstruct looks really neat, I like the no reflection approach. – kevdev Oct 11 '19 at 13:44
0

The approach you describe has nothing wrong by itself. But you have to be aware what you are doing, you are coupling your rest interface with your DB implementation. Deppending on your requirements this will probably be a problem. For instance, if your application need Optimistic Concurrency, you will need to add a @Version field in your entity, and you will automatically expose this information through the web service.

Generally you want to have control over the data that is exposed and generally you want to decouple the DB implementation of the rest API. And by the way, generally you also want to have a domain object with business logic for validation, business rules...

Alvaro Arranz
  • 444
  • 2
  • 5
  • Marked this as the accepted answer for outlining the impact on application design (persistence layer, validation layer, business logic layer) and the @Version thing (didn't even thought of that :D). Thank you! – kevdev Oct 11 '19 at 13:43
  • 1
    Actually, the only way to handle optimistic locking in a web app is to have the version field exposed to the client. https://stackoverflow.com/a/19456821/1356423. – Alan Hay Oct 18 '19 at 22:46