diff --git a/release-notes/VERSION b/release-notes/VERSION index 3beb737a74..bda097c6ba 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -6,6 +6,8 @@ Project: jackson-databind 2.9.0 (not yet released) +#219: SqlDateSerializer does not obey SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS + (reported by BrentDouglas@github) #507: Support for default `@JsonView` for a class (suggested by Mark W) #888: Allow specifying custom exclusion comparator via `@JsonInclude`, diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java index 4a840bc49d..73a980e86e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java @@ -80,7 +80,7 @@ protected abstract static class DateBasedDeserializer * Let's also keep format String for reference, to use for error messages */ protected final String _formatString; - + protected DateBasedDeserializer(Class clz) { super(clz); _customFormat = null; @@ -187,7 +187,7 @@ public static class CalendarDeserializer extends DateBasedDeserializer * used for instantiation. */ protected final Class _calendarClass; - + public CalendarDeserializer() { super(Calendar.class); _calendarClass = null; @@ -207,7 +207,7 @@ public CalendarDeserializer(CalendarDeserializer src, DateFormat df, String form protected CalendarDeserializer withDateFormat(DateFormat df, String formatString) { return new CalendarDeserializer(this, df, formatString); } - + @Override public Calendar deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/SqlDateSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/SqlDateSerializer.java index 2857b6f325..90bd3f4aa2 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/SqlDateSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/SqlDateSerializer.java @@ -4,8 +4,8 @@ import java.lang.reflect.Type; import java.text.DateFormat; -import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; + import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; @@ -21,10 +21,8 @@ public class SqlDateSerializer extends DateTimeSerializerBase { public SqlDateSerializer() { - /* 12-Apr-2014, tatu: for now, pass explicit 'false' to mean 'not using timestamp', - * for backwards compatibility; this differs from other Date/Calendar types. - */ - this(Boolean.FALSE); + // 11-Oct-2016, tatu: As per [databind#219] fixed for 2.9; was passing `false` prior + this(null); } protected SqlDateSerializer(Boolean useTimestamp) { @@ -43,11 +41,19 @@ protected long _timestamp(java.sql.Date value) { @Override public void serialize(java.sql.Date value, JsonGenerator gen, SerializerProvider provider) - throws IOException, JsonGenerationException + throws IOException { if (_asTimestamp(provider)) { gen.writeNumber(_timestamp(value)); + } else if (_customFormat != null) { + // 11-Oct-2016, tatu: As per [databind#219], same as with `java.util.Date` + synchronized (_customFormat) { + gen.writeString(_customFormat.format(value)); + } } else { + // 11-Oct-2016, tatu: For backwards-compatibility purposes, we shall just use + // the awful standard JDK serialization via `sqlDate.toString()`... this + // is problematic in multiple ways (including using arbitrary timezone...) gen.writeString(value.toString()); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/DateSerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/DateSerializationTest.java index 682da99624..d368882561 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/DateSerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/DateSerializationTest.java @@ -133,15 +133,29 @@ public void testDateOther() throws IOException public void testSqlDate() throws IOException { // use date 1999-04-01 (note: months are 0-based, use constant) - java.sql.Date date = new java.sql.Date(99, Calendar.APRIL, 1); - assertEquals(quote("1999-04-01"), MAPPER.writeValueAsString(date)); + final java.sql.Date date99 = new java.sql.Date(99, Calendar.APRIL, 1); + final java.sql.Date date0 = new java.sql.Date(0); - java.sql.Date date0 = new java.sql.Date(0L); - assertEquals(aposToQuotes("{'date':'"+date0.toString()+"'}"), + // 11-Oct-2016, tatu: As per [databind#219] we really should use global + // defaults in 2.9, even if this changes behavior. + + assertEquals(String.valueOf(date99.getTime()), + MAPPER.writeValueAsString(date99)); + + assertEquals(aposToQuotes("{'date':0}"), MAPPER.writeValueAsString(new SqlDateAsDefaultBean(0L))); // but may explicitly force timestamp too - assertEquals(aposToQuotes("{'date':0}"), MAPPER.writeValueAsString(new SqlDateAsNumberBean(0L))); + assertEquals(aposToQuotes("{'date':0}"), + MAPPER.writeValueAsString(new SqlDateAsNumberBean(0L))); + + // And also should be able to use String output as need be: + ObjectWriter w = MAPPER.writer().without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + assertEquals(quote("1999-04-01"), w.writeValueAsString(date99)); + assertEquals(quote(date0.toString()), w.writeValueAsString(date0)); + assertEquals(aposToQuotes("{'date':'"+date0.toString()+"'}"), + w.writeValueAsString(new SqlDateAsDefaultBean(0L))); } public void testSqlTime() throws IOException