Dénes Dénes - 6 months ago 39
Java Question

Handle cycle reference durint json serialization/deserialization

I develop a REST interface, with jackson 1.9.9.
I have these 2 classes, and Parent class contains a list of Child classes, and Child class have a reference to Parent class. (see below)

I want to be able to serialize them to json, and I also need to deserialize the same object from the json I serialized.

What I tried:

public class Child {
private Parent parent;
private Integer id;
private Integer baseId;

public Child(Parent parent, int i) {
this.parent = parent;
this.id = (i+4) * 33;
this.baseId = i;
}

public Integer getBaseId() {
return baseId;
}

public void setBaseId(Integer baseId) {
this.baseId = baseId;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

@JsonBackReference("employer-employee")
public Parent getParent() {
return parent;
}

@JsonBackReference("employer-employee")
public void setParent(Parent parent) {
this.parent = parent;
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Child other = (Child) obj;
if (this.parent != other.parent && (this.parent == null || !this.parent.equals(other.parent))) {
return false;
}
if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
return false;
}
if (this.baseId != other.baseId && (this.baseId == null || !this.baseId.equals(other.baseId))) {
return false;
}
return true;
}

@Override
public int hashCode() {
int hash = 3;
hash = 97 * hash + (this.parent != null ? this.parent.hashCode() : 0);
hash = 97 * hash + (this.id != null ? this.id.hashCode() : 0);
hash = 97 * hash + (this.baseId != null ? this.baseId.hashCode() : 0);
return hash;
}


}

public class Parent {
private Integer id;

private List<Child> list;

public Parent(Integer id){
this.id = id;
list= new ArrayList<Child>();
for(int i=0; i<5; ++i){
list.add(new Child(this, i));
}
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

@JsonManagedReference("employer-employee")
public List<Child> getList() {
return list;
}

@JsonManagedReference("employer-employee")
public void setList(List<Child> list) {
this.list= list;
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Parent other = (Parent) obj;
if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
return false;
}
if (this.list!= other.list&& (this.list== null || this.list.hashCode() != other.list.hashCode())) {
return false;
}
return true;
}

@Override
public int hashCode() {
int hash = 7;
hash = 67 * hash + (this.id != null ? this.id.hashCode() : 0);
hash = 67 * hash + (this.list!= null ? this.list.hashCode() : 0);
return hash;
}


}


EDIT: Equal method fiexed, not causes stackoverflow from now

I followed this article: http://wiki.fasterxml.com/JacksonFeatureBiDirReferences

At the and, it said that I may want to put the annotations on both setters and gettes.

The Json I get from serializating Parent: new Parent(6);

{
"id": 6,
"list": [{
"id": 132,
"baseId": 0
}, {
"id": 165,
"baseId": 1
}, {
"id": 198,
"baseId": 2
}, {
"id": 231,
"baseId": 3
}, {
"id": 264,
"baseId": 4
}]


}

The error I got:


No suitable constructor found for type [simple type, class servicetest.Parent]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: org.apache.catalina.connector.CoyoteInputStream@11b314c4; line: 1, column: 2]


My questions:

Is there any way to solve my problem with JsonManagedReference and JsonBackReference ?
Is there any way to solve this, without writing custom serialization (serialize the Child class parent field as a Long, and when deserializing, try to find it from server and connect the object o it. This would be the worst way to do this I think)

Thanks

Answer

The problem with the code above, that there are no default contructors. Set default constructor to Parent and Child too:

Parent.java:

public class Parent {

    //...

    public Parent(){}

    //...

}

Child.java:

public class Child{

    //...

    public Child(){}

    //....

}