diff --git a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java index eee9a722..9a3802b9 100644 --- a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java +++ b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java @@ -52,7 +52,7 @@ import java.util.TreeSet; final class DefaultTypeAdapters { private static final DefaultDateTypeAdapter DATE_TYPE_ADAPTER = - new DefaultDateTypeAdapter(DateFormat.DEFAULT); + new DefaultDateTypeAdapter(DateFormat.getDateTimeInstance()); @SuppressWarnings("unchecked") private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter(); private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter(); @@ -169,11 +169,19 @@ final class DefaultTypeAdapters { public DefaultDateTypeAdapter(String datePattern) { this.format = new SimpleDateFormat(datePattern); } + + DefaultDateTypeAdapter(DateFormat format) { + this.format = format; + } public DefaultDateTypeAdapter(int style) { this.format = DateFormat.getDateInstance(style); } + public DefaultDateTypeAdapter(int dateStyle, int timeStyle) { + this.format = DateFormat.getDateTimeInstance(dateStyle, timeStyle); + } + public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { String dateFormatAsString = format.format(src); return new JsonPrimitive(dateFormatAsString); diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 8dfcd61a..7559222d 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -117,7 +117,8 @@ public final class Gson { * {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer * to change the default representation, you can do so by registering a type adapter through * {@link GsonBuilder#registerTypeAdapter(Type, Object)}. - *
  • The default Date format is same as {@link java.text.DateFormat#DEFAULT}. You can change + *
  • The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format + * ignores the millisecond portion of the date during serialization. You can change * this by invoking {@link GsonBuilder#setDateFormat(int)} or * {@link GsonBuilder#setDateFormat(String)}.
  • *
  • By default, Gson ignores the {@link com.google.gson.annotations.Expose} annotation. diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index ccf1269b..4414ffaf 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -64,6 +64,7 @@ public final class GsonBuilder { private boolean serializeNulls; private String datePattern; private int dateStyle; + private int timeStyle; /** * Creates a GsonBuilder instance that can be used to build Gson with various configuration @@ -85,6 +86,7 @@ public final class GsonBuilder { deserializers = new ParameterizedTypeHandlerMap>(); serializeNulls = false; dateStyle = DateFormat.DEFAULT; + timeStyle = DateFormat.DEFAULT; } /** @@ -225,6 +227,28 @@ public final class GsonBuilder { return this; } + /** + * Configures Gson to to serialize {@code Date} objects according to the style value provided. + * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last + * invocation will be used to decide the serialization format. + * + *

    Note that this style value should be one of the predefined constants in the + * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more + * information on the valid style constants.

    + * + * @param dateStyle the predefined date style that date objects will be serialized/deserialized + * to/from + * @param timeStyle the predefined style for the time portion of the date objects + * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern + * @since 1.2 + */ + public GsonBuilder setDateFormat(int dateStyle, int timeStyle) { + this.dateStyle = dateStyle; + this.timeStyle = timeStyle; + this.datePattern = null; + return this; + } + /** * Configures Gson for custom serialization or deserialization. This method combines the * registration of an {@link InstanceCreator}, {@link JsonSerializer}, and a @@ -323,7 +347,8 @@ public final class GsonBuilder { ParameterizedTypeHandlerMap> customSerializers = serializers.copyOf(); ParameterizedTypeHandlerMap> customDeserializers = deserializers.copyOf(); - addTypeAdaptersForDate(datePattern, dateStyle, customSerializers, customDeserializers); + addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers, + customDeserializers); customSerializers.registerIfAbsent(DefaultTypeAdapters.DEFAULT_SERIALIZERS); customDeserializers.registerIfAbsent(DefaultTypeAdapters.DEFAULT_DESERIALIZERS); @@ -337,15 +362,15 @@ public final class GsonBuilder { return gson; } - private static void addTypeAdaptersForDate(String datePattern, int dateStyle, + private static void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle, ParameterizedTypeHandlerMap> serializers, ParameterizedTypeHandlerMap> deserializers) { // NOTE: if a date pattern exists, then that style takes priority DefaultDateTypeAdapter dateTypeAdapter = null; if (datePattern != null && !"".equals(datePattern.trim())) { dateTypeAdapter = new DefaultDateTypeAdapter(datePattern); - } else if (dateStyle != DateFormat.DEFAULT) { - dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle); + } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) { + dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle); } if (dateTypeAdapter != null && !serializers.hasAnyHandlerFor(Date.class) diff --git a/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java b/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java index 89eec9ab..3878b8b5 100644 --- a/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java +++ b/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java @@ -187,44 +187,52 @@ public class DefaultTypeAdaptersTest extends TestCase { public void testDefaultDateSerialization() { Date now = new Date(); String json = gson.toJson(now); - assertEquals("\"" + DateFormat.getDateInstance().format(now) + "\"", json); + assertEquals("\"" + DateFormat.getDateTimeInstance().format(now) + "\"", json); } public void testDefaultDateDeserialization() { Date date = new Date(); - assertEquals(date, gson.fromJson(gson.toJson(date), Date.class)); + String json = gson.toJson(date); + Date extracted = gson.fromJson(json, Date.class); + // Using comparison of string forms since the extracted date has lost the millisecond portion. + assertEquals(date.toString(), extracted.toString()); } - + public void testDefaultDateSerializationUsingBuilder() throws Exception { Gson gson = new GsonBuilder().create(); Date now = new Date(); String json = gson.toJson(now); - assertEquals("\"" + DateFormat.getDateInstance().format(now) + "\"", json); + assertEquals("\"" + DateFormat.getDateTimeInstance().format(now) + "\"", json); } public void testDefaultDateDeserializationUsingBuilder() throws Exception { Gson gson = new GsonBuilder().create(); Date now = new Date(); String json = gson.toJson(now); - assertEquals(now, gson.fromJson(json, Date.class)); + Date extracted = gson.fromJson(json, Date.class); + assertEquals(now.toString(), extracted.toString()); } public void testDateSerializationWithPattern() throws Exception { String pattern = "yyyy-MM-dd"; DateFormat formatter = new SimpleDateFormat(pattern); - Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG).setDateFormat(pattern).create(); + Gson gson = new GsonBuilder().setDateFormat(DateFormat.FULL).setDateFormat(pattern).create(); Date now = new Date(); String json = gson.toJson(now); assertEquals("\"" + formatter.format(now) + "\"", json); } + @SuppressWarnings("deprecation") public void testDateDeserializationWithPattern() throws Exception { String pattern = "yyyy-MM-dd"; DateFormat formatter = new SimpleDateFormat(pattern); - Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG).setDateFormat(pattern).create(); + Gson gson = new GsonBuilder().setDateFormat(DateFormat.FULL).setDateFormat(pattern).create(); Date now = new Date(); String json = gson.toJson(now); - assertEquals(now, gson.fromJson(json, Date.class)); + Date extracted = gson.fromJson(json, Date.class); + assertEquals(now.getYear(), extracted.getYear()); + assertEquals(now.getMonth(), extracted.getMonth()); + assertEquals(now.getDay(), extracted.getDay()); } private static class ClassWithBigDecimal {