java - jsoninclude - Servicio REST de Spring: cómo configurar para eliminar objetos nulos en la respuesta json
java jackson ignore if null (9)
A partir de Jackson 2.0, @JsonSerialize(include = xxx)
ha quedado en desuso en favor de @JsonInclude
Tengo un servicio web de primavera que devuelve una respuesta json. Estoy usando el ejemplo dado aquí para crear el servicio: http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/
El formato en el que se devuelve el json es: {"nombre": nulo, "staffName": ["kfc-kampar", "smith"]}
Quiero eliminar cualquier objeto nulo de la respuesta devuelta para que se vea así: {"staffName": ["kfc-kampar", "smith"]}
He encontrado preguntas similares aquí pero he podido lograr que una solución funcione, por ejemplo,
Configurando ObjectMapper en Spring
la configuración del jacksonObjectMapper no funciona en spring mvc 3
¿Cómo configurar spring mvc 3 para no devolver el objeto "nulo" en la respuesta json?
Spring configura el formato @ResponseBody JSON
Jackson + Spring3.0.5 asignador de objetos personalizados
Al leer estas y otras fuentes, imaginé que la forma más limpia de lograr lo que quería era usar Spring 3.1 y los convertidores de mensajes que se pueden configurar dentro de la anotación mvc. Mi archivo de configuración de primavera actualizado es:
<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 clase de servicio es la misma que se da en el sitio mkyong.com, excepto que comenté la configuración de la variable Nombre de la tienda, por lo que es nula, es decir
@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;
}
}
Los tarros Jackson que estoy usando son jackson-mapper-asl 1.9.0 y jackson-core-asl 1.9.0. Estos son los únicos frascos nuevos que he agregado al pom, como parte del proyecto spring-json que descargué de mkyong.com.
El proyecto se compila con éxito, pero cuando invoco el servicio a través del navegador todavía obtengo lo mismo, es decir, {"nombre": nulo, "nombre del personal": ["kfc-kampar", "smith"]}
¿Alguien me puede decir dónde me equivoco con mi configuración?
He intentado varias otras opciones, pero la única forma en que he podido devolver el json en el formato correcto es agregar el Asignador de objetos al JSONController y hacer que el método "getShopInJSON" devuelva una cadena, es decir
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;
}
Ahora, si invoco el servicio, obtengo el esperado, es decir, {"staffName": ["kfc-kampar", "cronin"]}
También he podido hacer que funcione con la anotación @JsonIgnore, pero esta solución no es adecuada para mí.
No entiendo por qué funciona en código pero no en la configuración, por lo que cualquier ayuda sería fantástica.
Dado que se está utilizando Jackson, debe configurarlo como una propiedad de Jackson. En el caso de los servicios REST de Spring Boot, debe configurarlo en application.properties
:
spring.jackson.default-property-inclusion = NON_NULL
Desde Jackson 2.0 puedes usar JsonInclude
@JsonInclude(Include.NON_NULL)
public class Shop {
//...
}
Desde la versión 1.6 tenemos una nueva anotación JsonSerialize (en la versión 1.9.9 por ejemplo).
Ejemplo:
@JsonSerialize(include=Inclusion.NON_NULL)
public class Test{
...
}
El valor predeterminado es SIEMPRE.
En versiones anteriores puede usar JsonWriteNullProperties, que está en desuso en nuevas versiones. Ejemplo:
@JsonWriteNullProperties(false)
public class Test{
...
}
He encontrado una solución a través de la configuración del contenedor Spring, pero aún no es exactamente lo que quería.
Regresé a Spring 3.0.5, eliminé y en su lugar cambié mi archivo de configuración a:
<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>
Por supuesto, esto es similar a las respuestas dadas en otras preguntas, por ejemplo,
la configuración del jacksonObjectMapper no funciona en spring mvc 3
Lo importante a tener en cuenta es que mvc: annotation-driven y AnnotationMethodHandlerAdapter no se pueden usar en el mismo contexto.
Todavía no puedo hacer que funcione con Spring 3.1 y mvc: aunque con anotación. Una solución que utiliza mvc: anotación impulsada y todos los beneficios que la acompañan serían mucho mejores, creo. Si alguien pudiera mostrarme cómo hacer esto, sería genial.
Para todas las personas que no son de configuración XML:
ObjectMapper objMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
HttpMessageConverter msgConverter = new MappingJackson2HttpMessageConverter(objMapper);
restTemplate.setMessageConverters(Collections.singletonList(msgConverter));
Puede usar JsonWriteNullProperties
para versiones anteriores de Jackson.
Para Jackson 1.9+, use JsonSerialize.include
.
Si está utilizando Jackson 2, la etiqueta de convertidores de mensajes es:
<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>
@JsonSerialize(include=JsonSerialize.Inclusion.NON_EMPTY)
public class Shop {
//...
}
para jackson 2.0 o posterior use @JsonInclude(Include.NON_NULL)
Esto eliminará objetos vacíos y nulos.