From 993fbb3a0dc42603d4844c47b983374d6bd11edd Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Tue, 22 Oct 2024 23:54:56 +0300 Subject: [PATCH] Retain existing modules in JacksonAutoConfiguration Previously, the default Jackson2ObjectMapperBuilderCustomizer implementation did set the list of modules to use. This had the effect of removing any modules that were registered programmatically by a customizer with higher precedence. This commit uses the variant of modulesToInstall that retain any existing modules. It also adds a note in the documentation as this behavior can be easily missed. See gh-42836 --- .../jackson/JacksonAutoConfiguration.java | 2 +- .../JacksonAutoConfigurationTests.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index e388f4c3e5..3bc23da13d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -307,7 +307,7 @@ public class JacksonAutoConfiguration { } private void configureModules(Jackson2ObjectMapperBuilder builder) { - builder.modulesToInstall(this.modules.toArray(new Module[0])); + builder.modulesToInstall((modules) -> modules.addAll(this.modules)); } private void configureLocale(Jackson2ObjectMapperBuilder builder) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java index 29dde38a97..06a937bc7b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java @@ -73,6 +73,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import static org.assertj.core.api.Assertions.assertThat; @@ -324,6 +326,16 @@ class JacksonAutoConfigurationTests { }); } + @Test + void customModulesRegisteredByBuilderCustomizerWithHighestPrecedenceShouldBeRetained() { + this.contextRunner.withUserConfiguration(ModuleConfig.class, CustomModuleBuilderCustomizerConfig.class) + .run((context) -> { + ObjectMapper objectMapper = context.getBean(Jackson2ObjectMapperBuilder.class).build(); + assertThat(context.getBean(CustomModule.class).getOwners()).contains(objectMapper); + assertThat(objectMapper.getRegisteredModuleIds()).contains("customizer-module"); + }); + } + @Test void defaultSerializationInclusion() { this.contextRunner.run((context) -> { @@ -592,6 +604,17 @@ class JacksonAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class CustomModuleBuilderCustomizerConfig { + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + Jackson2ObjectMapperBuilderCustomizer customModuleCustomizer() { + return (builder) -> builder.modulesToInstall(new SimpleModule("customizer-module")); + } + + } + @Configuration(proxyBeanMethods = false) static class ObjectMapperBuilderConsumerConfig {