What is a good strategy for converting jpa entities into restful resources
Asked Answered
N

4

29

Restful resources do not always have a one-to-one mapping with your jpa entities. As I see it there are a few problems that I am trying to figure out how to handle:

  1. When a resource has information that is populated and saved by more than one entity.
  2. When an entity has more information in it that you want to send down as a resource. I could just use Jackson's @JsonIgnore but I would still have issue 1, 3 and 4.
  3. When an entity (like an aggregate root) has nested entities and you want to include part of its nested entities but only to a certain level of nesting as your resource.
  4. When you want to exclude once piece of an entity when its part of one parent entity but exclude a separate piece when its part of a different parent entity.
  5. Blasted circular references (I got this mostly working with JSOG using Jackson's @JsonIdentityInfo)

Possible solutions: The only way I could think of that would handle all of these issues would be to create a whole bunch of "resource" classes that would have constructors that took the needed entities to construct the resource and put necessary getters and setters for that resource on it. Is that overkill?

To solve 2, 3, 4 , and 5 I could just do some pre and post processing on the actual entity before sending it to Jackson to serialize or deserialize my pojo into JSON, but that doesn't address issue 1.

These are all problems I would think others would have come across and I am curious what solutions other people of come up with. (I am currently using JPA 2, Spring MVC, Jackson, and Spring-Data but open to other technologies)

Nickolasnickolaus answered 26/7, 2013 at 6:48 Comment(0)
M
28

With a combination of JAX_RS 1.1 and Jackson/GSON you can expose JPA entities directly as REST resources, but you will run into a myriad of problems.

DTOs i.e. projections onto the JPA entities are the way to go. It would allow you to separate the resource representation concerns of REST from the transactional concerns of JPA. You get to explicitly define the nature of the representations. You can control the amount of data that appears in the representation, including the depth of the object graph to be traversed, if you design your DTOs/projections carefully. You may need to create multiple DTOs/projections for the same JPA entity for the different resources in which the entity may need to be represented differently.

Besides, in my experience using annotations like @JsonIgnore and @JsonIdentityInfo on JPA entities doesnt exactly lend to more usable resource representations. You may eventually run into trouble when merging the objects back into the persistence context (because of ignored properties), or your clients may be unable to consume the resource representations, since object references as a scheme may not be understood. Most JavaScript clients will usually have trouble consuming object references produced by the @JsonidentityInfo annotation, due to the lack of standardization here.

There are other additional aspects that would be possible through DTOs/projections. JPA @EmbeddedIds do not fit naturally into REST resource representations. Some advocate using the JAX-RS @MatrixParam annotation to identify the resource uniquely in the resource URIs, but this does not work out of the box for most clients. Matrix parameters are after all only a design note, and not a standard (yet). With a DTO/projection, you can serve out the resource representation against a computed Id (could be a combination of the constituent keys).

Note: I currently work on the JBoss Forge plugin for REST where some or all of these issues exist and would be fixed in some future release via the generation of DTOs.

Molli answered 30/7, 2013 at 7:48 Comment(3)
Thanks for your detailed answer. When first looking at this I had seen a few people mention DTOs as a possible solution, but often there were comments right after stating you shouldn't add another layer. It sounds like you wouldn't create a DTO for all of your entities just when you need a resource that is not a one-to-one mapping of an existing jpa entity. Is that right?Nickolasnickolaus
That's right. Simple object models especially ones with uni-directional relationships, and where the depth of the object graph is no more than 2, would benefit from a direct mapping between JPA entities and REST resources. However, in the real world, I haven't seen numerous examples of such models.Molli
As a follow up, I have been using the DTO pattern for a while now and they were totally the way to go. Thanks again for your thoughts :)Nickolasnickolaus
W
11

I agree with the other answers that DTOs are the way to go. They solve many problems:

  1. Separation of layers and clean code. One day you may need to expose the data model using a different format (eg. XML) or interface (eg. non web-service based). Keeping all configuration (such as @JsonIgnore, @JsonidentityInfo) for each interface/format in domain model would make is really messy. DTOs separate the concerns. They can contain all the configuration required by your external interface (web-service) without involving changes in domain model, which can stay web-service and format agnostic.

  2. Security - you easily control what is exposed to the client and what the client is allowed to modify.

  3. Performance - you easily control what is sent to the client.

  4. Issues such as (circular) entity references, lazily-loaded collections are also resolved explicitly and knowingly by you on converting to DTO.

Wandering answered 30/7, 2013 at 9:25 Comment(0)
D
2

Given your constraints, there looks to be no other solution than Data Transfer Objects - yes, it's occurring frequently enough that people named this pattern...

Durango answered 26/7, 2013 at 7:4 Comment(0)
F
0

If you application is completely CRUDish then the way to go is definitely Spring Data REST in which you absolutely do not need DTOs. If it's more complicated than that you will be safer with DTOs securing the application layer. But do not attempt to encapsulate DTOs inside the controller layer. They belong to a service layer cause the mapping is also the part of logic (what you let in the application and what you let out of it). This way the application layer stays hermetic. Of course in most cases it can be the mix of those two.

Framing answered 23/11, 2017 at 13:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.