mein Ziel ist es, die objectMapper
so zu konfigurieren, dass nur Elemente serialisiert werden, die mit @JsonProperty
versehen sind.
Um dies zu tun, folgte ich dieser Erklärung , die besagt, wie der objectmapper zu konfigurieren ist.
Ich habe den benutzerdefinierten Objectmapper wie hier hinzugefügt.
Wenn die Klasse NumbersOfNewEvents
jedoch serialisiert ist, enthält sie immer noch alle Attribute im json.
Hat jemand einen Tipp? Vielen Dank im Voraus
Jackson 1.8.0 Frühling 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();
}
}
Mit Spring Boot (1.2.4) und Jackson (2.4.6) funktionierte die folgende auf Anmerkungen basierende Konfiguration für mich.
@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;
}
}
Möglicherweise verwende ich Spring 3.1 (anstelle von Spring 3.0.5), aber die Antwort von Steve Eastwood funktionierte nicht für mich. Diese Lösung funktioniert für Spring 3.1:
In deinem XML-Kontext im Frühling:
<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" />
Es gibt lange Zeit org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean
. Ab Version 1.2 von Spring Boot gibt es org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
für Java Config.
In der String-Boot-Konfiguration kann das so einfach sein:
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
in classpath:application.properties
oder in einem Java-Code in @Configuration
-Klasse:
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
return builder;
}
Sehen:
Ich habe dies mit Jackson 2.x und Spring 3.1.2+ verwendet.
servlet-context.xml:
Beachten Sie, dass das Stammelement <beans:beans>
ist. Daher müssen Sie möglicherweise beans
entfernen und mvc
je nach Ihren Einstellungen zu einigen dieser Elemente hinzufügen.
<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;
}
}
}
Ich fand die Lösung jetzt basierend auf https://github.com/FasterXML/jackson-module-hibernate
Ich erweiterte den Object Mapper und fügte die Attribute im geerbten Konstruktor hinzu.
Dann wird der neue Object Mapper als Bean registriert.
<!-- 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>
Wenn Sie einen benutzerdefinierten ObjectMapper zum Registrieren benutzerdefinierter Serialisierer hinzufügen möchten, probieren Sie meine Antwort.
In meinem Fall (Spring 3.2.4 und Jackson 2.3.1), XML-Konfiguration für benutzerdefinierten Serialisierer:
<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>
wurde auf unerklärliche Weise von etwas zurückgeschrieben.
Das hat für mich funktioniert:
@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;
}
}
In meiner Lösung ist keine XML-Konfiguration (<mvc:message-converters>(...)</mvc:message-converters>
) erforderlich.
Ich verwende Spring 4.1.6 und 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>
dies funktioniert in meiner applicationContext.xml-Konfiguration
Ich verwende Spring 3.2.4 und Jackson FasterXML 2.1.1.
Ich habe einen benutzerdefinierten JacksonObjectMapper erstellt, der mit expliziten Anmerkungen für jedes Attribut der zugeordneten Objekte arbeitet:
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);
}
}
Dann wird dies in der Kontext-Konfiguration ( servlet-context.xml ) instanziiert:
<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>
Das funktioniert gut!
Um einen Nachrichtenkonverter im einfachen Spring-Web zu konfigurieren, in diesem Fall, um Java 8 JSR-310 JavaTimeModule zu aktivieren, müssen Sie zunächst WebMvcConfigurer
in Ihrer @Configuration
-Klasse implementieren und anschließend die configureMessageConverters
-Methode überschreiben:
@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));
}
Auf diese Weise können Sie jede benutzerdefinierte ObjectMapper
in einer Java-basierten Spring-Konfiguration registrieren.
Oberhalb von Spring 4 müssen Sie MappingJacksonHttpMessageConverter
nicht konfigurieren, wenn Sie nur ObjectMapper
konfigurieren möchten.
(configure MappingJacksonHttpMessageConverter
führt dazu, dass Sie andere MessageConverter verlieren)
Sie müssen nur tun:
public class MyObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 4219938065516862637L;
public MyObjectMapper() {
super();
enable(SerializationFeature.INDENT_OUTPUT);
}
}
Erstellen Sie in Ihrer Spring-Konfiguration diese Bean:
@Bean
public MyObjectMapper myObjectMapper() {
return new MyObjectMapper();
}
LÖSUNG 1
Erste funktionierende Lösung (getestet), die besonders bei Verwendung von @EnableWebMvc nützlich ist:
@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);
});
}
LÖSUNG 2
Natürlich funktioniert auch der folgende allgemeine Ansatz (auch mit @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));
}
Warum ist die Verwendung von @EnableWebMvc ein Problem?
@EnableWebMvc verwendet DelegatingWebMvcConfiguration
, wodurch WebMvcConfigurationSupport
erweitert wird.
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
das bedeutet, dass es keine Möglichkeit gibt, eine eigene ObjectMapper
zu injizieren, um sie für die Erstellung des Standard-MappingJackson2HttpMessageConverter
vorzubereiten, wenn @EnableWebMvc verwendet wird.