How to get json response only with an id of the related entity

featured_image

Fetching entities with complex relationships can consume a lot of resources during calls to your API. To minimize the size of the requested json string, you can use the LAZY fetch type. This will result in accessing only the serialized object and its properties – without considering its relations. But often you need to obtain the identifiers of the associated objects as well. Check out how to fetch an entity with an id of a related object while preserving proper serialization and deserialization.

What we are going to build

The example Task class has id and name properties and requires Many-to-One relation with the Project entity. We want the json representation of a Task instance to look like this:

You can achieve it by using @JsonIdentityInfo annotation alongside with @JsonIdentityReference. However, it may spawn the following error when the data is deserialized back to an object: "Unresolved forward references for related entity".

Let’s divide our venture into the following stages.

Requirements

The following fragment of the pom.xml file shows dependencies used in the project:

Define the relation between two entities

Let’s define the Many-to-One relation to the Project entity. When our API is requested for task data, we want to avoid fetching a related project with all other tasks associated with it. So we specify the fetch type to LAZY. You can see the relation between task and project entities defined in the following code snippet from the Task entity:

The @OnDelete annotation allows removing all child records (tasks) whenever the parent record (project) is deleted.

Include the id property from the related entity when fetching the object

If you need a serialized instance of a task containing an identifier of a related project, add @JsonIdentityInfo annotation when defining the relation:

Enforce use of the related object id

To ensure that the project id  will be properly included as a task property during serialization, add the @JsonIdentityReference annotation:

Set alwaysAsId option to true in order to serialize all referenced values as ids. In the annotation documentation you can read that:

“(…) if value of ‘true’ is used, deserialization may require additional contextual information, (…) the default handling may not be sufficient.”

Fix the deserialization issue

To help deserialize the task object properly, add the @JsonProperty annotation and specify the json object field name – "projectId":

Furthermore, we need the setter for the project property:

We are using a static factory method, as described in Effective Java (3rd Edition) by Joshua Bloch. To obtain a new Project instance with only id specified, add the following method to the Project entity:

After deserialization, the project property of the task object will hold a Project instance in which only the id property is set to an actual value.

Verify the results

The task instance was fully serialized and the related project was passed as a reference value and included in the json representation of the task as its property. To ascertain this, let’s add to the project the following test –  getsTaskById():

The source code for the Task entity

Photo by Toni Cuenca on StockSnap

6 thoughts on “How to get json response only with an id of the related entity

  1. Nice blog but I think setProjectFromId() method in the integration test should be renamed to setProjectById() as  declared in the Task class.
    I didn’t get really why we need to add the setter for projectId and why we must specify projectId in the JsonProperty annotation.

  2. thank you!

    I aws going crazy with  “com.fasterxml.jackson.databind.deser.UnresolvedForwardReference: Unresolved forward references for ” exception

    That help me me a lot!

  3. Very nice post which helped me a lot, however once versions are updated, to me it didn’t work. Using jackson 2.11.1, I needed to do quite different which on this example would be:

    In the Project class having the annotation: @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = Project.class) in the class level

    My Task class became also a little different:

    @ManyToOne(fetch = FetchType.EAGER, optional = false) //fetch must be eager here, however in scenarios where this cannot happen, need to solve the problem related to the lazy initialization of the relationship.

    @JsonProperty("projectId")
    private Project project;

    1. After this post I realized that also what I tried to use before didn’t work the way I was expecting, but at least that shed some light to a very simple solution once what I wanted mostly was to avoid sending the whole instance of the relationship as part of a response (JSON) from an http request.

      Just used getters and setters to return only the desired property of the related entity and used @JsonIgnore from Jackson to avoid sending the whole entity of the relationship and created getters and setters to the specific property of the relationship that I want to deal with.

Leave a Reply

Your email address will not be published. Required fields are marked *