Customizing Root Node Name in Jackson JSON Processor - JAXB Route

By default, Jackson JSON processor does not wrap the JSON object with the root name when used with JaxB Introspection(@JsonRootName will work for non-JaxB implementation). You can enable this feature by setting the property SerializationConfig.Feature.WRAP_ROOT_VALUE and DeserializationConfig.Feature.UNWRAP_ROOT_VALUE to true.

Domain Object - User.java

@XmlType(name = "user")
public class User implements Serializable {

    @XmlElement(name = "first_name")
    protected String firstName;

    @XmlElement(name = "last_name")
    protected String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String value) {
        this.firstName = value;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String value) {
        this.lastName = value;
    }
}
Default Jackson generated JSON Output
{"first_name": "James", "last_name": "Gosling"}
With WRAP_ROOT_VALUE=true
{"User": {"first_name": "James", "last_name": "Gosling"} }
All good? Not yet. Noticed the naming convention used in the root node? It came out in Pascal case(begins with a capital letter), how? By default Jackson uses class name as the root name. This makes our JSON output ugly. Let us find a way to make this root name inline with our naming convention.

JaxbAnnotationIntrospector for your rescue

We can tell Jackson ObjectMapper to use JAXB annotations to map objects with name and change the behavior of name generation by providing a customized version of JaxbAnnotationIntrospector. We can use this class to change the root name or even the property names; change to lower case, change to upper case, suffix or prefix names with custom string or even give new name to the elements.

Name root element as defined in JaxB

Below class overrides findRootName() of JaxbAnnotationIntrospector and returns the XmlType as root name.
public class MyAnnotationIntrospector extends JaxbAnnotationIntrospector {
 @Override
 public String findRootName(AnnotatedClass ac) {

  return ac.getAnnotations().get(XmlType.class).name();
 }
}
If you want to do it for only specific domain objects, you can add the below condition:
 if(ac.getAnnotated().getName().equalsIgnoreCase("com.texient.domain.User")) {...}
Now you can use this introspector in the mapper object:
public class MyObjectMapperFactory {

    public static ObjectMapper createMapper() {

        final ObjectMapper mapper = new ObjectMapper(); 
        final JaxbAnnotationIntrospector myAnnotationIntrospector = new MyAnnotationIntrospector();

        final DeserializationConfig deserializeConf = mapper.getDeserializationConfig()  
                .with(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE)
                .withAnnotationIntrospector(myAnnotationIntrospector);

        mapper.setDeserializationConfig(deserializeConf);

        final SerializationConfig serializeConf = mapper.getSerializationConfig()
                .with(SerializationConfig.Feature.WRAP_ROOT_VALUE)
                .withSerializationInclusion(JsonSerialize.Inclusion.NON_NULL)
                .withAnnotationIntrospector(myAnnotationIntrospector);

        mapper.setSerializationConfig(serializeConf);

        return mapper;
    }
}

Conclusion

So, with a custom Annotation Introspector you can customize the way the JSON serialization and de-serialization are done. Feel free to drop your feedback below.

3 Comments

Did you enjoy this post? Why not leave a comment below and continue the conversation, or subscribe to our feed and get articles like this delivered automatically to your feed reader? Like our Facebook Page.

  1. This blog tries to prevent copying and pasting of example code in a (not very effective) rude manner. What's the point of posting this if you don't want anyone to use these snippets?

    There is no more setSerializationConfig (in Jackson 2.4.1 at least), you can simply use mapper.setAnnotationIntrospector(…).

    ReplyDelete
    Replies
    1. Don't copy+paste, understand the concept and then implement it on your own :) You are right, setSerializationConfig() is available only in older versions, i think below 2.0 versions, which has package org.codehaus.jackson.* not with com.fasterxml.jackson.*.

      Delete
Post a Comment
Previous Post Next Post