Spring MVC 3.2 和 JSON ObjectMapper 问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14333709/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:42:42  来源:igfitidea点击:

Spring MVC 3.2 and JSON ObjectMapper issue

jsonspringspring-mvc

提问by spal

I have recently upgraded my Spring version to 3.2.0 from 3.1.2. I find that that JSON properties like wrap root element, prevent null values that are defined in ObjectMapper are not working anymore.

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

Here is the code snippet

这是代码片段

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

and the JSON converter

和 JSON 转换器

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

Object mapper code

对象映射器代码

public class CustomHymansonObjectMapper extends ObjectMapper {

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

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

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

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

   }
}

Hymanson version

Hyman逊版

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

What could be the issue? Any pointers are appreciated.

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

回答by andyb

Disclaimer: I could not determine why the code in question is not working, but I could reproduce the problem. This answer does provide an alternate approach that works for me.

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

It couldbe a bug, as I can reproduce the problem with both with explicit config:

可能是一个错误,因为我可以使用显式配置重现该问题:

<bean id="HymansonObjectMapper" class="com.demo.CustomHymansonObjectMapper"/>

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

and via the mvc:message-converter:

并通过mvc:message-converter

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

where both give me {"foo":null,"bar":"bar"}when using the example class

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

Demo.java

演示.java

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.codehaus.Hymanson.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;
        }
    }
}

However, I would have thought the mvc:message-convertermethod would work, only because I have seen issues overriding the default bean registration that <mvc:annotation-driven/>performs (see Web MVC Framework) and using the nested configuration is preferred(?).

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

Maybe the Hymanson 2 supporthas caused some backwards compatibility issues with Hymanson 1?

也许Hymanson 2 支持导致了 Hymanson 1 的一些向后兼容性问题?

However, switching to the MappingHymanson2HttpMessageConverter(supported in Spring 3.1.2 and Spring 3.2), I amable to alter the ObjectMapper configuration to not write null values and wrap the JSON output... butonly when using the config inside the <mvc:message-converters/>!

然而,切换到MappingHymanson2HttpMessageConverter(在Spring 3.1.2和Spring 3.2的支持),我能够改变ObjectMapper配置不写入空值,敷JSON输出...使用内部的配置,只有当<mvc:message-converters/>

I get {"Dummy":{"bar":"bar"}}with the following changes:

我得到{"Dummy":{"bar":"bar"}}以下变化:

pom.xml

pom.xml

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

CustomHymansonObjectMapper.java

CustomHymansonObjectMapper.java

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

public class CustomHymansonObjectMapper extends ObjectMapper {

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

Demo.javaswitch to new package structure for Hymanson 2

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

import com.fasterxml.Hymanson.annotation.JsonProperty;

demo-servlet.xml

演示-servlet.xml

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

Lastly, according to the SerializationConfig.Featuredocumentation, WRITE_NULL_PROPERTIESfeature is deprecated < v2.0 and you should be using SerializationConfig.setSerializationInclusion()anyway. I assume this is why the @SuppressWarnings("deprecation")exists in your code. In Hymanson >= v2.0, it has been removed, hence the code change in the CustomHymansonObjectMapper.javaexample.

最后,根据SerializationConfig.Feature文档,WRITE_NULL_PROPERTIES功能已弃用 < v2.0,SerializationConfig.setSerializationInclusion()无论如何您都应该使用。我认为这就是@SuppressWarnings("deprecation")您的代码中存在的原因。在 Hymanson >= v2.0 中,它已被删除,因此CustomHymansonObjectMapper.java示例中的代码更改。

Configuring ObjectMapper in Springproposes an alternate solution.

在 Spring 中配置 ObjectMapper提出了一个替代解决方案。

Hope it helps!

希望能帮助到你!

回答by Maze

Even though this one is an old post, I phased a similar (maybe even the same?) problem. I tracked it down to the following issue (and this might help others):

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

  • An extra library that was added has a transient dependency on Hymanson 2.x
  • So far we had a dependency on Hymanson 1.x
  • Between Hymanson 1.x and Hymanson 2.x the namespace was changed to avoid conflicts
  • Sprint started to pick up the newer (2.x) version
  • The annotation was still to the old (1.x) version
  • 添加的额外库对 Hymanson 2.x 具有暂时性依赖
  • 到目前为止,我们依赖于 Hymanson 1.x
  • 在 Hymanson 1.x 和 Hymanson 2.x 之间更改了命名空间以避免冲突
  • Sprint 开始选择更新的 (2.x) 版本
  • 注释仍然是旧的 (1.x) 版本

To solve the issue I can either:

为了解决这个问题,我可以:

  1. remove the 2.x version again
  2. Upgrade the annotation to the 2.x version
  3. Add an extra annotation to also cover the 2.x version
  1. 再次删除 2.x 版本
  2. 升级注解到2.x版本
  3. 添加额外的注释以涵盖 2.x 版本

In my case I went for solution 3, since we require the two different versions and the additional annotation didn't add a big overhead.

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