【问题标题】:Spring MVC 3.2 and JSON ObjectMapper issueSpring MVC 3.2 和 JSON ObjectMapper 问题
【发布时间】:2013-01-15 08:28:35
【问题描述】:

我最近将我的 Spring 版本从 3.1.2 升级到了 3.2.0。我发现像包装根元素这样的 JSON 属性,防止在 ObjectMapper 中定义的空值不再起作用。

这里是代码sn-p

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" /> 
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="true" />
    <property name="ignoreAcceptHeader" value="false" /> 
    <property name="mediaTypes" >
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>

和 JSON 转换器

<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
   <property name="objectMapper" ref="customJacksonObjectMapper"/>  
   <property name="supportedMediaTypes" value="application/json"/>
</bean>

对象映射器代码

public class CustomJacksonObjectMapper extends ObjectMapper {

@SuppressWarnings("deprecation")
public CustomJacksonObjectMapper() {
    super();
    final AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();

    this.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
    this.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRAP_ROOT_VALUE, true);

    this.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);

    this.setDeserializationConfig(this.getDeserializationConfig().withAnnotationIntrospector(introspector));
    this.setSerializationConfig(this.getSerializationConfig().withAnnotationIntrospector(introspector));

   }
}

杰克逊版

<dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-xc</artifactId>
        <version>1.9.7</version>
    </dependency>

可能是什么问题?任何指针表示赞赏。

【问题讨论】:

  • 你确定使用CustomJacksonObjectMapper吗?

标签: json spring spring-mvc


【解决方案1】:

免责声明:我无法确定相关代码为何不起作用,但我可以重现该问题。这个答案确实提供了一种对我有用的替代方法。

可能是一个错误,因为我可以通过显式配置重现这两个问题:

<bean id="jacksonObjectMapper" class="com.demo.CustomJacksonObjectMapper"/>

<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
   <property name="objectMapper" ref="jacksonObjectMapper"/>
   <property name="supportedMediaTypes" value="application/json"/>
</bean>

并通过 mvc:message-converter:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="objectMapper" ref="jacksonObjectMapper" />
        </bean>
   </mvc:message-converters>
</mvc:annotation-driven>

使用示例类时两者都给我{"foo":null,"bar":"bar"}

Demo.java

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.codehaus.jackson.annotate.JsonProperty;

@Controller
@RequestMapping("/data")
public class Data {
    @RequestMapping
    @ResponseBody
    public Dummy dataIndex() {
        return new Dummy();
    }

    public class Dummy {
        String foo = null;
        @JsonProperty
        public String foo() {
            return foo;
        }
        String bar = "bar";
        @JsonProperty
        public String bar() {
            return bar;
        }
    }
}

但是,我认为 mvc:message-converter 方法会起作用,只是因为我看到了覆盖&lt;mvc:annotation-driven/&gt; 执行的默认 bean 注册的问题(请参阅Web MVC Framework)并使用嵌套配置是首选(?)。

也许Jackson 2 support 引起了 Jackson 1 的一些向后兼容性问题?

但是,切换到MappingJackson2HttpMessageConverter(在 Spring 3.1.2 和 Spring 3.2 中受支持),我能够更改 ObjectMapper 配置以不写入空值并包装 JSON 输出。 . 仅在使用&lt;mvc:message-converters/&gt;中的配置时!

我收到了 {"Dummy":{"bar":"bar"}} 并进行了以下更改:

pom.xml

<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <version>2.1.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.1.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.1.0</version>
</dependency>

CustomJacksonObjectMapper.java

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import static com.fasterxml.jackson.annotation.JsonInclude.*;

public class CustomJacksonObjectMapper extends ObjectMapper {

public CustomJacksonObjectMapper() {
    super();
    this.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
    this.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
    this.setSerializationInclusion(Include.NON_NULL);
   }
}

Demo.java 切换到 Jackson 2 的新包结构

import com.fasterxml.jackson.annotation.JsonProperty;

demo-servlet.xml

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="jacksonObjectMapper" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

最后,根据SerializationConfig.Feature 文档,WRITE_NULL_PROPERTIES 功能已弃用SerializationConfig.setSerializationInclusion()。我认为这就是您的代码中存在@SuppressWarnings("deprecation") 的原因。在 Jackson >= v2.0 中,它已被删除,因此 CustomJacksonObjectMapper.java 示例中的代码发生了变化。

Configuring ObjectMapper in Spring 提出了另一种解决方案。

希望对你有帮助!

【讨论】:

  • 非常感谢您花时间在短时间内发布回复。这对我有用。还要特别感谢 stackoverflow.com 提供了这个很棒的平台来分享这些东西,现在是时候让我尽我所能做出贡献了......
  • 很乐意提供帮助 :-) 如果有人能确定 Jackson 1 的故障原因,我很想知道原因!如果我有时间,我会尝试更多地调试 Spring。
  • @andyb 我已经尝试过这个解决方案,但是当我尝试启动 Tomcat 时出现“java.lang.ClassNotFoundException: com.demo.CustomJacksonObjectMapper”异常。你有什么主意吗?非常感谢!
  • 听起来CustomJacksonObjectMapper.java 示例类不在com.demo 包中。我没有这个 src 了,但是如果你仍然有问题,我可以尝试重新创建它。
【解决方案2】:

尽管这是一篇旧帖子,但我分阶段解决了一个类似(甚至可能相同?)的问题。我将其归结为以下问题(这可能对其他人有所帮助):

  • 添加的额外库暂时依赖于 Jackson 2.x
  • 到目前为止,我们依赖于 Jackson 1.x
  • 在 Jackson 1.x 和 Jackson 2.x 之间更改了命名空间以避免冲突
  • Sprint 开始采用较新的 (2.x) 版本
  • 注释仍为旧 (1.x) 版本

要解决这个问题,我可以:

  1. 再次删除 2.x 版本
  2. 将注解升级到 2.x 版本
  3. 添加一个额外的注释以覆盖 2.x 版本

就我而言,我选择了解决方案 3,因为我们需要两个不同的版本,而且额外的注释并没有增加很大的开销。

【讨论】:

    猜你喜欢
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 2014-12-30
    • 2021-04-25
    • 1970-01-01
    相关资源
    最近更新 更多