Allow a custom JsonFactory to be used with JsonMapper.Builder

This commit improves the auto-configuration of the JSonMapper.Builder
to accept a custom JsonFactory if a bean of this type is present.

Closes gh-48594
This commit is contained in:
Stéphane Nicoll
2025-12-29 13:11:03 +01:00
parent 2c55ccfa7f
commit 22d6f6a7de
3 changed files with 26 additions and 3 deletions
@@ -106,7 +106,8 @@ This environment-based configuration is applied to the auto-configured javadoc:t
To ease the migration when working on an application that previously used Jackson 2, the auto-configured `JsonMapper` can be configured to use defaults that are as close as possible to those that Spring Boot used for Jackson 2. To enable these defaults, set configprop:spring.jackson.use-jackson2-defaults[] to `true`.
The context's javadoc:tools.jackson.databind.json.JsonMapper$Builder[] can be customized by one or more javadoc:org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer[] beans.
If a javadoc:tools.jackson.core.json.JsonFactory[] bean is present, it is used by the context's javadoc:tools.jackson.databind.json.JsonMapper$Builder[].
The builder can also be customized by one or more javadoc:org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer[] beans.
Such customizer beans can be ordered (Boot's own customizer has an order of 0), letting additional customization be applied both before and after Boot's customization.
Any beans of type javadoc:tools.jackson.databind.JacksonModule[] are automatically registered with the auto-configured javadoc:tools.jackson.databind.json.JsonMapper$Builder[] and are applied to any javadoc:tools.jackson.databind.json.JsonMapper[] instances that it creates.
@@ -32,6 +32,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import org.jspecify.annotations.Nullable;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.databind.JacksonModule;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.PropertyNamingStrategies;
@@ -97,8 +98,9 @@ public final class JacksonAutoConfiguration {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ConditionalOnMissingBean
JsonMapper.Builder jsonMapperBuilder(List<JsonMapperBuilderCustomizer> customizers) {
JsonMapper.Builder builder = JsonMapper.builder();
JsonMapper.Builder jsonMapperBuilder(ObjectProvider<JsonFactory> jsonFactory,
List<JsonMapperBuilderCustomizer> customizers) {
JsonMapper.Builder builder = JsonMapper.builder(jsonFactory.getIfAvailable(JsonFactory::new));
customize(builder, customizers);
return builder;
}
@@ -34,6 +34,8 @@ import org.junit.jupiter.params.provider.EnumSource;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.StreamReadFeature;
import tools.jackson.core.StreamWriteFeature;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.core.json.JsonFactoryBuilder;
import tools.jackson.core.json.JsonReadFeature;
import tools.jackson.core.json.JsonWriteFeature;
import tools.jackson.databind.DeserializationFeature;
@@ -391,6 +393,24 @@ class JacksonAutoConfigurationTests {
});
}
@Test
void defaultJsonFactoryIsRegisteredWithTheMapperBuilderWhenNoCustomFactoryExists() {
this.contextRunner.run((context) -> {
Builder jsonMapperBuilder = context.getBean(JsonMapper.Builder.class);
assertThat(jsonMapperBuilder.isEnabled(StreamReadFeature.AUTO_CLOSE_SOURCE)).isTrue();
});
}
@Test
void customJsonFactoryIsRegisteredWithTheMapperBuilder() {
JsonFactory customJsonFactory = new JsonFactoryBuilder().configure(StreamReadFeature.AUTO_CLOSE_SOURCE, false)
.build();
this.contextRunner.withBean("customJsonFactory", JsonFactory.class, () -> customJsonFactory).run((context) -> {
Builder jsonMapperBuilder = context.getBean(JsonMapper.Builder.class);
assertThat(jsonMapperBuilder.isEnabled(StreamReadFeature.AUTO_CLOSE_SOURCE)).isFalse();
});
}
@EnumSource
@ParameterizedTest
void moduleBeansAndWellKnownModulesAreRegisteredWithTheMapperBuilder(MapperType mapperType) {