Spring Проблема MVC 3.2 и JSON ObjectMapper

Недавно я обновил версию Spring до версии 3.2.0 с версии 3.1.2. Я нахожу, что такие свойства JSON, как элемент корневого корня, предотвращают ненужные значения, определенные в ObjectMapper, больше не работают.

Вот фрагмент кода

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

В чем может быть проблема? Любые указатели оцениваются.

Ответ 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 будет работать, только потому, что я видел проблемы, переопределяющие регистрацию по умолчанию bean, которую выполняет <mvc:annotation-driven/> (см. Web MVC Framework), и использование вложенной конфигурации предпочтительнее (?).

Возможно, поддержка Jackson 2 вызвала некоторые проблемы с обратной совместимостью с Jackson 1?

Однако, перейдя на MappingJackson2HttpMessageConverter (поддерживается в Spring 3.1.2 и Spring 3.2), я могу изменить конфигурацию ObjectMapper, чтобы не записывать нулевые значения и завершать вывод JSON... , но только при использовании конфигурации внутри <mvc:message-converters/>!

Я получаю {"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;

демо-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 устарела < v2.0, и вы все равно должны использовать SerializationConfig.setSerializationInclusion(). Я предполагаю, что поэтому @SuppressWarnings("deprecation") существует в вашем коде. В Jackson >= v2.0 он был удален, поэтому изменение кода в CustomJacksonObjectMapper.java.

Настройка ObjectMapper в Spring предлагает альтернативное решение.

Надеюсь, что это поможет!

Ответ 2

Даже если это старый пост, я поэтапно схожу (возможно, даже такую ​​же?) проблему. Я отследил его до следующей проблемы (и это могло бы помочь другим):

  • Дополнительная библиотека, которая была добавлена, имеет временную зависимость от Jackson 2.x
  • До сих пор у нас была зависимость от Jackson 1.x
  • Между Jackson 1.x и Jackson 2.x пространство имен было изменено, чтобы избежать конфликтов.
  • Sprint начал собирать новую версию (2.x)
  • Аннотации оставались в старой версии (1.x)

Чтобы решить проблему, я могу либо:

  • снова удалите версию 2.x
  • Обновите аннотацию до версии 2.x
  • Добавьте дополнительную аннотацию, чтобы также включить версию 2.x

В моем случае я пошел на решение 3, так как мы требуем две разные версии, а дополнительная аннотация не добавила больших накладных расходов.