moim celem jest skonfigurowanie elementu objectMapper
w taki sposób, aby serializował tylko elementy, które są oznaczone adnotacją @JsonProperty
.
Aby to zrobić, postępowałem zgodnie z tym wyjaśnieniem, które mówi, jak skonfigurować obiekt mapowania.
Dołączyłem niestandardowy obiekt mapowania zgodnie z opisem tutaj .
Jednak gdy klasa NumbersOfNewEvents
jest serializowana, nadal zawiera wszystkie atrybuty w pliku json.
Czy ktoś ma podpowiedź? Z góry dziękuję
Jackson 1.8.0, wiosna 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
? To automagiczny sposób, aby poinstruować Spring Boot, aby używał tej klasy jako klasy konfiguracyjnej dla Jacksona?@EnableWebMvc
? Wątpię, ponieważ ... zobacz w mojej odpowiedzi : Dlaczego używanie @EnableWebMvc jest problemem?Może to być spowodowane tym, że używam Spring 3.1 (zamiast Spring 3.0.5, jak określiło twoje pytanie), ale odpowiedź Steve'a Eastwooda nie zadziałała dla mnie. To rozwiązanie działa w wersji Spring 3.1:
W Twoim kontekście wiosennego XML:
<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" />
źródło
Jest
org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean
od dawna. Począwszy od wersji 1.2 Spring Boot dostępna jestorg.springframework.http.converter.json.Jackson2ObjectMapperBuilder
Java Config.W konfiguracji String Boot może być tak prosta, jak:
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
lub jakiś kod Java w@Configuration
klasie:@Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd")); return builder; }
Widzieć:
źródło
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json()
.Użyłem tego z Jackson 2.x i Spring 3.1.2+
servlet-context.xml:
Zwróć uwagę, że element główny to
<beans:beans>
, więc może być konieczne usunięciebeans
i dodaniemvc
niektórych z tych elementów w zależności od konfiguracji.<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; } } }
źródło
Znalazłem rozwiązanie teraz oparte na https://github.com/FasterXML/jackson-module-hibernate
Rozszerzyłem mapowanie obiektów i dodałem atrybuty w odziedziczonym konstruktorze.
Następnie nowy element mapujący obiekty jest rejestrowany jako komponent 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>
źródło
ObjectMapper
na@Component
i@Primary
. Jest to podejście zalecane w Przewodniku po sprężynach i dobrze mi się sprawdziło.Jeśli chcesz dodać niestandardowy ObjectMapper do rejestrowania niestandardowych serializatorów, wypróbuj moją odpowiedź.
W moim przypadku (Spring 3.2.4 i Jackson 2.3.1), konfiguracja XML dla niestandardowego serializatora:
<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>
został przez coś w niewyjaśniony sposób nadpisany z powrotem do wartości domyślnej.
To zadziałało dla mnie:
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; } }
<mvc:message-converters>(...)</mvc:message-converters>
W moim rozwiązaniu nie jest wymagana żadna konfiguracja XML ( ).źródło
Używam Spring 4.1.6 i 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>
działa to w mojej konfiguracji applicationContext.xml
źródło
ROZWIĄZANIE 1
Pierwsze działające rozwiązanie (przetestowane) przydatne zwłaszcza przy korzystaniu z @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); }); }
ROZWIĄZANIE 2
Oczywiście wspólne podejście poniżej działa również (działa również z @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)); }
Dlaczego używanie @EnableWebMvc jest problemem?
@EnableWebMvc używa
DelegatingWebMvcConfiguration
which extends,WebMvcConfigurationSupport
co robi to:if (jackson2Present) { Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); if (this.applicationContext != null) { builder.applicationContext(this.applicationContext); } messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); }
co oznacza, że nie ma możliwości wstrzyknięcia własnego
ObjectMapper
w celu przygotowania go do użycia do utworzenia domyślnegoMappingJackson2HttpMessageConverter
podczas korzystania z @EnableWebMvc.źródło
W Spring Boot
2.2.x
musisz to skonfigurować w następujący sposób:@Bean public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { return builder.build() }
Kotlin:
@Bean fun objectMapper(builder: Jackson2ObjectMapperBuilder) = builder.build()
źródło
Powyżej Spring 4 nie ma potrzeby konfigurowania,
MappingJacksonHttpMessageConverter
jeśli zamierzasz tylko konfigurowaćObjectMapper
.(konfiguracja
MappingJacksonHttpMessageConverter
spowoduje utratę innych MessageConverter)Musisz tylko:
public class MyObjectMapper extends ObjectMapper { private static final long serialVersionUID = 4219938065516862637L; public MyObjectMapper() { super(); enable(SerializationFeature.INDENT_OUTPUT); } }
A w konfiguracji Spring utwórz tę fasolkę:
@Bean public MyObjectMapper myObjectMapper() { return new MyObjectMapper(); }
źródło
_halObjectMapper: defined in null
Aby skonfigurować konwerter komunikatów w zwykłym spring-web, w tym przypadku, aby włączyć JavaTimeModule JSR-310 Java 8, musisz najpierw zaimplementować
WebMvcConfigurer
w swojej@Configuration
klasie, a następnie nadpisaćconfigureMessageConverters
metodę:@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)); }
W ten sposób możesz zarejestrować dowolną niestandardową
ObjectMapper
konfigurację Springa opartą na Javie.źródło
extendMessageConverters
, zgodnie z dokumentacją Springa . Ale nie potrzebowałem tego, ponieważ potrzebuję tylko niestandardowegoMappingJackson2HttpMessageConverter
.Używam Springa 3.2.4 i Jackson FasterXML 2.1.1.
Utworzyłem niestandardowy JacksonObjectMapper, który działa z wyraźnymi adnotacjami dla każdego atrybutu mapowanych obiektów:
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); } }
Następnie jest tworzony egzemplarz w konfiguracji kontekstu ( 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>
To działa dobrze!
źródło