mon objectif est de configurer la variable objectMapper
de manière à ne sérialiser que les éléments annotés avec @JsonProperty
.
Pour ce faire, j'ai suivi cette explication qui explique comment configurer le mappeur d'objets.
J'ai inclus le objectmapper personnalisé comme décrit ici .
Cependant, lorsque la classe NumbersOfNewEvents
est sérialisée, elle contient toujours tous les attributs du json.
Quelqu'un a-t-il un indice? Merci d'avance
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();
}
}
En utilisant Spring Boot (1.2.4) et Jackson (2.4.6), la configuration basée sur les annotations suivante a fonctionné pour moi.
@Configuration
public class JacksonConfiguration {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);
return mapper;
}
}
C'est peut-être parce que j'utilise Spring 3.1 (au lieu de Spring 3.0.5 selon votre question), mais la réponse de Steve Eastwood n'a pas fonctionné pour moi. Cette solution fonctionne pour Spring 3.1:
Dans votre contexte xml de printemps:
<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" />
Il y a org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean
pendant longtemps. À partir de la version 1.2 de Spring Boot, il existe org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
pour Java Config.
Dans String Boot, la configuration peut être aussi simple que:
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
dans classpath:application.properties
ou du code Java dans la classe @Configuration
:
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
return builder;
}
Voir:
J'ai utilisé cela avec Jackson 2.x et Spring 3.1.2+
servlet-context.xml:
Notez que l'élément racine est <beans:beans>
; vous devrez peut-être supprimer beans
et ajouter mvc
à certains de ces éléments, selon votre configuration.
<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;
}
}
}
J'ai trouvé la solution maintenant sur https://github.com/FasterXML/jackson-module-hibernate
J'ai étendu le mappeur d'objets et ajouté les attributs dans le constructeur hérité.
Ensuite, le nouveau mappeur d'objets est enregistré en tant que 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>
Si vous souhaitez ajouter ObjectMapper personnalisé pour l'enregistrement de sérialiseurs personnalisés, essayez ma réponse.
Dans mon cas (Spring 3.2.4 et Jackson 2.3.1), configuration XML pour le sérialiseur personnalisé:
<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>
était de manière inexpliquée écrasée de nouveau par défaut.
Cela a fonctionné pour moi:
@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject {
private Long value;
public Long getValue() {
return value;
}
public void setValue(Long value) {
this.value = value;
}
}
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;
}
}
Aucune configuration XML (<mvc:message-converters>(...)</mvc:message-converters>
) n'est requise dans ma solution.
J'utilise Spring 4.1.6 et 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>
cela fonctionne sur ma configration de applicationContext.xml
J'utilise Spring 3.2.4 et Jackson FasterXML 2.1.1.
J'ai créé un personnalisé JacksonObjectMapper qui fonctionne avec des annotations explicites pour chaque attribut des objets mappés:
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);
}
}
Ceci est ensuite instancié dans la configuration de contexte ( 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>
Cela fonctionne bien!
Pour configurer un convertisseur de message dans plain spring-web, dans ce cas, pour activer JavaTimeModule Java 8 JSR-310, vous devez d'abord implémenter WebMvcConfigurer
dans votre classe @Configuration
, puis substituer la méthode configureMessageConverters
:
@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 cette façon, vous pouvez enregistrer toute variable ObjectMapper
personnalisée définie dans une configuration Spring basée sur Java.
Au-dessus de Spring 4, il n'est pas nécessaire de configurer MappingJacksonHttpMessageConverter
si vous souhaitez uniquement configurer ObjectMapper
.
(configurer MappingJacksonHttpMessageConverter
vous fera perdre un autre MessageConverter)
Vous avez juste besoin de faire:
public class MyObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 4219938065516862637L;
public MyObjectMapper() {
super();
enable(SerializationFeature.INDENT_OUTPUT);
}
}
Et dans votre configuration Spring, créez ce bean:
@Bean
public MyObjectMapper myObjectMapper() {
return new MyObjectMapper();
}
SOLUTION 1
Première solution de travail (testée) particulièrement utile lors de l'utilisation de @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);
});
}
SOLUTION 2
Bien sûr, l’approche commune ci-dessous fonctionne également (avec @EnableWebMvc également):
@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));
}
Pourquoi l'utilisation de @EnableWebMvc pose problème?
@EnableWebMvc utilise DelegatingWebMvcConfiguration
qui étend WebMvcConfigurationSupport
qui fait ceci:
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
ce qui signifie qu'il n'y a aucun moyen d'injecter votre propre ObjectMapper
dans le but de le préparer à être utilisé pour créer le MappingJackson2HttpMessageConverter
par défaut lors de l'utilisation de @EnableWebMvc.