Skip to content
Advertisement

@JsonIdentityInfo serialization of items

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.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement