115

My goal is to configure the objectMapper in the way that it only serialises element which are annotated with @JsonProperty.

In order to do so I followed this explanation which says how to configurate the objectmapper.

I included the custom objectmapper as described here.

However, when the class NumbersOfNewEvents is serialized it still contains all attributes in the json.

Why is this happening, and how can I get the desired result?

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(); } } 

13 Answers 13

162

Using Spring Boot (1.2.4) and Jackson (2.4.6) the following annotation based configuration worked for me.

@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; } } 
Sign up to request clarification or add additional context in comments.

11 Comments

Spring supports customize some properties of Jackson in application.properties: docs.spring.io/spring-boot/docs/current/reference/html/…
Hey, guys. I faced a problem that when you declare bean with name objectMapper in java config, just as it is showed in example, this bean is ignored by Spring Boot, cause bean with such name is already registered in the system, even if you place \@Primary annotation on it. To fix this problem you need to register bean with different name, e.g. jsonObjectMapper, and mark it with \@Primary annotation
Please refer to my answer if you're not using Spring Boot.
A question: you must name the class JacksonConfiguration? It's an automagical way to instruct Spring Boot to use this class as configuration class for Jackson?
Is it really working when using also @EnableWebMvc? I doubt because ... see in my answer: Why @EnableWebMvc usage is a problem?
|
27

It may be because I'm using Spring 3.1 (instead of Spring 3.0.5 as your question specified), but Steve Eastwood's answer didn't work for me. This solution works for Spring 3.1:

In your spring xml context:

<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" /> 

2 Comments

This helped for using Jackson 2.x with Spring 3.1: stackoverflow.com/questions/10420040/…
Useful! Had to adopt this approach to registering my custom ObjectMapper on upgrading from Spring 3.0 to 3.2. Had previously been setting an objectMapper property when defining a MappingJacksonJsonView bean, but that no longer worked. This is with Jackson 1.7
26

There is org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean for a long time. Starting from 1.2 release of Spring Boot there is org.springframework.http.converter.json.Jackson2ObjectMapperBuilder for Java Config.

In String Boot configuration can be as simple as:

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 or some Java code in @Configuration class:

@Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd")); return builder; } 

See:

2 Comments

This works for most use cases, however the Spring Boot jackson configuration is ignored if you're using the @EnableWebMvc annotation (tested in Spring Boot 2.0.3).
Though I didn't test I'm sure that won't work with @EnableWebMvc (despite using or not spring boot). Why? see WebMvcConfigurationSupport (DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport): Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json().
16

I've used this with Jackson 2.x and Spring 3.1.2+

servlet-context.xml:

Note that the root element is <beans:beans>, so you may need to remove beans and add mvc to some of these elements depending on your setup.

 <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; } } } 

Comments

15

SOLUTION 1

First (tested) working solution useful especially when using @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

Of course the common approach below works too (also working with @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)); } 

Why @EnableWebMvc usage is a problem?

@EnableWebMvc is using DelegatingWebMvcConfiguration which extends WebMvcConfigurationSupport which does this:

if (jackson2Present) { Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); if (this.applicationContext != null) { builder.applicationContext(this.applicationContext); } messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); } 

which means that there's no way of injecting your own ObjectMapper with the purpose of preparing it to be used for creating the default MappingJackson2HttpMessageConverter when using @EnableWebMvc.

3 Comments

Great! Actually RepositoryRestMvcConfiguration, part of spring-data-rest-webmvc:3.2.3 doesn't use ObjectMapper created by Spring and only custom objectMapper with modules don't work out-of-the-box. First approach are actual and replace ObjectMapper customized by spring-data-rest-webmvc. Thanks!
I had an issue where I couldn't customize my ObjectMapper that was miserable b/c of EnableWebMvc. So glad I stumbled across this.
Here's a way to combine the default Spring Boot Jackson config (props) with Spring MVC: stackoverflow.com/a/78419070/648271
10

I found the solution now based on https://github.com/FasterXML/jackson-module-hibernate

I extended the object mapper and added the attributes in the inherited constructor.

Then the new object mapper is registered as a 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> 

2 Comments

Thank you very much for the solution! I have spen over four hours digging around <annotation-driven>, it simply did not pick up the converters. Tried your answer, finally it works!
To use annotations, you could just annotate your custom Mapper that extends ObjectMapper as @Component and @Primary. This is the approach recommended in the Spring Reference Guide and it has worked fine for me.
9

If you want to add custom ObjectMapper for registering custom serializers, try my answer.

In my case (Spring 3.2.4 and Jackson 2.3.1), XML configuration for custom serializer:

<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> 

was in unexplained way overwritten back to default by something.

This worked for me:

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 XML configuration (<mvc:message-converters>(...)</mvc:message-converters>) is needed in my solution.

Comments

7

I am using Spring 4.1.6 and 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> 

this works at my applicationContext.xml configration

Comments

4

To configure a message converter in plain spring-web, in this case to enable the Java 8 JSR-310 JavaTimeModule, you first need to implement WebMvcConfigurer in your @Configuration class and then override the configureMessageConverters method:

@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)); } 

Like this you can register any custom defined ObjectMapper in a Java-based Spring configuration.

5 Comments

I would prefer to have the ObjectMapper injected and configured via Spring Boot.
Sure, if you use Spring Boot. This was not a Spring Boot question.
Yes, interesting to notice that when using Spring Web with Spring Boot it does not use the ObjectMapper provided by Spring Boot and that is why I ended up in this question which helped me.
This would clear all default message converters! I'm pretty sure no one wants this. See my answer for the solution.
Well if you'd want to extend the message converters the correct solution would be to override extendMessageConverters, as per Spring documentation. But I haven't had any need for it, because I just need a customized MappingJackson2HttpMessageConverter.
4

In Spring Boot 2.2.x you need to configure it like this:

@Bean public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { return builder.build() } 

Kotlin:

@Bean fun objectMapper(builder: Jackson2ObjectMapperBuilder) = builder.build() 

1 Comment

Can you explain why?
2

Above Spring 4, there is no need to configure MappingJacksonHttpMessageConverter if you only intend to configure ObjectMapper.

(configure MappingJacksonHttpMessageConverter will cause you to lose other MessageConverter)

You just need to do:

public class MyObjectMapper extends ObjectMapper { private static final long serialVersionUID = 4219938065516862637L; public MyObjectMapper() { super(); enable(SerializationFeature.INDENT_OUTPUT); } } 

And in your Spring configuration, create this bean:

@Bean public MyObjectMapper myObjectMapper() { return new MyObjectMapper(); } 

2 Comments

Does not work - - customObjectMapper: defined by method 'customObjectMapper' in class path resource [com/Config.class] - _halObjectMapper: defined in null
And this will only work with Spring Boot. Not plain Spring Web.
1

I am using Spring 3.2.4 and Jackson FasterXML 2.1.1.

I have created a custom JacksonObjectMapper that works with explicit annotations for each attribute of the Objects mapped:

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); } } 

Then this is instantiated in the context-configuration (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> 

This works fine!

Comments

1

If you are using Spring WebFlux, @EnableWebFlux overrides any custom settings like spring.jackson.serialization.write-dates-as-timestamps=false, so you need to override WebFlux's ObjectMapper instance according to WebFlux doc.

@Configuration public class WebfluxConfig implements WebFluxConfigurer { private final ObjectMapper objectMapper; @Autowired public WebfluxConfig(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper)); configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper)); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.