I am developing rest web app with spring framework, Hibernate and JSON. Please Assume that I have two entities like below:
BaseEntity.java
@MappedSuperclass
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id" )
public abstract class BaseEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    public long getId() {
        return id;
    }
}
University.java
 public class University extends BaseEntity {
      private String uniName;
       @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,orphanRemoval = true)
      @JoinColumn(name = "university_id")
        private List<Student> students=new ArrayList<>();
    // setter an getter
    }
Student.java
    public class Student extends BaseEntity{
        private String stuName;
        @ManyToOne(fetch = FetchType.EAGER)
        @JoinColumn(name = "university_id",updatable = false,insertable = false)   
        private University university;
    // setter an getter
        }
when I call my rest api to list University every things work fine as I expect, but when I call my rest api to list student eagerly my JSON response is
[
   {
    "id": 1,
    "stuName": "st1",
    "university": {
        "id": 1,
        "uniName": "uni1"
                 }
    },
    {
        "id": 2,
        "stuName": "st2",
        "university": 1
    }
]
but my desired response is:
[
    {
        "id": 1,
        "stutName": "st1",
        "university": 
        {
         "id": 1,
        "uniName": "uni1"
        }
    },
    {
        "id": 2,
        "stutName": "st2",
        "university": 
        {
         "id": 1,
        "uniName": "uni1"
        }
    }
Update 1: my hibernate annotation working fine I have JSON issue
Requirements :
I need both side fetch eagerly(the university side is Ok)
I need university object in student side for every student(when I fetching student eagerly)
What kind of serialization or JSON config I need to do that for matching my desired response?
Update 2:
by removing @JsonIdentityInfo and editing student side like below:
@ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "university_id",updatable = false,insertable = false) @JsonIgnoreProperties(value = "students", allowSetters = true) private University university;
the json response still same I need my desired response that is mentioned above.
thanks
I had the same problem. Hibernate (or eclipselink) are not the problem. The only constraint in JPA is the FetchType.EAGER .
In the BaseEntity I have added a standard method
public String getLabel(){
   return "id:"+this.getId();
}
this method would be abstract, but I had a lot of class and i didn't want to change it all so I added a default value.
In parent entity, in this case University, override the method
@Override
public String getLabel{
    return this.uniName;
}
For each parent class, use a particular field as a label for your entity
Define a MyStandardSerializer:
public class StandardJsonSerializer extends JsonSerializer<EntityInterface> {
@Override
public void serializeWithType(EntityInterface value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException {
        serialize(value, jgen, provider); 
}
@Override
public void serialize(EntityInterface value, JsonGenerator jgen, SerializerProvider provider) 
  throws IOException, JsonProcessingException {
    jgen.writeStartObject();
    jgen.writeNumberField("id", (long) value.getId());
    jgen.writeStringField("label", value.getLabel());
    jgen.writeEndObject();
}
}
In the student class, on univrsity add:
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "university_id",updatable = false,insertable = false)   
@JsonSerialize(using=StandardJsonSerializer.class)
private University university;
Now you have resolved circularity. When you need a label, override the method in the parent entity. When you need some particular fields, create a specific Serializer.
You might want to try using @JsonRawValue as an annotation for your university property. The behavior you're encountering is due to reference collapsing - since it's the same University twice, the serializer tries to be smart and just return a reference the second time it's encountered.
EDIT: The toString():
@Override
public String toString() {
    ObjectMapper mapper = new ObjectMapper();
    return mapper.writeValueAsString(this);
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With