2

I have a Spring Boot 2 application in which I have the following User entity:

@Data
... JPA and other annotations
class User {
    ... many fields including Integer id
    @ManyToOne(fetch = FetchType.LAZY)
    public User createBy;
    @ManyToOne(fetch = FetchType.LAZY)
    public User updateBy;
}

Now, the main problem I am facing right now is the self-reference of User (from User) and this either is causing StackOverflow Exceptions or InvalidDefinitionException depending on the certain annotations I am using on User. This issue is very common and several solutions are discussed over the internet which are:

1. Annotate both fields with @JsonBackReference Annotating with @JsonBackReference omits the updateBy and createBy fields altogether, meaning I am not getting them when desired in my API responses.

2. Annotate class with @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") or None.class or IntSequenceGenerator.class or UUIDGenerator.class This approach works fine, until the serializer finds the same user object somewhere down the json and instead of putting it up there again, it puts a reference of that object based on the class selected above. e.g.

[
  {"id": 1, ..., "createBy": {"id": 2, ...},
  2 // <- Let's ignore how user 1 is created by user 2 and notice that instead of a user object, I get an integer ID reference.
]

This means, the client parsing this data will often there to be an object and not a number, causing parsing errors.

3. Implementing a custom serializer (or extending an existing one) Now, I am really unsure if this is the right way to go about achieving my goals (mentioned below). But if this is the right approach, how would I go about handling this self-reference?

GOALS:

  1. Serialize the data so that, at least certain fields in the child object (user) are passed back, preventing further recursive calls.
{
  "id": 1, "name": "old user", .. many other fields .., "createBy": {id: 2, "name": "2nd user"}
}
  1. When the client sends a user object as request body, the application needs only the id of the child entity and not the whole object, as below:
{
   "name": "new user", ...., "createBy": {id: 1}
}

I know that self-referencing is integral to ORMs and there are a lot of use cases for self-referencing. But how do professional developers/applications handle this issue, especially in Spring Framework? If a custom serializer is the only way to go, how do I make it function appropriately?

Also, is it advisable to exclude these fields (createBy and updateBy) from EqualsAndHashCode and ToString methods?

sbsatter
  • 591
  • 3
  • 22

0 Answers0