Tuesday, January 25, 2011

Marshal Json data using Jackson in Spring MVC with Jaxb Annotations

The title is quite a mouthful but let me explain...For the DevNexus.com website I want to provide the website's data not only via XML but also via JSON in order to provide maximum flexibility for other consuming services. E.g. Pratik Patel pinged me the other day that he intends building an IPad client and Charlie Collins is planning to update his DevNexus Android client, which he originally created for the 2010 conference (The pressure is on gentleman ;-).

The DevNexus website is based on Spring MVC 3.0 and provides RESTful Urls that render Html views of the data (Targeting traditional browser clients as well as mobile client using Spring Mobile and jQuery Mobile).

Thus, I configured Restful endpoints as described in my last blog post. The easiest way to marshal JSON in Spring MVC is via the Jackson Java JSON-processor. Spring has a few documentation pointers regarding that. Theoretically, the setup is fairly simple and in its simplest forms means to just put the Jackson jar file onto your class path and adding mvc:annotation-driven to your Spring Xml Context file (See Chapter 15.12.1 of the Spring documentation). No sweat.

To get started more specifically with Jackson, here are some blog entries that I came accross while diving deeper into it:
While the tutorials may make you think that serializing JSON is happening defacto automatically, it turned out, that I had to fine-tune my domain model for Jackson. My domain model objects have bi-directional relationships and and I was getting a ton of errors of type:

java.lang.StackOverflowError - org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

You can configure Jackson's marshalling behavior by annotating your domain model objects. However, those annotations are Jackson specific and I already was annotating my obejects with Jaxb annotations for the Xml marshalling of data.

Well - cool beans - , it turns out, Jackson can indeed use Jaxb annotations to renders Json data (added with version 1.1 of Jackson).

But how do I configure Jackson? How do I make it work in my Spring environment? I came across 2 blogs, that combined, provided the necessary solution.

The first example I found here, which provides a really nice example.

Furthermore, I not only wanted to configure Jackson to use Jaxb annotations, but I also needed to make it work for my Spring environment. For that Kyrill Alyoshin has some good information on his blog (
He also details how to make Jackson work better with Hibernate, which sounds interesting and I may return to his blog entry more specifically for that.).

Basically the best way to integrate Jackson and Spring is to create a custom ObjectMapper class that enables Jaxb support and which can then be injected into Spring's MappingJacksonJsonView.

Here are the things that were needed to get things going for my project -

First, add the following Maven Dependencies (jackson-xc provides the additional Jaxb support):
<!-- Jackson JSON Mapper -->
 <dependency>
     <groupId>org.codehaus.jackson</groupId>
     <artifactId>jackson-core-lgpl</artifactId>
     <version>1.6.4</version>
 </dependency>
 <dependency>
     <groupId>org.codehaus.jackson</groupId>
     <artifactId>jackson-mapper-lgpl</artifactId>
     <version>1.6.4</version>
 </dependency>
 <dependency>
     <groupId>org.codehaus.jackson</groupId>
     <artifactId>jackson-xc</artifactId>
     <version>1.6.4</version>
 </dependency>

The custom ObjectMapper:
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;

public class JaxbJacksonObjectMapper extends ObjectMapper {

 public JaxbJacksonObjectMapper() {
  final AnnotationIntrospector introspector
      = new JaxbAnnotationIntrospector();
  super.getDeserializationConfig()
       .setAnnotationIntrospector(introspector);
  super.getSerializationConfig()
       .setAnnotationIntrospector(introspector);
    }

} 

The SpringContext configuration that wires everything together:
    <bean class="org.springframework.web.servlet.view
        .ContentNegotiatingViewResolver">
        <property name="order" value="1" />
        <property name="ignoreAcceptHeader" value="true" />
        <property name="mediaTypes">
            <map>
                <entry key="xml"  value="application/xml"/>
                <entry key="json" value="application/json"/>
            </map>
        </property>
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view
          .xml.MarshallingView">
                    <property name="marshaller" 
                      ref="jaxbMarshaller"/>
                </bean>
                <bean
                    class="org.springframework.web
.servlet.view.json.MappingJacksonJsonView">
                    <property name="objectMapper"
 ref="jaxbJacksonObjectMapper"/>
                </bean> 
            </list>
        </property>
    </bean>

5 comments:

Stephen Souness said...

Hi Gunnar.

Was it really necessary to create that JaxbJacksonObjectMapper class?

Surely you could have had your Spring configuration instantiate the JaxbAnnotationIntrospector and an ObjectMapper and inject the JaxbAnnotationIntrospector in?

edlovesjava said...

Thanks for your guidance on this post.

Did you ever solve the parent/child relationship (bi-direcitonal relationship) with Jackson mapping using JAXB annotations alone? Since Jackson doesn't support XmlID and XmlIDREF, what else do we do? Mix annotations (JAXB and JSON?)

Dan Koch said...

Thanks Gunnar! This was extremely helpful!

For folks looking to accomplish this entirely through Spring configuration, here's one way of going about it:











You can also create the JaxbAnnotationIntrospector outside of the deserializationConfig and serializationConfig -- it's a matter of stylistic preference.

andry said...

json is a very interesting language to be used. very good tutorial and can hopefully help me in building json in the application that I created for this lecture. thank you

Willie Wheeler said...

Somehow Dan's configuration seems to have been lost, so I'll post what I did:

<bean id="jaxbAnnotationIntrospector" class="org.codehaus.jackson.xc.JaxbAnnotationIntrospector" />
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper">
<property name="serializationConfig.annotationIntrospector" ref="jaxbAnnotationIntrospector" />
<property name="deserializationConfig.annotationIntrospector" ref="jaxbAnnotationIntrospector" />
</bean>

Good luck.