java - jsonvalue - spring boot jackson2objectmapperbuilder
¿Cómo personalizar el mapeador Jackson JSON utilizado implícitamente por Spring Boot? (10)
Conozco la pregunta que pide el arranque de Spring, pero creo que muchas personas buscan cómo hacer esto en un arranque que no es Spring, como yo buscando casi todo el día.
Por encima del Spring 4, no es necesario configurar
MappingJacksonHttpMessageConverter
si solo tiene la intención de configurar
ObjectMapper
.
Solo necesitas hacer:
public class MyObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 4219938065516862637L;
public MyObjectMapper() {
super();
enable(SerializationFeature.INDENT_OUTPUT);
}
}
Y en su configuración de Spring, cree este bean:
@Bean
public MyObjectMapper myObjectMapper() {
return new MyObjectMapper();
}
Estoy usando Spring Boot (1.2.1), de manera similar a su tutorial de Creación de un servicio web RESTful :
@RestController
public class EventController {
@RequestMapping("/events/all")
EventList events() {
return proxyService.getAllEvents();
}
}
Entonces, Spring MVC utiliza implícitamente Jackson para serializar mi objeto
EventList
en JSON.
Pero quiero hacer algunas personalizaciones simples para el formato JSON, como:
setSerializationInclusion(JsonInclude.Include.NON_NULL)
La pregunta es, ¿cuál es la forma más sencilla de personalizar el mapeador JSON implícito?
Probé el enfoque en esta publicación de blog , creando un CustomObjectMapper, etc., pero el paso 3, "Registrar clases en el contexto de Spring", falla:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name ''jacksonFix'': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire method: public void com.acme.project.JacksonFix.setAnnotationMethodHandlerAdapter(org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter);
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]
found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Parece que esas instrucciones son para versiones anteriores de Spring MVC, mientras que estoy buscando una manera simple de hacer que esto funcione con Spring Boot más reciente.
Cuando traté de hacer ObjectMapper primario en spring boot 2.0.6 obtuve errores, así que modifiqué el que Spring Boot me creó
Consulte también https://.com/a/48519868/255139
@Lazy
@Autowired
ObjectMapper mapper;
@PostConstruct
public ObjectMapper configureMapper() {
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
SimpleModule module = new SimpleModule();
module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
module.addSerializer(LocalDate.class, new LocalDateSerializer());
mapper.registerModule(module);
return mapper;
}
Encontré la solución descrita anteriormente con:
spring.jackson.serialization-inclusive = non_null
Para trabajar solo a partir de la versión 1.4.0.RELEASE de spring boot. En todos los demás casos, la configuración se ignora.
Verifiqué esto experimentando con una modificación de la muestra de arranque de primavera "spring-boot-sample-jersey"
Estoy respondiendo un poco tarde a esta pregunta, pero alguien, en el futuro, podría encontrar esto útil. El siguiente enfoque, además de muchos otros enfoques, funciona mejor, y personalmente creo que sería mejor para una aplicación web.
@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
Me topé con otra solución, que es bastante agradable.
Básicamente, solo realice el
paso 2 del blog publicado mencionado
y defina un ObjectMapper personalizado como Spring
@Component
.
(Las cosas comenzaron a funcionar cuando
eliminé
todo el material AnnotationMethodHandlerAdapter del paso 3.)
@Component
@Primary
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
setSerializationInclusion(JsonInclude.Include.NON_NULL);
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
Funciona mientras el componente esté en un paquete escaneado por Spring.
(Usar
@Primary
no es obligatorio en mi caso, pero ¿por qué no hacer las cosas explícitas?)
Para mí hay dos beneficios en comparación con el otro enfoque:
-
Esto es mas simple;
Solo puedo extender una clase de Jackson y no necesito saber cosas muy específicas de Spring como
Jackson2ObjectMapperBuilder
. -
Quiero usar las mismas configuraciones de Jackson para deserializar JSON en otra parte de mi aplicación, y de esta manera es muy simple:
new CustomObjectMapper()
lugar denew ObjectMapper()
.
Puede agregar un siguiente método dentro de su clase bootstrap que se anota con
@SpringBootApplication
@Bean
@Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
objectMapper.registerModule(new JodaModule());
return objectMapper;
}
Se pueden configurar muchas cosas en las propiedades de la aplicación. Desafortunadamente, esta característica solo se encuentra en la Versión 1.3, pero puede agregar una Clase de configuración
@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
... other configurations
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
builder.serializationInclusion(Include.NON_EMPTY);
builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
}
[ACTUALIZACIÓN: debe trabajar en ObjectMapper porque se llama al método
build()
antes de ejecutar la configuración.]
Si está utilizando Spring Boot 1.3, puede configurar la inclusión de serialización a través de
application.properties
:
spring.jackson.serialization-inclusion=non_null
Después de los cambios en Jackson 2.7, Spring Boot 1.4 usa una propiedad llamada
spring.jackson.default-property-inclusion
en
spring.jackson.default-property-inclusion
lugar:
spring.jackson.default-property-inclusion=non_null
Consulte la sección " Personalizar el Jackson ObjectMapper " en la documentación de Spring Boot.
Si está utilizando una versión anterior de Spring Boot, la forma más fácil de configurar la inclusión de serialización en Spring Boot es declarar su propio bean
Jackson2ObjectMapperBuilder
configurado
Jackson2ObjectMapperBuilder
.
Por ejemplo:
@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
return builder;
}
La documentación establece varias formas de hacer esto.
Si desea reemplazar completamente el
ObjectMapper
predeterminado, defina un@Bean
de ese tipo y@Primary
como@Primary
.La definición de un
@Bean
de tipoJackson2ObjectMapperBuilder
le permitirá personalizar tantoObjectMapper
comoXmlMapper
(utilizados enMappingJackson2HttpMessageConverter
yMappingJackson2XmlHttpMessageConverter
respectivamente).
spring.jackson.serialization-inclusion=non_null
solía trabajar para nosotros
Pero cuando actualizamos la versión de arranque de primavera a 1.4.2.RELEASE o superior, dejó de funcionar.
Ahora, otra propiedad
spring.jackson.default-property-inclusion=non_null
está haciendo la magia.
de hecho, la
serialization-inclusion
está en desuso.
Esto es lo que me arroja mi inteligencia.
En desuso: ObjectMapper.setSerializationInclusion fue en desuso en Jackson 2.7
Entonces, comience a usar
spring.jackson.default-property-inclusion=non_null
en
spring.jackson.default-property-inclusion=non_null
lugar