杰克逊弹簧控制器序列化

时间:2014-05-06 15:44:08

标签: java json spring spring-mvc jackson

我有一个Java Spring 3.2 + Hibernate项目。

我在模型中使用了jackson2注释(com.fasterxml.jackson.annotation),并且我(猜测)当序列化请求的对象时,弹簧控制器应该使用jackson2(aka com.fasterxml.jackson)。

我为应用程序配置了:                      

        <!-- 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>

HibernateAwareObjectMapper以这种方式定义:

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);
    }
}

所以我可以声明它扩展了com.fasterxml ObjectMapper(OTOH我不知道它为什么被添加,因为我只是继承了其他开发人员的代码)。

请注意,据我所知,spring3.2默认情况下应该使用jackson2。 这大部分工作正常,但后来我有一个序列化问题,只有特定的服务/控制器才会发生。我有一个定义父对象的对象,包含与子对象相同的对象。这导致序列化循环,在服务器端以例外结束:

[...]
        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)
[...]

以及发送给客户端的不完整JSON。

这是控制器代码:

@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;
}

序列化由框架隐式执行。

问题是:为什么春天显然使用org.codehaus.jackson而不是com.fasterxml.jackson,正如我所期望的那样?请注意,描述序列化对象的模型使用jackson2注释(特别是@JsonBackReference和@JsonIgnore),因此在使用jackson1时可能会忽略它们(我认为)可能会导致循环问题。

经过几个小时的敲打我的脑袋后,我仍然不知道为什么会这样。你能提供任何提示吗?

2 个答案:

答案 0 :(得分:2)

嗯,事实证明问题是由于控制器代码中缺少@ResponseBody注释。

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

添加@ResponseBody注释神奇地修复了我的问题。

我通过将这个控制器代码与来自类似控制器的代码进行比较来意识到这个问题,这些代码没有显示出问题(我以前没有这么做过傻),经过几次徒劳的尝试挖掘Spring代码。

谢谢大家的答案!

答案 1 :(得分:1)

MappingJackson2HttpMessageConverter位于类路径上时,Spring会自动配置Jackson2。但是,您可以通过定义自己的MappingJackson2HttpMessageConverter类型的bean来覆盖此行为。首先,检查是否是用于序列化的bean(例如通过调试)。然后检查其配置。似乎ObjectMapper的Hibernate扩展的构造函数没有调用super(),这意味着缺少默认SerializerProviderBeanSerializerFactory的配置。有关详细信息,请参阅http://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/ObjectMapper.html