diff --git a/spring-web/spring-web.gradle b/spring-web/spring-web.gradle index f066790df20c..efc2eb756f76 100644 --- a/spring-web/spring-web.gradle +++ b/spring-web/spring-web.gradle @@ -59,6 +59,7 @@ dependencies { testImplementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8") testImplementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin") + testImplementation("com.fasterxml.jackson.module:jackson-module-parameter-names") testImplementation("org.apache.tomcat:tomcat-util") testImplementation("org.apache.tomcat.embed:tomcat-embed-core") testImplementation("org.eclipse.jetty:jetty-server") diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index 5cae8ff06d13..672c662cf9f5 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -824,6 +824,16 @@ private void registerWellKnownModulesIfAvailable(MultiValueMap m // jackson-datatype-jdk8 not available } + try { + Class parameterNamesModuleClass = (Class) + ClassUtils.forName("com.fasterxml.jackson.module.paramnames.ParameterNamesModule", this.moduleClassLoader); + Module parameterNamesModule = BeanUtils.instantiateClass(parameterNamesModuleClass); + modulesToRegister.set(parameterNamesModule.getTypeId(), parameterNamesModule); + } + catch (ClassNotFoundException ex) { + // jackson-module-parameter-names not available + } + try { Class javaTimeModuleClass = (Class) ClassUtils.forName("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", this.moduleClassLoader); diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java index eb4c321a1edf..2f29de20895b 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java @@ -85,6 +85,7 @@ import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -257,6 +258,25 @@ void modulesToInstallByInstance() { assertThat(serializers.findSerializer(null, SimpleType.construct(Integer.class), null).getClass()).isSameAs(CustomIntegerSerializer.class); } + static class ParameterModuleDto { + + int x; + int y; + + ParameterModuleDto(int x, int y) { + this.x = x; + this.y = y; + } + + int getX() { + return x; + } + + int getY() { + return y; + } + } + @Test void wellKnownModules() throws JsonProcessingException, UnsupportedEncodingException { ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build(); @@ -267,6 +287,9 @@ void wellKnownModules() throws JsonProcessingException, UnsupportedEncodingExcep Optional optional = Optional.of("test"); assertThat(new String(objectMapper.writeValueAsBytes(optional), "UTF-8")).isEqualTo("\"test\""); + + assertThatCode(() -> objectMapper.readValue("{\"x\":1,\"y\":2}", ParameterModuleDto.class)).doesNotThrowAnyException(); + // Kotlin module IntRange range = new IntRange(1, 3); assertThat(new String(objectMapper.writeValueAsBytes(range), "UTF-8")).isEqualTo("{\"start\":1,\"end\":3}");