From 93ae71cf9371c33bfd2e3dc8f9d1d3f8403b3fd1 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 22 Nov 2017 19:43:35 -0800 Subject: [PATCH] Switch Jackson write-dates-as-timestamps default Update `JacksonAutoConfiguration` so that `write-dates-as-timestamps` now defaults to `false`. Fixes gh-11079 --- .../jackson/JacksonAutoConfiguration.java | 30 ++++++++++++++----- .../JacksonAutoConfigurationTests.java | 14 +++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) 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 95116cb58b3..2f4d8c9110b 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 @@ -20,16 +20,18 @@ import java.lang.reflect.Field; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Map.Entry; import java.util.TimeZone; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat; import com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer; @@ -70,12 +72,21 @@ import org.springframework.util.ReflectionUtils; * @author Marcel Overdijk * @author Sebastien Deleuze * @author Johannes Edmeier + * @author Phillip Webb * @since 1.1.0 */ @Configuration @ConditionalOnClass(ObjectMapper.class) public class JacksonAutoConfiguration { + private static final Map FEATURE_DEFAULTS; + + static { + Map featureDefaults = new HashMap<>(); + featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults); + } + @Bean public JsonComponentModule jsonComponentModule() { return new JsonComponentModule(); @@ -228,6 +239,7 @@ public class JacksonAutoConfiguration { if (this.jacksonProperties.getTimeZone() != null) { builder.timeZone(this.jacksonProperties.getTimeZone()); } + configureFeatures(builder, FEATURE_DEFAULTS); configureFeatures(builder, this.jacksonProperties.getDeserialization()); configureFeatures(builder, this.jacksonProperties.getSerialization()); configureFeatures(builder, this.jacksonProperties.getMapper()); @@ -241,14 +253,16 @@ public class JacksonAutoConfiguration { private void configureFeatures(Jackson2ObjectMapperBuilder builder, Map features) { - for (Entry entry : features.entrySet()) { - if (entry.getValue() != null && entry.getValue()) { - builder.featuresToEnable(entry.getKey()); - } - else { - builder.featuresToDisable(entry.getKey()); + features.forEach((feature, value) -> { + if (value != null) { + if (value) { + builder.featuresToEnable(feature); + } + else { + builder.featuresToDisable(feature); + } } - } + }); } private void configureDateFormat(Jackson2ObjectMapperBuilder builder) { 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 a573aaf5c9a..4cb4c757891 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 @@ -22,6 +22,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.Set; +import java.util.TimeZone; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator.Mode; @@ -42,6 +43,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.util.StdDateFormat; +import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; @@ -448,6 +450,18 @@ public class JacksonAutoConfigurationTests { ParameterNamesModuleConfig.class, JacksonAutoConfiguration.class); } + @Test + public void writeDatesAsTimestampsDefault() throws Exception { + this.context.register(JacksonAutoConfiguration.class); + this.context.refresh(); + ObjectMapper mapper = this.context.getBean(ObjectMapper.class); + DateTime dateTime = new DateTime(1988, 6, 25, 20, 30, DateTimeZone.UTC); + String expected = FormatConfig.DEFAULT_DATETIME_PRINTER.rawFormatter() + .withZone(DateTimeZone.forTimeZone(TimeZone.getTimeZone("UTC"))) + .print(dateTime); + assertThat(mapper.writeValueAsString(dateTime)).isEqualTo("\"" + expected + "\""); + } + private void assertParameterNamesModuleCreatorBinding(Mode expectedMode, Class... configClasses) { this.context.register(configClasses);