Skip to content

Commit 02dfa22

Browse files
committed
refactor ObjectMapper handling
MappingJackson2HttpMessageConverter, which is created automatically, was always using a different and internally created ObjectMapper instance instead of the global Bean ObjectMapper. for the longest time, i could not figure out why and how to modify this behavior. therefore, we were using the modifications this commit deletes in order to influence that. the goal was always: create one spring Bean ObjectMapper that has all needed capabilities and use it for all HTTP purposes. i stumbled upon this hint: spring-projects/spring-boot#15027 (comment) in essence, usage of "EnableWebMvc" annotation was causing the issue i was trying to solve. this annotation disables spring boot's auto-configuration and some other spring boot mvc defaults. after removing it + Jackson2ObjectMapperBuilderCustomizer from this commit, i could observe that the instance generated by Spring Boot is _the_ bean that is used everywhere.
1 parent 041c261 commit 02dfa22

File tree

1 file changed

+14
-40
lines changed

1 file changed

+14
-40
lines changed

src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@
1818
*/
1919
package de.rwth.idsg.steve.config;
2020

21-
import com.fasterxml.jackson.databind.DeserializationFeature;
22-
import com.fasterxml.jackson.databind.ObjectMapper;
23-
import com.fasterxml.jackson.databind.SerializationFeature;
21+
import com.fasterxml.jackson.datatype.joda.JodaModule;
2422
import com.mysql.cj.conf.PropertyKey;
2523
import com.zaxxer.hikari.HikariConfig;
2624
import com.zaxxer.hikari.HikariDataSource;
@@ -35,28 +33,24 @@
3533
import org.jooq.impl.DSL;
3634
import org.jooq.impl.DataSourceConnectionProvider;
3735
import org.jooq.impl.DefaultConfiguration;
36+
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
3837
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
3938
import org.springframework.context.annotation.Bean;
4039
import org.springframework.context.annotation.ComponentScan;
4140
import org.springframework.context.annotation.Configuration;
4241
import org.springframework.context.annotation.Primary;
43-
import org.springframework.format.support.FormattingConversionService;
44-
import org.springframework.http.converter.HttpMessageConverter;
45-
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
4642
import org.springframework.scheduling.annotation.EnableAsync;
4743
import org.springframework.scheduling.annotation.EnableScheduling;
4844
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
4945
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
50-
import org.springframework.web.accept.ContentNegotiationManager;
51-
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
5246
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
53-
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
5447
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
55-
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
5648
import org.springframework.web.servlet.view.InternalResourceViewResolver;
5749

5850
import javax.sql.DataSource;
59-
import java.util.List;
51+
52+
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
53+
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
6054

6155
/**
6256
* Configuration and beans of Spring Framework.
@@ -66,7 +60,6 @@
6660
*/
6761
@Slf4j
6862
@Configuration
69-
@EnableWebMvc
7063
@EnableScheduling
7164
@EnableAsync
7265
@ComponentScan("de.rwth.idsg.steve")
@@ -200,34 +193,15 @@ public void addResourceHandlers(final ResourceHandlerRegistry registry) {
200193
// API config
201194
// -------------------------------------------------------------------------
202195

203-
@Override
204-
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
205-
for (HttpMessageConverter<?> converter : converters) {
206-
if (converter instanceof MappingJackson2HttpMessageConverter conv) {
207-
ObjectMapper objectMapper = conv.getObjectMapper();
208-
objectMapper.findAndRegisterModules();
209-
// if the client sends unknown props, just ignore them instead of failing
210-
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
211-
// default is true
212-
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
213-
break;
214-
}
215-
}
216-
}
217-
218-
/**
219-
* Find the ObjectMapper used in MappingJackson2HttpMessageConverter and initialized by Spring automatically.
220-
* MappingJackson2HttpMessageConverter is not a Bean. It is created in {@link WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List)}.
221-
* Therefore, we have to access it via proxies that reference it. RequestMappingHandlerAdapter is a Bean, created in
222-
* {@link WebMvcConfigurationSupport#requestMappingHandlerAdapter(ContentNegotiationManager, FormattingConversionService, org.springframework.validation.Validator)}.
223-
*/
224196
@Bean
225-
@Primary
226-
public ObjectMapper jacksonObjectMapper(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
227-
return requestMappingHandlerAdapter.getMessageConverters().stream()
228-
.filter(converter -> converter instanceof MappingJackson2HttpMessageConverter)
229-
.findAny()
230-
.map(conv -> ((MappingJackson2HttpMessageConverter) conv).getObjectMapper())
231-
.orElseThrow(() -> new RuntimeException("There is no MappingJackson2HttpMessageConverter in Spring context"));
197+
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
198+
return builder -> {
199+
// default is true
200+
builder.featuresToDisable(WRITE_DATES_AS_TIMESTAMPS);
201+
// if the client sends unknown props, just ignore them instead of failing
202+
builder.featuresToDisable(FAIL_ON_UNKNOWN_PROPERTIES);
203+
// we still use joda DateTime...
204+
builder.modulesToInstall(new JodaModule());
205+
};
232206
}
233207
}

0 commit comments

Comments
 (0)