web-dev-qa-db-fra.com

Spring REST Service: comment configurer pour supprimer les objets null dans la réponse json

J'ai un service Web printanier qui renvoie une réponse json. J'utilise l'exemple donné ici pour créer le service: http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/

Le format dans lequel le fichier json est retourné est le suivant: {"name": null, "staffName": ["kfc-kampar", "smith"]}

Je veux supprimer tous les objets nuls de la réponse renvoyée afin que cela ressemble à ceci: {"staffName": ["kfc-kampar", "smith"]}

J'ai trouvé des questions similaires posées ici, mais j'ai pu trouver une solution efficace, par exemple.

Configuration d'ObjectMapper en Spring

Comment configurer MappingJacksonHttpMessageConverter en utilisant une configuration à annotation par ressort?

configuration du jacksonObjectMapper ne fonctionnant pas au printemps mvc

comment configurer spring mvc 3 pour ne pas renvoyer d'objet "null" dans la réponse json?

format JSON du printemps @ResponseBody de la configuration du printemps

mappeur d'objet personnalisé Jackson + Spring3.0.5

En lisant ces sources et d’autres, j’ai trouvé que le moyen le plus propre d’atteindre ce que je voulais était d’utiliser Spring 3.1 et les convertisseurs de messages pouvant être configurés dans mvc-annotation. Mon fichier de configuration printanier mis à jour est:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans     
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

<context:component-scan base-package="com.mkyong.common.controller" />

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="prefixJson" value="true" />
            <property name="supportedMediaTypes" value="application/json" />
            <property name="objectMapper">
                <bean class="org.codehaus.jackson.map.ObjectMapper">
                    <property name="serializationInclusion" value="NON_NULL"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

La classe de service est la même que celle indiquée sur le site mkyong.com, sauf que j'ai commenté le paramètre de la variable Nom de la boutique de sorte qu'il soit null i.e.

@Controller
@RequestMapping("/kfc/brands")
public class JSONController {
    @RequestMapping(value="{name}", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK) 
    public @ResponseBody Shop getShopInJSON(@PathVariable String name) {
        Shop shop = new Shop();
        //shop.setName(name);
        shop.setStaffName(new String[]{name, "cronin"});
        return shop;
    }
}

Les bocaux Jackson que j'utilise sont jackson-mapper-asl 1.9.0 et jackson-core-asl 1.9.0. Ce sont les seuls nouveaux bocaux que j'ai ajoutés au pom, fournis dans le cadre du projet spring-json que j'ai téléchargé sur mkyong.com.

Le projet est construit avec succès, mais quand j'appelle le service via le navigateur, j'obtiens toujours la même chose, à savoir {"name": null, "staffName": ["kfc-kampar", "smith"]}}

Quelqu'un peut-il me dire où je me trompe avec ma configuration?

J'ai essayé plusieurs autres options, mais la seule façon de retourner JSON au format correct est d'ajouter le mappeur d'objets au JSONController et de faire en sorte que la méthode "getShopInJSON" renvoie une chaîne i.e.

public @ResponseBody String getShopInJSON(@PathVariable String name) throws JsonGenerationException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);

    Shop shop = new Shop();
    //shop.setName(name);
    shop.setStaffName(new String[]{name, "cronin"});
    String test = mapper.writeValueAsString(shop);
    return test;
}

Maintenant, si j'appelle le service, je reçois le résultat escompté, à savoir {"staffName": ["kfc-kampar", "cronin"]}

J'ai également pu le faire fonctionner en utilisant l'annotation @JsonIgnore, mais cette solution ne me convient pas.

Je ne comprends pas pourquoi cela fonctionne dans le code mais pas dans la configuration, donc toute aide serait fantastique.

53
mikec

Depuis Jackson 2.0, vous pouvez utiliser JsonInclude

@JsonInclude(Include.NON_NULL)
public class Shop {
    //...
}
75
Walery Strauch

Puisque Jackson est utilisé, vous devez configurer cela comme une propriété de Jackson. Dans le cas de Spring Boot REST services, vous devez le configurer dans application.properties ou application.yml:

spring.jackson.default-property-inclusion = NON_NULL

source

59
Luís Soares
@JsonSerialize(include=JsonSerialize.Inclusion.NON_EMPTY)
public class Shop {
    //...
}

pour Jackson 2.0 ou version ultérieure, utilisez @JsonInclude(Include.NON_NULL)

Cela supprimera les objets vides et nuls.

8
Jekin Kalariya

Si vous utilisez Jackson 2, la balise message-converters est:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="prefixJson" value="true"/>
            <property name="supportedMediaTypes" value="application/json"/>
            <property name="objectMapper">
                <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                    <property name="serializationInclusion" value="NON_NULL"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>
5
Eduardo

À partir de Jackson 2.0, @JsonSerialize(include = xxx) est déconseillé au profit de @JsonInclude

5
A B

Depuis la version 1.6, nous avons la nouvelle annotation JsonSerialize (dans la version 1.9.9 par exemple).

Exemple:

@JsonSerialize(include=Inclusion.NON_NULL)
public class Test{
...
}

La valeur par défaut est TOUJOURS.

Dans les anciennes versions, vous pouvez utiliser JsonWriteNullProperties, qui est obsolète dans les nouvelles versions. Exemple:

@JsonWriteNullProperties(false)
public class Test{
    ...
}
4
grep

Pour tous les membres de votre configuration non-xml:

ObjectMapper objMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
HttpMessageConverter msgConverter = new MappingJackson2HttpMessageConverter(objMapper);
restTemplate.setMessageConverters(Collections.singletonList(msgConverter));
3
cosbor11

Vous pouvez utiliser JsonWriteNullProperties pour les anciennes versions de Jackson.

Pour Jackson 1.9+, utilisez JsonSerialize.include .

1
user647772

J'ai trouvé une solution en configurant le conteneur Spring, mais ce n'est toujours pas exactement ce que je voulais.

Je suis revenu à Spring 3.0.5, supprimé et à sa place, j'ai changé mon fichier de configuration en:

    <bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </list>
    </property>
</bean>


<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
    factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />
<bean
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jacksonSerializationConfig" />
    <property name="targetMethod" value="setSerializationInclusion" />
    <property name="arguments">
        <list>
            <value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_NULL</value>
        </list>
    </property>
</bean>

Ceci est bien sûr similaire aux réponses données dans d’autres questions, par exemple.

configuration du jacksonObjectMapper ne fonctionnant pas au printemps mvc

Il est important de noter que mvc: annotation-driven et AnnotationMethodHandlerAdapter ne peuvent pas être utilisés dans le même contexte.

Je n'arrive toujours pas à le faire fonctionner avec Spring 3.1 et mvc: piloté par les annotations. Une solution qui utilise mvc: axée sur les annotations et tous les avantages qui l'accompagnent serait bien meilleure, je pense. Si quelqu'un pouvait me montrer comment faire cela, ce serait formidable.

1
mikec

Réglage du spring.jackson.default-property-inclusion=non_null est la solution la plus simple et elle fonctionne bien.

Cependant, soyez prudent si vous implémentez WebMvcConfigurer quelque part dans votre code, la solution de propriété ne fonctionnera pas et vous devrez configurer la sérialisation NON_NULL dans le code comme suit:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    // some of your config here...

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
        converters.add(jsonConverter);
    }
}
0
Zantsu