Merge pull request #42836 from nosan

* pr/42836:
  Polish "Retain existing modules in JacksonAutoConfiguration"
  Retain existing modules in JacksonAutoConfiguration

Closes gh-42836
This commit is contained in:
Stéphane Nicoll
2025-01-07 12:15:11 +01:00
3 changed files with 32 additions and 1 deletions

View File

@@ -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) {

View File

@@ -73,6 +73,7 @@ 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.annotation.Order;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import static org.assertj.core.api.Assertions.assertThat;
@@ -324,6 +325,17 @@ class JacksonAutoConfigurationTests {
});
}
@Test
void customModulesRegisteredByBuilderCustomizerShouldBeRetained() {
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("module-A", "module-B",
CustomModule.class.getName());
});
}
@Test
void defaultSerializationInclusion() {
this.contextRunner.run((context) -> {
@@ -592,6 +604,23 @@ class JacksonAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class CustomModuleBuilderCustomizerConfig {
@Bean
@Order(-1)
Jackson2ObjectMapperBuilderCustomizer highPrecedenceCustomizer() {
return (builder) -> builder.modulesToInstall((modules) -> modules.add(new SimpleModule("module-A")));
}
@Bean
@Order(1)
Jackson2ObjectMapperBuilderCustomizer lowPrecedenceCustomizer() {
return (builder) -> builder.modulesToInstall((modules) -> modules.add(new SimpleModule("module-B")));
}
}
@Configuration(proxyBeanMethods = false)
static class ObjectMapperBuilderConsumerConfig {

View File

@@ -118,6 +118,8 @@ Such customizer beans can be ordered (Boot's own customizer has an order of 0),
Any beans of type javadoc:com.fasterxml.jackson.databind.Module[] are automatically registered with the auto-configured javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[] and are applied to any javadoc:com.fasterxml.jackson.databind.ObjectMapper[] instances that it creates.
This provides a global mechanism for contributing custom modules when you add new features to your application.
NOTE: If you wish to register additional modules programmatically using a javadoc:org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer[], make sure to use the `modulesToInstall` method that takes a consumer as the other variants are not additive.
If you want to replace the default javadoc:com.fasterxml.jackson.databind.ObjectMapper[] completely, either define a javadoc:org.springframework.context.annotation.Bean[format=annotation] of that type or, if you prefer the builder-based approach, define a javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[] javadoc:org.springframework.context.annotation.Bean[format=annotation].
When defining an javadoc:com.fasterxml.jackson.databind.ObjectMapper[] bean, marking it as javadoc:org.springframework.context.annotation.Primary[format=annotation] is recommended as the auto-configuration's javadoc:com.fasterxml.jackson.databind.ObjectMapper[] that it will replace is javadoc:org.springframework.context.annotation.Primary[format=annotation].
Note that, in either case, doing so disables all auto-configuration of the javadoc:com.fasterxml.jackson.databind.ObjectMapper[].