meu objetivo é configurar o de objectMapper
forma que ele apenas serialize elementos que são anotados com @JsonProperty
.
Para fazer isso, segui esta explicação que diz como configurar o mapeador de objetos.
Incluí o mapeador de objetos personalizado conforme descrito aqui .
No entanto, quando a classe NumbersOfNewEvents
é serializada, ela ainda contém todos os atributos no json.
Alguém tem uma dica? desde já, obrigado
Jackson 1.8.0 spring 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
? É uma maneira automática de instruir o Spring Boot a usar essa classe como classe de configuração para Jackson?@EnableWebMvc
? Duvido porque ... veja na minha resposta : Por que o uso de @EnableWebMvc é um problema?Pode ser porque estou usando Spring 3.1 (em vez de Spring 3.0.5 como sua pergunta especificou), mas a resposta de Steve Eastwood não funcionou para mim. Esta solução funciona para Spring 3.1:
Em seu 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" />
fonte
Há
org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean
muito tempo. A partir da versão 1.2 do Spring Boot, háorg.springframework.http.converter.json.Jackson2ObjectMapperBuilder
para Java Config.Em String Boot, a configuração pode ser tão simples 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
em
classpath:application.properties
ou algum código Java na@Configuration
classe:@Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd")); return builder; }
Vejo:
fonte
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json()
.Eu usei isso com Jackson 2.xe Spring 3.1.2+
servlet-context.xml:
Observe que o elemento raiz é
<beans:beans>
, portanto, pode ser necessário removerbeans
e adicionarmvc
alguns desses elementos, dependendo de sua configuração.<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; } } }
fonte
Encontrei a solução agora baseada em https://github.com/FasterXML/jackson-module-hibernate
Estendi o mapeador de objetos e adicionei os atributos no construtor herdado.
Em seguida, o novo mapeador de objetos é registrado como um 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>
fonte
ObjectMapper
como@Component
e@Primary
. Essa é a abordagem recomendada no Guia de Referência do Spring e funcionou bem para mim.Se você deseja incluir ObjectMapper customizado para registrar serializadores customizados, tente minha resposta.
No meu caso (Spring 3.2.4 e Jackson 2.3.1), configuração 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>
foi de forma inexplicável substituída de volta ao padrão por algo.
Isso funcionou para mim:
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; } }
Nenhuma configuração XML (
<mvc:message-converters>(...)</mvc:message-converters>
) é necessária em minha solução.fonte
SOLUÇÃO 1
Primeira solução de trabalho (testada) útil especialmente ao usar @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); }); }
SOLUÇÃO 2
É claro que a abordagem comum abaixo também funciona (trabalhando também com @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 que o uso de @EnableWebMvc é um problema?
@EnableWebMvc está usando o
DelegatingWebMvcConfiguration
que estende oWebMvcConfigurationSupport
que faz isso:if (jackson2Present) { Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); if (this.applicationContext != null) { builder.applicationContext(this.applicationContext); } messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); }
o que significa que não há como injetar o seu próprio
ObjectMapper
com o objetivo de prepará-lo para ser usado na criação do padrãoMappingJackson2HttpMessageConverter
ao usar @EnableWebMvc.fonte
Estou usando Spring 4.1.6 e 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>
isso funciona na minha configuração applicationContext.xml
fonte
Para configurar um conversor de mensagem em spring-web simples, neste caso para habilitar o Java 8 JSR-310 JavaTimeModule, primeiro você precisa implementar
WebMvcConfigurer
em sua@Configuration
classe e então substituir oconfigureMessageConverters
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)); }
Assim, você pode registrar qualquer definição personalizada
ObjectMapper
em uma configuração Spring baseada em Java.fonte
extendMessageConverters
, de acordo com a documentação do Spring . Mas não tive necessidade, só preciso de um customizadoMappingJackson2HttpMessageConverter
.No Spring Boot,
2.2.x
você precisa configurá-lo assim:@Bean public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { return builder.build() }
Kotlin:
@Bean fun objectMapper(builder: Jackson2ObjectMapperBuilder) = builder.build()
fonte
Acima do Spring 4, não há necessidade de configurar
MappingJacksonHttpMessageConverter
se você apenas pretende configurarObjectMapper
.(configure
MappingJacksonHttpMessageConverter
fará com que você perca outro MessageConverter)Você só precisa fazer:
public class MyObjectMapper extends ObjectMapper { private static final long serialVersionUID = 4219938065516862637L; public MyObjectMapper() { super(); enable(SerializationFeature.INDENT_OUTPUT); } }
E em sua configuração Spring, crie este bean:
@Bean public MyObjectMapper myObjectMapper() { return new MyObjectMapper(); }
fonte
_halObjectMapper: defined in null
Estou usando Spring 3.2.4 e Jackson FasterXML 2.1.1.
Eu criei um JacksonObjectMapper personalizado que funciona com anotações explícitas para cada atributo dos objetos mapeados:
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); } }
Então, isso é instanciado na configuração 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>
Isso funciona bem!
fonte