Skip to content

Commit 52eea3d

Browse files
committed
Automatically find and add Jackson modules
Closes gh-47485
1 parent 2d6b460 commit 52eea3d

File tree

5 files changed

+39
-5
lines changed

5 files changed

+39
-5
lines changed

documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/spring-mvc.adoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ The context's javadoc:tools.jackson.databind.json.JsonMapper.Builder[] can be cu
110110
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.
111111

112112
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.
113-
This provides a global mechanism for contributing custom modules when you add new features to your application.
113+
This provides an application-wide mechanism for contributing custom modules when you add new features to your application.
114+
115+
Any modules that participate in the Java `ServiceLoader` mechanism are, by default, found and added to the auto-configured javadoc:tools.jackson.databind.json.JsonMapper.Builder[]. To disable this behavior, set configprop:spring.jackson.find-and-add-modules[] to `false`.
114116

115117
If you want to replace the default javadoc:tools.jackson.databind.json.JsonMapper[] 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:tools.jackson.databind.json.JsonMapper.Builder[] javadoc:org.springframework.context.annotation.Bean[format=annotation].
116118
When defining an javadoc:tools.jackson.databind.json.JsonMapper[] bean, marking it as javadoc:org.springframework.context.annotation.Primary[format=annotation] is recommended as the auto-configuration's javadoc:tools.jackson.databind.json.JsonMapper[] that it will replace is javadoc:org.springframework.context.annotation.Primary[format=annotation].

module/spring-boot-jackson/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ dependencies {
3737

3838
testImplementation(project(":core:spring-boot-test"))
3939
testImplementation(project(":test-support:spring-boot-test-support"))
40+
testImplementation("tools.jackson.module:jackson-module-kotlin")
4041
testRuntimeOnly("ch.qos.logback:logback-classic")
4142
}
4243

module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfiguration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ public void customize(JsonMapper.Builder builder) {
170170
.disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS,
171171
DateTimeFeature.WRITE_DURATIONS_AS_TIMESTAMPS);
172172
}
173+
if (this.jacksonProperties.isFindAndAddModules()) {
174+
builder.findAndAddModules(getClass().getClassLoader());
175+
}
173176
if (this.jacksonProperties.getDefaultPropertyInclusion() != null) {
174177
builder.changeDefaultPropertyInclusion((handler) -> handler
175178
.withValueInclusion(this.jacksonProperties.getDefaultPropertyInclusion()));

module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonProperties.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ public class JacksonProperties {
115115
*/
116116
private boolean useJackson2Defaults = false;
117117

118+
/**
119+
* Whether to find and add modules to the auto-configured JsonMapper.Builder using
120+
* MapperBuilder.findAndAddModules(ClassLoader).
121+
*/
122+
private boolean findAndAddModules = true;
123+
118124
private final Datatype datatype = new Datatype();
119125

120126
private final Json json = new Json();
@@ -199,6 +205,14 @@ public void setUseJackson2Defaults(boolean useJackson2Defaults) {
199205
this.useJackson2Defaults = useJackson2Defaults;
200206
}
201207

208+
public boolean isFindAndAddModules() {
209+
return this.findAndAddModules;
210+
}
211+
212+
public void setFindAndAddModules(boolean findModules) {
213+
this.findAndAddModules = findModules;
214+
}
215+
202216
public Datatype getDatatype() {
203217
return this.datatype;
204218
}

module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfigurationTests.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import tools.jackson.databind.json.JsonMapper.Builder;
5353
import tools.jackson.databind.module.SimpleModule;
5454
import tools.jackson.databind.util.StdDateFormat;
55+
import tools.jackson.module.kotlin.KotlinModule;
5556

5657
import org.springframework.aot.hint.RuntimeHints;
5758
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
@@ -269,11 +270,11 @@ void enableMapperFeature() {
269270

270271
@Test
271272
void disableMapperFeature() {
272-
this.contextRunner.withPropertyValues("spring.jackson.mapper.use_annotations:false").run((context) -> {
273+
this.contextRunner.withPropertyValues("spring.jackson.mapper.infer-property-mutators:false").run((context) -> {
273274
JsonMapper mapper = context.getBean(JsonMapper.class);
274-
assertThat(MapperFeature.USE_ANNOTATIONS.enabledByDefault()).isTrue();
275-
assertThat(mapper.deserializationConfig().isEnabled(MapperFeature.USE_ANNOTATIONS)).isFalse();
276-
assertThat(mapper.serializationConfig().isEnabled(MapperFeature.USE_ANNOTATIONS)).isFalse();
275+
assertThat(MapperFeature.INFER_PROPERTY_MUTATORS.enabledByDefault()).isTrue();
276+
assertThat(mapper.deserializationConfig().isEnabled(MapperFeature.INFER_PROPERTY_MUTATORS)).isFalse();
277+
assertThat(mapper.serializationConfig().isEnabled(MapperFeature.INFER_PROPERTY_MUTATORS)).isFalse();
277278
});
278279
}
279280

@@ -591,6 +592,19 @@ void whenUsingJackson2DefaultsShouldBeConfiguredUsingConfigureForJackson2() {
591592
});
592593
}
593594

595+
@Test
596+
void shouldFindAndAddModulesByDefault() {
597+
this.contextRunner.run((context) -> assertThat(context.getBean(JsonMapper.class).getRegisteredModules())
598+
.hasAtLeastOneElementOfType(KotlinModule.class));
599+
}
600+
601+
@Test
602+
void shouldNotFindAndAddModulesWhenDisabled() {
603+
this.contextRunner.withPropertyValues("spring.jackson.find-and-add-modules=false")
604+
.run((context) -> assertThat(context.getBean(JsonMapper.class).getRegisteredModules())
605+
.doesNotHaveAnyElementsOfTypes(KotlinModule.class));
606+
}
607+
594608
static class MyDateFormat extends SimpleDateFormat {
595609

596610
MyDateFormat() {

0 commit comments

Comments
 (0)