Kennis Blogs JBoss AS7.1 and RESTEasy: upgrading Jackson

JBoss AS7.1 and RESTEasy: upgrading Jackson

We're currently in the process of upgrading our application platform from JBoss 5.1.0 to JBoss AS7.1.1. Since it's quite a big change (especially the transition from AS6 to AS7) things tend to break where you don't expect them to. When writing blog posts, I like to present solutions for problems I encounter in my everyday engineering tasks... So here we go!

 

For JSON related operations Jackson is our weapon of choice, in this case as a provider for RESTEasy (JBoss' JAX-RS implementation). This usually plays out quite well, until we upgraded to JBoss AS7.1.1 when suddenly even the simplest entities couldn't be deserialized. It appears that when using custom Jackson (de)serializers along with the RESTEasy shipped with AS7.1.1, they are ignored. Although you annotated your properties with @JsonDeserialize, the following exception is thrown:

 

org.jboss.resteasy.core.SynchronousDispatcher -  
Failed executing GET /rest/user: org.jboss.resteasy.spi.WriterException: org.codehaus.jackson.map.JsonMappingException: No serializer found  for class my.company.DebtorNumber and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: my.company.Customer[ "debtorNumber" ])
Caused by: org.codehaus.jackson.map.JsonMappingException: No serializer found  for class my.company.DebtorNumber and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: my.company.Customer[ "debtorNumber" ])

 

Especially if you have always packaged your own Jackson dependencies with your application, this can be quite a headache. After some research it occurred to me that JBoss AS7 now ships RESTEasy, which will probably mean it ships its own version of Jackson too. It appears that JBoss AS7.1.1 comes with jackson-mapper-asl v1.9.2 while we always have been packaging v1.9.7. A quick search through Jackson's changelog (thanks JIRA!) brought up this issue which was fixed in v1.9.7.

 

This is where you have to make a fundamental choice:

  1. Exclude the RESTEasy module in your jboss-deployment-structure.xml and package your own version. Leaves other applications in the same container with a broken Jackson container.
  2. Upgrade the Jackson modules shipped with JBoss. Fixes the problem for all applications in the same container, but is quite a bit of work (since there are 4 of them).
  3. Introduce a custom Jackson module which can be used by RESTEasy.

Short on time but keen for a clean solution, I decided to go for option 3 by introducing a new module named org.codehaus.jackson.custom with slot 1.9.7 (which is the new Jackson version).

 

Custom Jackson module

Create the following directory module in your JBoss installation add the specified Jackson JARs and the module.xml below:

 

modules/org/codehaus/jackson/custom/1.9.7/
module.xml
jackson-xc-1.9.7.jar
jackson-mapper-asl-1.9.7.jar
jackson-jaxrs-1.9.7.jar
jackson-core-asl-1.9.7.jar <? xml version = "1.0" encoding = "UTF-8" ?> < module name = "org.codehaus.jackson.custom" slot = "1.9.7" xmlns = "urn:jboss:module:1.1" > < properties > < property name = "jboss.api" value = "private" /> </ properties > < resources > < resource-root path = "jackson-xc-1.9.7.jar" /> < resource-root path = "jackson-mapper-asl-1.9.7.jar" /> < resource-root path = "jackson-jaxrs-1.9.7.jar" /> < resource-root path = "jackson-core-asl-1.9.7.jar" /> </ resources > < dependencies > < module name = "javax.api" /> </ dependencies > </ module >

Upgrading resteasy-jackson-provider's Jackson module

Replace org/jboss/resteasy/resteasy-jackson-provider/main/module.xml in the Jackson module dependencies by our freshly introduced Jackson module:

<module name="org.codehaus.jackson.custom" slot="1.9.7"/>
<? xml version = "1.0" encoding = "UTF-8" ?>
< module name = "org.jboss.resteasy.resteasy-jackson-provider" xmlns = "urn:jboss:module:1.1" >
     < properties >
         < property name = "jboss.api" value = "private" />
     </ properties >
     < resources >
         < resource-root path = "resteasy-jackson-provider-2.3.2.Final.jar" />
         < resource-root path = "resteasy-jackson-provider-2.3.2.Final-jandex.jar" />
     </ resources >
     < dependencies >
         <!--
         <module name="org.codehaus.jackson.jackson-core-asl"/>
         <module name="org.codehaus.jackson.jackson-jaxrs"/>
         <module name="org.codehaus.jackson.jackson-mapper-asl"/>
         <module name="org.codehaus.jackson.jackson-xc"/>
         -->
         <!-- Custom Jackson module -->
         < module name = "org.codehaus.jackson.custom" slot = "1.9.7" />
         < module name = "javax.xml.bind.api" />
         < module name = "javax.api" />
         < module name = "javax.enterprise.api" />
         < module name = "javax.servlet.api" />
         < module name = "javax.ws.rs.api" />
         < module name = "org.jboss.resteasy.resteasy-jaxrs" />
     </ dependencies >
</ module >

Now your application will be provided with Jackson v1.9.7 instead of the bugged v1.9.2 release shipped with JBoss.