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 915eb534c9f..a1318c45191 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 @@ -187,6 +187,7 @@ public class JacksonAutoConfiguration { configurePropertyNamingStrategy(builder); configureModules(builder); configureLocale(builder); + configureDefaultLeniency(builder); } private void configureFeatures(Jackson2ObjectMapperBuilder builder, Map features) { @@ -289,6 +290,13 @@ public class JacksonAutoConfiguration { } } + private void configureDefaultLeniency(Jackson2ObjectMapperBuilder builder) { + Boolean defaultLeniency = this.jacksonProperties.getDefaultLeniency(); + if (defaultLeniency != null) { + builder.postConfigurer((objectMapper) -> objectMapper.setDefaultLeniency(defaultLeniency)); + } + } + private static Collection getBeans(ListableBeanFactory beanFactory, Class type) { return BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, type).values(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java index f11baa6f485..fa9e17e9124 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -92,6 +92,11 @@ public class JacksonProperties { */ private JsonInclude.Include defaultPropertyInclusion; + /** + * Global default setting (if any) for leniency. + */ + private Boolean defaultLeniency; + /** * Time zone used when formatting dates. For instance, "America/Los_Angeles" or * "GMT+10". @@ -151,6 +156,14 @@ public class JacksonProperties { this.defaultPropertyInclusion = defaultPropertyInclusion; } + public Boolean getDefaultLeniency() { + return this.defaultLeniency; + } + + public void setDefaultLeniency(Boolean defaultLeniency) { + this.defaultLeniency = defaultLeniency; + } + public TimeZone getTimeZone() { return this.timeZone; } 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 6c770b02988..3d2856d576f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import java.util.Set; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator.Mode; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -40,6 +41,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.util.StdDateFormat; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; @@ -57,6 +59,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; /** @@ -301,6 +304,25 @@ class JacksonAutoConfigurationTests { }); } + @Test + void enableDefaultLeniency() { + this.contextRunner.withPropertyValues("spring.jackson.default-leniency:true").run((context) -> { + ObjectMapper mapper = context.getBean(ObjectMapper.class); + Person person = mapper.readValue("{\"birthDate\": \"2010-12-30\"}", Person.class); + assertThat(person.getBirthDate()).isNotNull(); + }); + } + + @Test + void disableDefaultLeniency() { + this.contextRunner.withPropertyValues("spring.jackson.default-leniency:false").run((context) -> { + ObjectMapper mapper = context.getBean(ObjectMapper.class); + assertThatThrownBy(() -> mapper.readValue("{\"birthDate\": \"2010-12-30\"}", Person.class)) + .isInstanceOf(InvalidFormatException.class).hasMessageContaining("expected format") + .hasMessageContaining("yyyyMMdd"); + }); + } + @Test void additionalJacksonBuilderCustomization() { this.contextRunner.withUserConfiguration(ObjectMapperBuilderCustomConfig.class).run((context) -> { @@ -537,4 +559,19 @@ class JacksonAutoConfigurationTests { } + static class Person { + + @JsonFormat(pattern = "yyyyMMdd") + private Date birthDate; + + Date getBirthDate() { + return this.birthDate; + } + + void setBirthDate(Date birthDate) { + this.birthDate = birthDate; + } + + } + }