web-dev-qa-db-fra.com

Problème Spring MVC 3.2 et JSON ObjectMapper

J'ai récemment mis à niveau ma version de Spring à la version 3.2.0 à partir de la version 3.1.2. Je trouve que les propriétés JSON telles que l'élément racine wrap, empêchent les valeurs NULL définies dans ObjectMapper ne fonctionnent plus. 

Voici l'extrait de code 

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

et le convertisseur JSON

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

Code du mappeur d'objets

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

   }
}

Version de Jackson

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

Quel pourrait être le problème? Tous les indicateurs sont appréciés.

11
spal

_ {Avertissement: je ne peux pas déterminer pourquoi le code en question ne fonctionne pas, mais je peux reproduire le problème. Cette réponse fournit une approche alternative qui fonctionne pour moi.} _

Cela pourrait être un bogue, car je peux reproduire le problème avec les deux avec une configuration explicite:

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

et via le mvc: convertisseur de messages:

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

où les deux me donnent {"foo":null,"bar":"bar"} lors de l'utilisation de la classe d'exemple

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

Cependant, j’aurais pensé que la méthode mvc: message-converter fonctionnerait, uniquement parce que j’ai rencontré des problèmes annulant l’enregistrement du bean par défaut exécuté par <mvc:annotation-driven/> (voir Web MVC Framework ) et utilisant la méthode imbriquée. la configuration est préférée (?).

Peut-être que le support Jackson 2 a causé des problèmes de compatibilité avec les versions antérieures de Jackson 1?

Cependant, le passage à MappingJackson2HttpMessageConverter (pris en charge dans Spring 3.1.2 et Spring 3.2), permet à I am de modifier la configuration de ObjectMapper afin de ne pas écrire les valeurs nulles et d'envelopper la sortie JSON ... mais uniquement lors de l'utilisation de la configuration dans le <mvc:message-converters/>!

Je reçois {"Dummy":{"bar":"bar"}} avec les modifications suivantes:

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 bascule vers la nouvelle structure de paquet pour 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>

Enfin, selon le SerializationConfig.Feature documentation, la fonctionnalité WRITE_NULL_PROPERTIES est obsolète <v2.0 et vous devriez quand même utiliser SerializationConfig.setSerializationInclusion(). Je suppose que c'est pourquoi la @SuppressWarnings("deprecation") existe dans votre code. Dans Jackson> = v2.0, il a été supprimé, d'où le changement de code dans CustomJacksonObjectMapper.Java example.

Configuration d'ObjectMapper dans Spring propose une solution alternative.

J'espère que ça aide!

14
andyb

Même si celui-ci est un ancien post, j'ai mis en phase un problème similaire (peut-être même le même?). Je l'ai retrouvé dans le problème suivant (et cela pourrait aider les autres):

  • Une bibliothèque supplémentaire ajoutée a une dépendance transitoire sur Jackson 2.x
  • Jusqu'à présent, nous dépendions de Jackson 1.x
  • Entre Jackson 1.x et Jackson 2.x, l'espace de noms a été modifié pour éviter les conflits.
  • Sprint a commencé à prendre la version la plus récente (2.x)
  • L'annotation était toujours à l'ancienne version (1.x)

Pour résoudre le problème, je peux soit:

  1. supprimer à nouveau la version 2.x
  2. Mettre à niveau l'annotation vers la version 2.x
  3. Ajouter une annotation supplémentaire pour couvrir également la version 2.x

Dans mon cas, j’ai opté pour la solution 3, car nous avons besoin de deux versions différentes et que l’annotation supplémentaire n’ajoute pas beaucoup de travail.

0
Maze