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!
Advertisement
Answer
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.