4

I have two entities which are bidirectional mapped. A vehicle which has a collection of registrations and the registration itself. These entities are exposed as REST services.

@Entity
@XmlRootElement
public class Vehicle implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String brand;
  private String type;

  @OneToMany(mappedBy = "vehicle", fetch = FetchType.EAGER)
  private List<Registration> registrations;
}

The problem is that the FetchType.EAGER produces an infinite recursion.

@Entity
@XmlRootElement
public class Registration implements Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;

  @ManyToOne
  private Vehicle vehicle;
}

After some researching I figured out that I have to add the annotation @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") to the Vehicle class to solve the problem.

My question is: What does the PropertyGenerator class actually do?

ammerzon
  • 998
  • 1
  • 13
  • 30

1 Answers1

4

The problem is not because of FetchType.EAGER. FetchType.EAGER is a JPA annotation and does not come into play when you are serializing an instance of Vehicle using Jackson.

What's actually happening is that Jackson is serializing a Vehicle, which triggers serialization of the list of Registrations, which serializes a Vehicle, which has a list of Registrations, and so on forever.

As you noticed, the @JsonIdentityInfo annotation short circuits the infinite recursion, but it's not because of the specific PropertyGenerator that you have specified. The JavaDoc for @JsonIdentityInfo gives some insight into what's going on:

@JsonIdentityInfo Annotation used for indicating that values of annotated type or property should be serializing so that instances either contain additional object identifier (in addition actual object properties), or as a reference that consists of an object id that refers to a full serialization. In practice this is done by serializing the first instance as full object and object identity, and other references to the object as reference values.

In other words, the first time you serialize something you'll get the full serialized JSON/XML version. The next time that object is serialized then you will get a reference to that first serialized object.

There are other ways to solve this problem too. Check out Infinite Recursion with Jackson JSON and Hibernate JPA issue (your question is arguably a duplicate of this one). The answers there suggest you can also use @JsonIgnore or a combination of @JsonManagedReference and @JsonBackReference to avoid the infinite recursion.

Now, to your specific question about what the PropertyGenerator actually does: it instructs Jackson to use a specific property from your class as the reference to the full serialized version of the object. You specified "id" as the property so in your resulting serialized JSON/XML you should see that if you have an object with ID of 342 then the first serialized object will show the id and all other serialized properties but each subsequent time that object is serialized you will just see the 342 serialized as a reference to the original object.

Community
  • 1
  • 1
Erik Gillespie
  • 3,929
  • 2
  • 31
  • 48