diff --git a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java index 0b21e161..a42f9c31 100644 --- a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java +++ b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java @@ -47,9 +47,6 @@ final class DefaultTypeAdapters { private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER = new DefaultTimestampDeserializer(); - private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER = - new GregorianCalendarTypeAdapter(); - // The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS // must be defined after the constants for the type adapters. Otherwise, the type adapter // constants will appear as nulls. @@ -68,8 +65,6 @@ final class DefaultTypeAdapters { map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER, true); map.register(Timestamp.class, DATE_TYPE_ADAPTER, true); map.register(Time.class, TIME_TYPE_ADAPTER, true); - map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); - map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); map.makeUnmodifiable(); return map; @@ -82,8 +77,6 @@ final class DefaultTypeAdapters { map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER), true); map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER), true); map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER), true); - map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); - map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); map.makeUnmodifiable(); return map; @@ -253,44 +246,4 @@ final class DefaultTypeAdapters { } } } - - private static final class GregorianCalendarTypeAdapter - implements JsonSerializer, JsonDeserializer { - - private static final String YEAR = "year"; - private static final String MONTH = "month"; - private static final String DAY_OF_MONTH = "dayOfMonth"; - private static final String HOUR_OF_DAY = "hourOfDay"; - private static final String MINUTE = "minute"; - private static final String SECOND = "second"; - - public JsonElement serialize(GregorianCalendar src, Type typeOfSrc, - JsonSerializationContext context) { - JsonObject obj = new JsonObject(); - obj.addProperty(YEAR, src.get(Calendar.YEAR)); - obj.addProperty(MONTH, src.get(Calendar.MONTH)); - obj.addProperty(DAY_OF_MONTH, src.get(Calendar.DAY_OF_MONTH)); - obj.addProperty(HOUR_OF_DAY, src.get(Calendar.HOUR_OF_DAY)); - obj.addProperty(MINUTE, src.get(Calendar.MINUTE)); - obj.addProperty(SECOND, src.get(Calendar.SECOND)); - return obj; - } - - public GregorianCalendar deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) throws JsonParseException { - JsonObject obj = json.getAsJsonObject(); - int year = obj.get(YEAR).getAsInt(); - int month = obj.get(MONTH).getAsInt(); - int dayOfMonth = obj.get(DAY_OF_MONTH).getAsInt(); - int hourOfDay = obj.get(HOUR_OF_DAY).getAsInt(); - int minute = obj.get(MINUTE).getAsInt(); - int second = obj.get(SECOND).getAsInt(); - return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second); - } - - @Override - public String toString() { - return GregorianCalendarTypeAdapter.class.getSimpleName(); - } - } } diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 1962105f..70f65356 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -247,6 +247,7 @@ public final class Gson { .factory(TypeAdapters.LOCALE_FACTORY) .factory(TypeAdapters.INET_ADDRESS_FACTORY) .factory(TypeAdapters.BIT_SET_FACTORY) + .factory(TypeAdapters.CALENDAR_FACTORY) .typeAdapter(BigDecimal.class, new BigDecimalTypeAdapter()) .typeAdapter(BigInteger.class, new BigIntegerTypeAdapter()) .factory(new CollectionTypeAdapterFactory(constructorConstructor)) diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index 40f03c13..a2d6779d 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -22,6 +22,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.BitSet; +import java.util.Calendar; +import java.util.GregorianCalendar; import java.util.Locale; import java.util.StringTokenizer; import java.util.UUID; @@ -405,6 +407,66 @@ public final class TypeAdapters { public static final TypeAdapter.Factory UUID_FACTORY = newFactory(UUID.class, UUID); + public static final TypeAdapter CALENDAR = new TypeAdapter() { + private static final String YEAR = "year"; + private static final String MONTH = "month"; + private static final String DAY_OF_MONTH = "dayOfMonth"; + private static final String HOUR_OF_DAY = "hourOfDay"; + private static final String MINUTE = "minute"; + private static final String SECOND = "second"; + + @Override + public Calendar read(JsonReader reader) throws IOException { + reader.beginObject(); + int year = 0; + int month = 0; + int dayOfMonth = 0; + int hourOfDay = 0; + int minute = 0; + int second = 0; + while (reader.peek() != JsonToken.END_OBJECT) { + String name = reader.nextName(); + int value = reader.nextInt(); + if (YEAR.equals(name)) { + year = value; + } else if (MONTH.equals(name)) { + month = value; + } else if (DAY_OF_MONTH.equals(name)) { + dayOfMonth = value; + } else if (HOUR_OF_DAY.equals(name)) { + hourOfDay = value; + } else if (MINUTE.equals(name)) { + minute = value; + } else if (SECOND.equals(name)) { + second = value; + } + } + reader.endObject(); + return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second); + } + + @Override + public void write(JsonWriter writer, Calendar value) throws IOException { + writer.beginObject(); + writer.name(YEAR); + writer.value(value.get(Calendar.YEAR)); + writer.name(MONTH); + writer.value(value.get(Calendar.MONTH)); + writer.name(DAY_OF_MONTH); + writer.value(value.get(Calendar.DAY_OF_MONTH)); + writer.name(HOUR_OF_DAY); + writer.value(value.get(Calendar.HOUR_OF_DAY)); + writer.name(MINUTE); + writer.value(value.get(Calendar.MINUTE)); + writer.name(SECOND); + writer.value(value.get(Calendar.SECOND)); + writer.endObject(); + } + }; + + public static final TypeAdapter.Factory CALENDAR_FACTORY = + newFactoryForMultipleTypes(Calendar.class, GregorianCalendar.class, CALENDAR); + public static final TypeAdapter LOCALE = new TypeAdapter() { @Override public Locale read(JsonReader reader) throws IOException { @@ -501,6 +563,17 @@ public final class TypeAdapters { }; } + public static TypeAdapter.Factory newFactoryForMultipleTypes( + final Class base, final Class sub, final TypeAdapter typeAdapter) { + return new TypeAdapter.Factory() { + @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal + public TypeAdapter create(MiniGson context, TypeToken typeToken) { + Class rawType = typeToken.getRawType(); + return (rawType == base || rawType == sub) ? (TypeAdapter) typeAdapter : null; + } + }; + } + public static TypeAdapter.Factory newTypeHierarchyFactory( final Class clazz, final TypeAdapter typeAdapter) { return new TypeAdapter.Factory() {