I'm trying to serialize relations using @JsonItentityInfo to avoid circular references. I've created a test to try test the result of the serialization, and I've found that jackson is not behaving as I expected. The serialization in not what I though it would be and, in fact, when I try to desarialize the serializated object, an exception is thrown. The code I'm using is:
public class Test {
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public static class A {
private final String id;
private final String name;
private final B b;
public A(final String id, final String name, final B b) {
this.id = id;
this.name = name;
this.b = b;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
public B getB() {
return this.b;
}
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public static class B {
private final String id;
private final String name;
public B(final String id, final String name) {
this.id = id;
this.name = name;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
}
public static void main(final String[] args) {
try {
System.out.println(
new ObjectMapper().writeValueAsString(new A("1", "a", new B("2", "b"))));
} catch (final JsonProcessingException e) {
e.printStackTrace();
}
}
}
To my understanding, the output should be
{"id":"1","name":"a","b":"2"}
but the test returns
{"id":"1","name":"a","b":{"id":"2","name":"b"}}
In fact, when trying to read the serialized string jackson throws an exception. What am I doing wrong?
Thank you all for your help
Edit: The example was not complete. The object should be enveloped in another object, so the two of them are serialized.
package lvillap.deliverytoolsserver.domain;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Test {
private final A a;
private final B b;
public Test(final A a, final B b) {
this.a = a;
this.b = b;
}
public A getA() {
return this.a;
}
public B getB() {
return this.b;
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public static class A {
private final String id;
private final String name;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = true)
private final B b;
public A(final String id, final String name, final B b) {
this.id = id;
this.name = name;
this.b = b;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
public B getB() {
return this.b;
}
}
public static class B {
private final String id;
private final String name;
public B(final String id, final String name) {
this.id = id;
this.name = name;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
}
public static void main(final String[] args) {
try {
final B b = new B("2", "b");
final A a = new A("1", "a", b);
System.out.println(new ObjectMapper().writeValueAsString(new Test(a, b)));
} catch (final JsonProcessingException e) {
e.printStackTrace();
}
}
}
When implemented this way, the result is the expected: {"a":{"id":"1","name":"a","b":"2"},"b":{"id":"2","name":"b"}}
Thank you all for you help!
Under default circumstances, you get exactly what you you should get.
What you can do is change you class A
like follows.
Note that I have changed getB()
method. It no longer return instance of class B
. It returns id
attribute of that class B
instance.
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public static class A {
private final String id;
private final String name;
private final B b;
public A(final String id, final String name, final B b) {
this.id = id;
this.name = name;
this.b = b;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getB() {
return this.b.id;
}
}
You can also create a custom serializer for class B
as well.