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?

2 Answers 2

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"}
Sign up to request clarification or add additional context in comments.

3 Comments

hi, may be you know how to get output without "@id"? my question is here stackoverflow.com/questions/33790565/…
@Sloth, I assume you can return null from findObjectIdInfo method int he answer about. I'm sure I understand your use case.
Excellent answer - thanks for sharing all 3 methods.
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);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.