5

I use Jackson 2.2.3 to serialize POJOs to JSON. Then I had the problem, that I couldn't serialize recursive structures...I solved this problem by using @JsonIdentityInfo => works great.

But, I don't want this annotation on the top of my POJO.

So my question is: Is there any other possibility to set the default behavior of my ObjectMapper to use the feature for every POJO?

So I want to transform this annotation code

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")

to something like

ObjectMapper om = new ObjectMapper();
om.setDefaultIdentityInfo(ObjectIdGenerators.IntSequenceGenerator.class, "@id");

Any ideas?

Ilya Ovesnov
  • 4,079
  • 1
  • 27
  • 31
user3227576
  • 554
  • 8
  • 22

2 Answers2

6

You can achieve that using the Jackson mix-in annotations or the Jackson annotation introspector.

Here is an example showing both methods:

public class JacksonJsonIdentityInfo {
    @JsonIdentityInfo(
            generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@id")
    static class Bean {
        public final String field;

        public Bean(final String field) {this.field = field;}
    }

    static class Bean2 {
        public final String field2;

        public Bean2(final String field2) {this.field2 = field2;}
    }

    @JsonIdentityInfo(
            generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@id2")
    static interface Bean2MixIn {
    }

    static class Bean3 {
        public final String field3;

        public Bean3(final String field3) {this.field3 = field3;}
    }

    static class MyJacksonAnnotationIntrospector extends JacksonAnnotationIntrospector {
        @Override
        public ObjectIdInfo findObjectIdInfo(final Annotated ann) {
            if (ann.getRawType() == Bean3.class) {
                return new ObjectIdInfo(
                        PropertyName.construct("@id3", null),
                        null,
                        ObjectIdGenerators.IntSequenceGenerator.class,
                        null);
            }
            return super.findObjectIdInfo(ann);
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        final Bean bean = new Bean("value");
        final Bean2 bean2 = new Bean2("value2");
        final Bean3 bean3 = new Bean3("value3");
        final ObjectMapper mapper = new ObjectMapper();
        mapper.addMixInAnnotations(Bean2.class, Bean2MixIn.class);
        mapper.setAnnotationIntrospector(new MyJacksonAnnotationIntrospector());
        System.out.println(mapper.writeValueAsString(bean));
        System.out.println(mapper.writeValueAsString(bean2));
        System.out.println(mapper.writeValueAsString(bean3));
    }    
}

Output:

{"@id":1,"field":"value"}
{"@id2":1,"field2":"value2"}
{"@id3":1,"field3":"value3"}
Alexey Gavrilov
  • 10,593
  • 2
  • 38
  • 48
  • hi, may be you know how to get output without "@id"? my question is here http://stackoverflow.com/questions/33790565/jsonidentityinfo-how-to-not-serialize-id-property – serhii Nov 18 '15 at 22:16
  • @Sloth, I assume you can return null from findObjectIdInfo method int he answer about. I'm sure I understand your use case. – Alexey Gavrilov Nov 19 '15 at 11:09
  • Excellent answer - thanks for sharing all 3 methods. – matt forsythe Mar 22 '18 at 20:12
0

After several months and a lot of research, I've implemented my own solution to keep my domain clear of jackson dependencies.

public class Parent {
    private Child child;
    public Child getChild(){return child;} 
    public void setChild(Child child){this.child=child;}
}

public class Child {
    private Parent parent;
    public Child getParent(){return parent;} 
    public void setParent(Parent parent){this.parent=parent;}
}

First, you have to declare each of your entities of the bidirectional relationship:

public interface BidirectionalDefinition {

    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=Parent.class)
    public interface ParentDef{};

    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=Child.class)
    public interface ChildDef{};

}

After that, the object mapper can be automatically configured:

ObjectMapper om = new ObjectMapper();
Class<?>[] definitions = BidirectionalDefinition.class.getDeclaredClasses();
for (Class<?> definition : definitions) {
    om.addMixInAnnotations(definition.getAnnotation(JsonIdentityInfo.class).scope(), definition);
}
Pablo
  • 2,430
  • 1
  • 13
  • 11