mi objetivo es configurar el objectMapper
de manera que solo serialice los elementos que están anotados @JsonProperty
.
Para hacerlo, seguí esta explicación que dice cómo configurar el objectmapper.
Incluí el mapeador de objetos personalizado como se describe aquí .
Sin embargo, cuando la clase NumbersOfNewEvents
se serializa, todavía contiene todos los atributos en json.
¿Alguien tiene una pista? Gracias por adelantado
Jackson 1.8.0 resorte 3.0.5
CustomObjectMapper
public class CompanyObjectMapper extends ObjectMapper {
public CompanyObjectMapper() {
super();
setVisibilityChecker(getSerializationConfig()
.getDefaultVisibilityChecker()
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
.withFieldVisibility(JsonAutoDetect.Visibility.NONE)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.DEFAULT));
}
}
servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="de.Company.backend.web" />
<mvc:annotation-driven />
<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="de.Company.backend.web.CompanyObjectMapper" />
</beans>
NumbersOfNewEvents
public class NumbersOfNewEvents implements StatusAttribute {
public Integer newAccepts;
public Integer openRequests;
public NumbersOfNewEvents() {
super();
}
}
JacksonConfiguration
? ¿Es una forma automática de indicar a Spring Boot que use esta clase como clase de configuración para Jackson?@EnableWebMvc
? Dudo porque ... vea en mi respuesta : ¿Por qué el uso de @EnableWebMvc es un problema?Puede ser porque estoy usando Spring 3.1 (en lugar de Spring 3.0.5 como especificó su pregunta), pero la respuesta de Steve Eastwood no funcionó para mí. Esta solución funciona para Spring 3.1:
En su contexto xml de primavera:
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"/> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> <property name="objectMapper" ref="jacksonObjectMapper" /> </bean> </mvc:message-converters> </mvc:annotation-driven> <bean id="jacksonObjectMapper" class="de.Company.backend.web.CompanyObjectMapper" />
fuente
Hay
org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean
por mucho tiempo. A partir de la versión 1.2 de Spring Boot, existeorg.springframework.http.converter.json.Jackson2ObjectMapperBuilder
Java Config.En String Boot la configuración puede ser tan simple como:
spring.jackson.deserialization.<feature_name>=true|false spring.jackson.generator.<feature_name>=true|false spring.jackson.mapper.<feature_name>=true|false spring.jackson.parser.<feature_name>=true|false spring.jackson.serialization.<feature_name>=true|false spring.jackson.default-property-inclusion=always|non_null|non_absent|non_default|non_empty
en
classpath:application.properties
o algún código Java en@Configuration
clase:@Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd")); return builder; }
Ver:
fuente
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json()
.He usado esto con Jackson 2.xy Spring 3.1.2+
servlet-context.xml:
Tenga en cuenta que el elemento raíz es
<beans:beans>
, por lo que es posible que deba eliminarbeans
y agregarmvc
algunos de estos elementos según su configuración.<annotation-driven> <message-converters> <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter" /> <beans:bean class="org.springframework.http.converter.ResourceHttpMessageConverter" /> <beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <beans:property name="objectMapper" ref="jacksonObjectMapper" /> </beans:bean> </message-converters> </annotation-driven> <beans:bean id="jacksonObjectMapper" class="au.edu.unimelb.atcom.transfer.json.mappers.JSONMapper" />
au.edu.unimelb.atcom.transfer.json.mappers.JSONMapper.java:
public class JSONMapper extends ObjectMapper { public JSONMapper() { SimpleModule module = new SimpleModule("JSONModule", new Version(2, 0, 0, null, null, null)); module.addSerializer(Date.class, new DateSerializer()); module.addDeserializer(Date.class, new DateDeserializer()); // Add more here ... registerModule(module); } }
DateSerializer.java:
public class DateSerializer extends StdSerializer<Date> { public DateSerializer() { super(Date.class); } @Override public void serialize(Date date, JsonGenerator json, SerializerProvider provider) throws IOException, JsonGenerationException { // The client side will handle presentation, we just want it accurate DateFormat df = StdDateFormat.getBlueprintISO8601Format(); String out = df.format(date); json.writeString(out); } }
DateDeserializer.java:
public class DateDeserializer extends StdDeserializer<Date> { public DateDeserializer() { super(Date.class); } @Override public Date deserialize(JsonParser json, DeserializationContext context) throws IOException, JsonProcessingException { try { DateFormat df = StdDateFormat.getBlueprintISO8601Format(); return df.parse(json.getText()); } catch (ParseException e) { return null; } } }
fuente
Encontré la solución ahora basada en https://github.com/FasterXML/jackson-module-hibernate
Extendí el mapeador de objetos y agregué los atributos en el constructor heredado.
Luego, el nuevo mapeador de objetos se registra como un bean.
<!-- https://github.com/FasterXML/jackson-module-hibernate --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <array> <bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> <property name="objectMapper"> <bean class="de.company.backend.spring.PtxObjectMapper"/> </property> </bean> </array> </property> </bean>
fuente
ObjectMapper
como@Component
y@Primary
. Este es el enfoque recomendado en la Guía de referencia de Spring y me ha funcionado bien.Si desea agregar ObjectMapper personalizado para registrar serializadores personalizados, pruebe mi respuesta.
En mi caso (Spring 3.2.4 y Jackson 2.3.1), configuración XML para serializador personalizado:
<mvc:annotation-driven> <mvc:message-converters register-defaults="false"> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="serializers"> <array> <bean class="com.example.business.serializer.json.CustomObjectSerializer"/> </array> </property> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
se sobrescribió de forma inexplicable de nuevo al valor predeterminado por algo.
Esto funcionó para mí:
CustomObject.java
@JsonSerialize(using = CustomObjectSerializer.class) public class CustomObject { private Long value; public Long getValue() { return value; } public void setValue(Long value) { this.value = value; } }
CustomObjectSerializer.java
public class CustomObjectSerializer extends JsonSerializer<CustomObject> { @Override public void serialize(CustomObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException,JsonProcessingException { jgen.writeStartObject(); jgen.writeNumberField("y", value.getValue()); jgen.writeEndObject(); } @Override public Class<CustomObject> handledType() { return CustomObject.class; } }
No
<mvc:message-converters>(...)</mvc:message-converters>
se necesita ninguna configuración XML ( ) en mi solución.fuente
Estoy usando Spring 4.1.6 y Jackson FasterXML 2.1.4.
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <!-- 设置不输出null字段--> <property name="serializationInclusion" value="NON_NULL"/> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
esto funciona en mi configuración applicationContext.xml
fuente
SOLUCION 1
Primera solución de trabajo (probada) útil especialmente cuando se usa @EnableWebMvc:
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Autowired private ObjectMapper objectMapper;// created elsewhere @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // this won't add a 2nd MappingJackson2HttpMessageConverter // as the SOLUTION 2 is doing but also might seem complicated converters.stream().filter(c -> c instanceof MappingJackson2HttpMessageConverter).forEach(c -> { // check default included objectMapper._registeredModuleTypes, // e.g. Jdk8Module, JavaTimeModule when creating the ObjectMapper // without Jackson2ObjectMapperBuilder ((MappingJackson2HttpMessageConverter) c).setObjectMapper(this.objectMapper); }); }
SOLUCION 2
Por supuesto, el enfoque común a continuación también funciona (también funciona con @EnableWebMvc):
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Autowired private ObjectMapper objectMapper;// created elsewhere @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // this will add a 2nd MappingJackson2HttpMessageConverter // (additional to the default one) but will work and you // won't lose the default converters as you'll do when overwriting // configureMessageConverters(List<HttpMessageConverter<?>> converters) // // you still have to check default included // objectMapper._registeredModuleTypes, e.g. // Jdk8Module, JavaTimeModule when creating the ObjectMapper // without Jackson2ObjectMapperBuilder converters.add(new MappingJackson2HttpMessageConverter(this.objectMapper)); }
¿Por qué el uso de @EnableWebMvc es un problema?
@EnableWebMvc está usando
DelegatingWebMvcConfiguration
que se extiendeWebMvcConfigurationSupport
que hace esto:if (jackson2Present) { Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); if (this.applicationContext != null) { builder.applicationContext(this.applicationContext); } messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); }
lo que significa que no hay forma de inyectar el tuyo propio
ObjectMapper
con el propósito de prepararlo para ser usado para crear el predeterminadoMappingJackson2HttpMessageConverter
al usar @EnableWebMvc.fuente
En Spring Boot
2.2.x
necesitas configurarlo así:@Bean public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { return builder.build() }
Kotlin:
@Bean fun objectMapper(builder: Jackson2ObjectMapperBuilder) = builder.build()
fuente
Por encima de Spring 4, no es necesario configurar
MappingJacksonHttpMessageConverter
si solo tiene la intención de configurarObjectMapper
.(la configuración
MappingJacksonHttpMessageConverter
hará que pierda otro MessageConverter)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(); }
fuente
_halObjectMapper: defined in null
Para configurar un conversor de mensajes en spring-web simple, en este caso para habilitar Java 8 JSR-310 JavaTimeModule, primero debe implementar
WebMvcConfigurer
en su@Configuration
clase y luego anular elconfigureMessageConverters
método:@Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(new JavaTimeModule(), new Jdk8Module()).build() .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); converters.add(new MappingJackson2HttpMessageConverter(objectMapper)); }
De esta manera, puede registrar cualquier personalizado definido
ObjectMapper
en una configuración de Spring basada en Java.fuente
extendMessageConverters
, según la documentación de Spring . Pero no lo he necesitado, solo necesito un personalizadoMappingJackson2HttpMessageConverter
.Estoy usando Spring 3.2.4 y Jackson FasterXML 2.1.1.
He creado un JacksonObjectMapper personalizado que funciona con anotaciones explícitas para cada atributo de los Objetos asignados:
package com.test; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; public class MyJaxbJacksonObjectMapper extends ObjectMapper { public MyJaxbJacksonObjectMapper() { this.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) .setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY) .setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE) .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE) .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE); this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); } }
Luego, esto se instancia en la configuración de contexto ( servlet-context.xml ):
<mvc:annotation-driven> <mvc:message-converters> <beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <beans:property name="objectMapper"> <beans:bean class="com.test.MyJaxbJacksonObjectMapper" /> </beans:property> </beans:bean> </mvc:message-converters> </mvc:annotation-driven>
¡Esto funciona bien!
fuente