diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 12e44f8f..7b23deac 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -16,6 +16,28 @@ package com.google.gson; +import com.google.gson.internal.ConstructorConstructor; +import com.google.gson.internal.ParameterizedTypeHandlerMap; +import com.google.gson.internal.Primitives; +import com.google.gson.internal.Streams; +import com.google.gson.internal.bind.ArrayTypeAdapter; +import com.google.gson.internal.bind.BigDecimalTypeAdapter; +import com.google.gson.internal.bind.BigIntegerTypeAdapter; +import com.google.gson.internal.bind.CollectionTypeAdapterFactory; +import com.google.gson.internal.bind.DateTypeAdapter; +import com.google.gson.internal.bind.ExcludedTypeAdapterFactory; +import com.google.gson.internal.bind.MapTypeAdapterFactory; +import com.google.gson.internal.bind.MiniGson; +import com.google.gson.internal.bind.ObjectTypeAdapter; +import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory; +import com.google.gson.internal.bind.TimeTypeAdapter; +import com.google.gson.internal.bind.TypeAdapter; +import com.google.gson.internal.bind.TypeAdapters; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.google.gson.stream.MalformedJsonException; import java.io.EOFException; import java.io.IOException; import java.io.Reader; @@ -31,27 +53,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import com.google.gson.internal.ConstructorConstructor; -import com.google.gson.internal.ParameterizedTypeHandlerMap; -import com.google.gson.internal.Primitives; -import com.google.gson.internal.Streams; -import com.google.gson.internal.bind.ArrayTypeAdapter; -import com.google.gson.internal.bind.BigDecimalTypeAdapter; -import com.google.gson.internal.bind.BigIntegerTypeAdapter; -import com.google.gson.internal.bind.CollectionTypeAdapterFactory; -import com.google.gson.internal.bind.ExcludedTypeAdapterFactory; -import com.google.gson.internal.bind.MapTypeAdapterFactory; -import com.google.gson.internal.bind.MiniGson; -import com.google.gson.internal.bind.ObjectTypeAdapter; -import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory; -import com.google.gson.internal.bind.TypeAdapter; -import com.google.gson.internal.bind.TypeAdapters; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.google.gson.stream.MalformedJsonException; - /** * This is the main class for using Gson. Gson is typically used by first constructing a * Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)} @@ -255,9 +256,9 @@ public final class Gson { .factory(TypeAdapters.LOCALE_FACTORY) .factory(TypeAdapters.INET_ADDRESS_FACTORY) .factory(TypeAdapters.BIT_SET_FACTORY) - .factory(TypeAdapters.DATE_FACTORY) + .factory(DateTypeAdapter.FACTORY) .factory(TypeAdapters.CALENDAR_FACTORY) - .factory(TypeAdapters.SQL_TIME_FACTORY) + .factory(TimeTypeAdapter.FACTORY) .factory(TypeAdapters.SQL_DATE_FACTORY) .factory(TypeAdapters.SQL_TIMESTAMP_FACTORY) .factory(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)) diff --git a/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java new file mode 100644 index 00000000..cd97c5af --- /dev/null +++ b/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.gson.internal.bind; + +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + * Adapter for Time. Although this class appears stateless, it is not. + * DateFormat captures its time zone and locale when it is created, which gives + * this class state. DateFormat isn't thread safe either, so this class has + * to synchronize its read and write methods. + */ +public final class DateTypeAdapter extends TypeAdapter { + public static final Factory FACTORY = new Factory() { + @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal + public TypeAdapter create(MiniGson context, TypeToken typeToken) { + return typeToken.getRawType() == Date.class ? (TypeAdapter) new DateTypeAdapter() : null; + } + }; + + private final DateFormat enUsFormat + = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US); + private final DateFormat localFormat + = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT); + private final DateFormat iso8601Format = buildIso8601Format(); + + private static DateFormat buildIso8601Format() { + DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); + iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); + return iso8601Format; + } + + @Override public Date read(JsonReader reader) throws IOException { + return deserializeToDate(reader.nextString()); + } + + private synchronized Date deserializeToDate(String json) { + try { + return localFormat.parse(json); + } catch (ParseException ignored) { + } + try { + return enUsFormat.parse(json); + } catch (ParseException ignored) { + } + try { + return iso8601Format.parse(json); + } catch (ParseException e) { + throw new JsonSyntaxException(json, e); + } + } + + @Override public synchronized void write(JsonWriter writer, Date value) throws IOException { + String dateFormatAsString = enUsFormat.format(value); + writer.value(dateFormatAsString); + } +} diff --git a/gson/src/main/java/com/google/gson/internal/bind/TimeTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/TimeTypeAdapter.java new file mode 100644 index 00000000..e130b9bd --- /dev/null +++ b/gson/src/main/java/com/google/gson/internal/bind/TimeTypeAdapter.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.gson.internal.bind; + +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.sql.Time; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Adapter for Time. Although this class appears stateless, it is not. + * DateFormat captures its time zone and locale when it is created, which gives + * this class state. DateFormat isn't thread safe either, so this class has + * to synchronize its read and write methods. + */ +public final class TimeTypeAdapter extends TypeAdapter