Question

I have a Java Spring 3.2 + Hibernate project.

I used jackson2 annotations (com.fasterxml.jackson.annotation) in the model, and I (guess) the spring rest controller should use jackson2 (aka com.fasterxml.jackson) when serializing the requested objects.

I configured the application with:

        <!-- Use the HibernateAware mapper instead of the default -->
        <bean
            class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="myProj.util.HibernateAwareObjectMapper">
                    <property name="serializationInclusion">
                        <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>

The HibernateAwareObjectMapper is defined this way:

package myProj.util;

import com.fasterxml.jackson.databind.ObjectMapper;

public class HibernateAwareObjectMapper extends ObjectMapper {
private static final long serialVersionUID = -5002954669679467811L;

public HibernateAwareObjectMapper() {
        Hibernate4Module hbm = new Hibernate4Module();
        hbm.enable(Hibernate4Module.Feature.FORCE_LAZY_LOADING);
        registerModule(hbm);
    }
}

so I can state that it extends the com.fasterxml ObjectMapper (OTOH I'm not sure why it was added, since I just inherited the code from other developers).

Note that from what I know spring3.2 should use jackson2 by default. This is mostly working fine but then I have a serialization issue which only happens with a specific service/controller. I have an object which defines a parent, containing the same object as a child. This is resulting in a serialization loop, which ends with an exception on the server side:

[...]
        at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
        at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
        at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
        at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
        at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
        at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
        at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
        at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
[...]

and an incomplete JSON sent to the client.

This is the controller code:

@RequestMapping(value = "/getReleases", method = RequestMethod.POST)
public Map<String, Object> getReleases(@RequestBody Project project) {
    Map<String, Object> subProjectsMap = new HashMap<String, Object>();
    List<Release> releaseList = null;
    try {
        releaseList = jiraService.getReleases(project);
        subProjectsMap.put("success", (releaseList.size() > 0) ? true : false);
        subProjectsMap.put("data", releaseList);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return subProjectsMap;
}

Serialization is performed implicitly by the framework.

The question is: why is spring apparently using org.codehaus.jackson rather than com.fasterxml.jackson as I would expect? Note that the model describing the serialized object is using jackson2 annotations (in particular @JsonBackReference and @JsonIgnore), so they are possibly ignored when using jackson1, which (I think) may result in the loop issue.

After many hours spent banging my head I still don't know why this is happening. Can you provide any hint?

Was it helpful?

Solution

Well, it turned out the problem was due to the missing @ResponseBody annotation in the controller code.

 @RequestMapping(value = "/getReleases", method = RequestMethod.POST)
 public @ResponseBody Map<String, Object> getReleases(@RequestBody Project project) {
      [...]
 }

Adding the @ResponseBody annotation magically fixed the problem for me.

I realized the problem by comparing this controller code with the code from similar controllers which were not showing the issue (silly of me not doing this before), after several vain attempts at digging through the Spring code.

Thanks all for the answers!

OTHER TIPS

Spring automatically configures MappingJackson2HttpMessageConverter when Jackson2 is on the classpath. However, you override this behavior by defining your own bean of type MappingJackson2HttpMessageConverter. First of all, check if it is your bean being used for serialization (e.g. via debugging). Then check its configuration. It seems the constructor of the Hibernate extension to ObjectMapper is not calling super(), which means that configuration of the default SerializerProvider and BeanSerializerFactory is missing. See http://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/ObjectMapper.html for more details.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top