【问题标题】:Spring MVC configuration + Jackson + Guava multimapSpring MVC 配置 + Jackson + Guava 多图
【发布时间】:2014-11-17 18:12:39
【问题描述】:

我正在为此苦苦挣扎:

我们有一个带有 Guava 多图的 Table 类(简化的代码,基本上是 1 个成员,2 个构造函数,多图的 getter 和 setter):

public class Table {

    private LinkedHashMultimap<String,Field> fields;

    public Table(){
        this.fields = LinkedHashMultimap.create();
    };

    public Table (LinkedHashMultimap<String, Field> fields){
        this.fields= fields;
    }

    public LinkedHashMultimap<String, Field> getFields() {
        return fields;
    }

    public void setFields(LinkedHashMultimap<String, Field> fields) {
        this.fields = fields;
    }
}

我想使用 Spring MVC 3.2.11 使用 jackson 2.4.3 序列化它。

POM 相关依赖有:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.4.3</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.4.3</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-guava</artifactId>
  <version>2.4.3</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>3.2.11.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>3.2.11.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
</dependency>

我的 spring.xml NOW 看起来像这样(在此example 之后)

<bean id="abstractJacksonObjectMapper"
      class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
      p:targetMethod="registerModule">
    <property name="targetObject">
        <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
              p:indentOutput="true">
            <!--<property name="featuresToDisable">-->
                <!--<util:constant static-field="com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES" />-->
            <!--</property>-->
        </bean>
    </property>
    <property name="arguments">
        <list>
            <bean class="com.fasterxml.jackson.datatype.guava.GuavaModule" />
        </list>
    </property>
</bean>

<bean id="abstractMappingJacksonHttpMessageConverter"
      class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"
      abstract="true"/>

<bean id="abstractMappingJacksonJsonView"
      class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"
      abstract="true"
      p:extractValueFromSingleKeyModel="true"/>

<bean id="jacksonObjectMapper" parent="abstractJacksonObjectMapper" />

<bean id="mappingJacksonHttpMessageConverter"
      parent="abstractMappingJacksonHttpMessageConverter"
      p:objectMapper-ref="jacksonObjectMapper"
      p:supportedMediaTypes="application/json" />

<bean id="mappingJacksonJsonView"
      parent="abstractMappingJacksonJsonView"
      p:objectMapper-ref="jacksonObjectMapper"
      p:contentType="application/json" />

也尝试过这种其他方法,使用扩展的 Jackson2ObjectMapperFactoryBean:

<!-- Json rendering configuration-->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="order" value="1" />
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
                <property name="objectMapper">
                    <bean class="my.package.Jackson2ObjectMapperFactoryBean"/>
                </property>
            </bean>
        </list>
    </property>
    <property name="ignoreAcceptHeader" value="true" />
</bean>

然后 FactoryBean 看起来像这样:

package my.package;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;

public class Jackson2ObjectMapperFactoryBean extends org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean{

public ObjectMapper getObject(){

    ObjectMapper objectMapper =super.getObject();
    objectMapper.registerModule(new GuavaModule());

    return objectMapper;
}

}

我有一个工作正常的测试类,根本没有使用 Spring(只是测试 Table.class + Jackson + guava)简化:

Table study = getTable();

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new GuavaModule());

String tableString = mapper.writeValueAsString(table);

它正确地序列化它:

{
  "fields":{
    "Field1":[
      {
        "index":0,
        "header":"Field1",
        "fieldType":"fieldtype",
        "description":null,
        "cleanHeader":null
      }
    ],
    "Field2":[
      {
        "index":1,
        "header":"Field2",
        "fieldType":"fieldtype",
        "description":null,
        "cleanHeader":null
      }
    ]
  }
}

使用 spring(两种方法中的任何一种)我得到:

{
  "fields":{
    "empty": false
  }
}

我的控制器有一个@ResponseBody 注释并且它返回一个表。

已编辑:我正在深入调试 spring 类(第一次,;-))和 org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor 正在处理请求。这是否与我的问题有关...我的 spring xml 是否与 @ResponseBody 注释相矛盾?

任何想法我做错了什么?

注意:我需要 Multimap,不能是标准的 Java 集合。

【问题讨论】:

    标签: java spring-mvc multimap jackson-modules guava


    【解决方案1】:

    不知道下面的解决方案是否完全适合您的问题,但如果您想将 SpringBootApplication 配置为也序列化番石榴,您可以使用 @Bean 增强您的 @Configuration 类,如下所示:

    @Configuration
    public class Application extends SpringBootServletInitializer {
    
        @Bean
        ObjectMapper customizeJacksonConfiguration() {
            ObjectMapper om = new ObjectMapper();
            om.registerModule(new GuavaModule());
            return om;
        }
    }
    

    【讨论】:

    • 谢谢!不使用 SpringBootApplication,但可能对使用它的人有用。
    • 如果您在 pom 文件中导入了多个 Jackson 模块,这将全部加载:ObjectMapper mapper = new ObjectMapper(); mapper.findAndRegisterModules();
    【解决方案2】:

    我认为您需要在 spring.xml 中添加一个 mvc:messsage-converters 部分。比如

     <mvc:annotation-driven ignoreDefaultModelOnRedirect="true" >
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

    【讨论】:

    • 谢谢卡特琳娜!我已经添加了您的代码并尝试了上述两种方法....我得到了相同的 "fields":{"empty": false} 结果。
    【解决方案3】:

    毕竟我发现@ResponseBody 注释强制使用不同的“viewResolver”,即使用 Jackson,但没有 Guava 模块。

    所以,为了解决这个问题,我删除了 Controller 方法中的 @ResponseBody 注释:

    <!-- language: java -->
    @ResponseBody
    @RequestMapping("table")
    public Table getTable() {
    

    不幸的是,这返回:{Table:{...}} 并且是由 ValueHandlder (ModelAttributeMethodProcessor) 引入的人工制品。

    最后,现在的工作是:

    1.- 恢复@ResponseBody 2.- 在 @ResponseBody 处理程序默认提供的 MappingJackson2HttpMessageConverter 中注册 Guava 模块。

    这是 spring xml 的样子:非常干净和简单:

    <!-- JSON parser configuration-->
    <bean id="guavaObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/>
    
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject"><ref local="guavaObjectMapper" /></property>
        <property name="targetMethod"><value>registerModule</value></property>
        <property name="arguments">
            <list>
                <bean id="guavaModule" class="com.fasterxml.jackson.datatype.guava.GuavaModule"/>
            </list>
        </property>
    </bean>
    
    
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <ref  local="guavaObjectMapper"/>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-17
      • 2015-04-02
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      • 2013-07-18
      相关资源
      最近更新 更多