diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 27f3ee9246..a7938c84e6 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -49,9 +49,8 @@ import com.google.gson.internal.bind.MapTypeAdapterFactory; import com.google.gson.internal.bind.ObjectTypeAdapter; import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory; -import com.google.gson.internal.bind.SqlDateTypeAdapter; -import com.google.gson.internal.bind.TimeTypeAdapter; import com.google.gson.internal.bind.TypeAdapters; +import com.google.gson.internal.sql.SqlTypesSupport; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; @@ -262,9 +261,13 @@ public Gson() { factories.add(TypeAdapters.BIT_SET_FACTORY); factories.add(DateTypeAdapter.FACTORY); factories.add(TypeAdapters.CALENDAR_FACTORY); - factories.add(TimeTypeAdapter.FACTORY); - factories.add(SqlDateTypeAdapter.FACTORY); - factories.add(TypeAdapters.TIMESTAMP_FACTORY); + + if (SqlTypesSupport.SUPPORTS_SQL_TYPES) { + factories.add(SqlTypesSupport.TIME_FACTORY); + factories.add(SqlTypesSupport.DATE_FACTORY); + factories.add(SqlTypesSupport.TIMESTAMP_FACTORY); + } + factories.add(ArrayTypeAdapter.FACTORY); factories.add(TypeAdapters.CLASS_FACTORY); diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index b97be452be..b2fd74edec 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -17,7 +17,6 @@ package com.google.gson; import java.lang.reflect.Type; -import java.sql.Timestamp; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; @@ -28,8 +27,10 @@ import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.Excluder; +import com.google.gson.internal.bind.DefaultDateTypeAdapter; import com.google.gson.internal.bind.TreeTypeAdapter; import com.google.gson.internal.bind.TypeAdapters; +import com.google.gson.internal.sql.SqlTypesSupport; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; @@ -417,8 +418,8 @@ public GsonBuilder disableHtmlEscaping() { * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation * will be used to decide the serialization format. * - *

The date format will be used to serialize and deserialize {@link java.util.Date}, {@link - * java.sql.Timestamp} and {@link java.sql.Date}. + *

The date format will be used to serialize and deserialize {@link java.util.Date} and in case + * the {@code java.sql} module is present, also {@link java.sql.Timestamp} and {@link java.sql.Date}. * *

Note that this pattern must abide by the convention provided by {@code SimpleDateFormat} * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on @@ -602,26 +603,35 @@ public Gson create() { this.factories, this.hierarchyFactories, factories); } - @SuppressWarnings("unchecked") private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle, List factories) { - DefaultDateTypeAdapter dateTypeAdapter; - TypeAdapter timestampTypeAdapter; - TypeAdapter javaSqlDateTypeAdapter; - if (datePattern != null && !"".equals(datePattern.trim())) { - dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, datePattern); - timestampTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(Timestamp.class, datePattern); - javaSqlDateTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(java.sql.Date.class, datePattern); + TypeAdapterFactory dateAdapterFactory; + boolean sqlTypesSupported = SqlTypesSupport.SUPPORTS_SQL_TYPES; + TypeAdapterFactory sqlTimestampAdapterFactory = null; + TypeAdapterFactory sqlDateAdapterFactory = null; + + if (datePattern != null && !datePattern.trim().isEmpty()) { + dateAdapterFactory = DefaultDateTypeAdapter.DateType.DATE.createAdapterFactory(datePattern); + + if (sqlTypesSupported) { + sqlTimestampAdapterFactory = SqlTypesSupport.TIMESTAMP_DATE_TYPE.createAdapterFactory(datePattern); + sqlDateAdapterFactory = SqlTypesSupport.DATE_DATE_TYPE.createAdapterFactory(datePattern); + } } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) { - dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, dateStyle, timeStyle); - timestampTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(Timestamp.class, dateStyle, timeStyle); - javaSqlDateTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(java.sql.Date.class, dateStyle, timeStyle); + dateAdapterFactory = DefaultDateTypeAdapter.DateType.DATE.createAdapterFactory(dateStyle, timeStyle); + + if (sqlTypesSupported) { + sqlTimestampAdapterFactory = SqlTypesSupport.TIMESTAMP_DATE_TYPE.createAdapterFactory(dateStyle, timeStyle); + sqlDateAdapterFactory = SqlTypesSupport.DATE_DATE_TYPE.createAdapterFactory(dateStyle, timeStyle); + } } else { return; } - factories.add(TypeAdapters.newFactory(Date.class, dateTypeAdapter)); - factories.add(TypeAdapters.newFactory(Timestamp.class, timestampTypeAdapter)); - factories.add(TypeAdapters.newFactory(java.sql.Date.class, javaSqlDateTypeAdapter)); + factories.add(dateAdapterFactory); + if (sqlTypesSupported) { + factories.add(sqlTimestampAdapterFactory); + factories.add(sqlDateAdapterFactory); + } } } diff --git a/gson/src/main/java/com/google/gson/internal/$Gson$Types.java b/gson/src/main/java/com/google/gson/internal/$Gson$Types.java index a708dc055b..617a644b1f 100644 --- a/gson/src/main/java/com/google/gson/internal/$Gson$Types.java +++ b/gson/src/main/java/com/google/gson/internal/$Gson$Types.java @@ -339,6 +339,7 @@ public static Type[] getMapKeyAndValueTypes(Type context, Class contextRawTyp } public static Type resolve(Type context, Class contextRawType, Type toResolve) { + return resolve(context, contextRawType, toResolve, new HashMap, Type>()); } diff --git a/gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/DefaultDateTypeAdapter.java similarity index 60% rename from gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java rename to gson/src/main/java/com/google/gson/internal/bind/DefaultDateTypeAdapter.java index 522963795a..f56faee0f9 100644 --- a/gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/bind/DefaultDateTypeAdapter.java @@ -14,10 +14,9 @@ * limitations under the License. */ -package com.google.gson; +package com.google.gson.internal.bind; import java.io.IOException; -import java.sql.Timestamp; import java.text.DateFormat; import java.text.ParseException; import java.text.ParsePosition; @@ -27,6 +26,10 @@ import java.util.List; import java.util.Locale; +import com.google.gson.JsonSyntaxException; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.JavaVersion; import com.google.gson.internal.PreJava9DateFormatProvider; import com.google.gson.internal.bind.util.ISO8601Utils; @@ -35,17 +38,53 @@ import com.google.gson.stream.JsonWriter; /** - * This type adapter supports three subclasses of date: Date, Timestamp, and - * java.sql.Date. + * This type adapter supports subclasses of date by defining a + * {@link DefaultDateTypeAdapter.DateType} and then using its {@code createAdapterFactory} + * methods. * * @author Inderjeet Singh * @author Joel Leitch */ -final class DefaultDateTypeAdapter extends TypeAdapter { - +public final class DefaultDateTypeAdapter extends TypeAdapter { private static final String SIMPLE_NAME = "DefaultDateTypeAdapter"; - private final Class dateType; + public static abstract class DateType { + public static final DateType DATE = new DateType(Date.class) { + @Override protected Date deserialize(Date date) { + return date; + } + }; + + private final Class dateClass; + + protected DateType(Class dateClass) { + this.dateClass = dateClass; + } + + protected abstract T deserialize(Date date); + + private final TypeAdapterFactory createFactory(DefaultDateTypeAdapter adapter) { + return TypeAdapters.newFactory(dateClass, adapter); + } + + public final TypeAdapterFactory createAdapterFactory(String datePattern) { + return createFactory(new DefaultDateTypeAdapter(this, datePattern)); + } + + public final TypeAdapterFactory createAdapterFactory(int style) { + return createFactory(new DefaultDateTypeAdapter(this, style)); + } + + public final TypeAdapterFactory createAdapterFactory(int dateStyle, int timeStyle) { + return createFactory(new DefaultDateTypeAdapter(this, dateStyle, timeStyle)); + } + + public final TypeAdapterFactory createDefaultsAdapterFactory() { + return createFactory(new DefaultDateTypeAdapter(this, DateFormat.DEFAULT, DateFormat.DEFAULT)); + } + } + + private final DateType dateType; /** * List of 1 or more different date formats used for de-serialization attempts. @@ -53,27 +92,16 @@ final class DefaultDateTypeAdapter extends TypeAdapter { */ private final List dateFormats = new ArrayList(); - DefaultDateTypeAdapter(Class dateType) { - this.dateType = verifyDateType(dateType); - dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US)); - if (!Locale.getDefault().equals(Locale.US)) { - dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)); - } - if (JavaVersion.isJava9OrLater()) { - dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT)); - } - } - - DefaultDateTypeAdapter(Class dateType, String datePattern) { - this.dateType = verifyDateType(dateType); + private DefaultDateTypeAdapter(DateType dateType, String datePattern) { + this.dateType = $Gson$Preconditions.checkNotNull(dateType); dateFormats.add(new SimpleDateFormat(datePattern, Locale.US)); if (!Locale.getDefault().equals(Locale.US)) { dateFormats.add(new SimpleDateFormat(datePattern)); } } - DefaultDateTypeAdapter(Class dateType, int style) { - this.dateType = verifyDateType(dateType); + private DefaultDateTypeAdapter(DateType dateType, int style) { + this.dateType = $Gson$Preconditions.checkNotNull(dateType); dateFormats.add(DateFormat.getDateInstance(style, Locale.US)); if (!Locale.getDefault().equals(Locale.US)) { dateFormats.add(DateFormat.getDateInstance(style)); @@ -83,12 +111,8 @@ final class DefaultDateTypeAdapter extends TypeAdapter { } } - public DefaultDateTypeAdapter(int dateStyle, int timeStyle) { - this(Date.class, dateStyle, timeStyle); - } - - public DefaultDateTypeAdapter(Class dateType, int dateStyle, int timeStyle) { - this.dateType = verifyDateType(dateType); + private DefaultDateTypeAdapter(DateType dateType, int dateStyle, int timeStyle) { + this.dateType = $Gson$Preconditions.checkNotNull(dateType); dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US)); if (!Locale.getDefault().equals(Locale.US)) { dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle)); @@ -98,13 +122,6 @@ public DefaultDateTypeAdapter(Class dateType, int dateStyle, int } } - private static Class verifyDateType(Class dateType) { - if ( dateType != Date.class && dateType != java.sql.Date.class && dateType != Timestamp.class ) { - throw new IllegalArgumentException("Date type must be one of " + Date.class + ", " + Timestamp.class + ", or " + java.sql.Date.class + " but was " + dateType); - } - return dateType; - } - // These methods need to be synchronized since JDK DateFormat classes are not thread-safe // See issue 162 @Override @@ -120,22 +137,13 @@ public void write(JsonWriter out, Date value) throws IOException { } @Override - public Date read(JsonReader in) throws IOException { + public T read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } Date date = deserializeToDate(in.nextString()); - if (dateType == Date.class) { - return date; - } else if (dateType == Timestamp.class) { - return new Timestamp(date.getTime()); - } else if (dateType == java.sql.Date.class) { - return new java.sql.Date(date.getTime()); - } else { - // This must never happen: dateType is guarded in the primary constructor - throw new AssertionError(); - } + return dateType.deserialize(date); } private Date deserializeToDate(String s) { @@ -145,11 +153,12 @@ private Date deserializeToDate(String s) { return dateFormat.parse(s); } catch (ParseException ignored) {} } - try { - return ISO8601Utils.parse(s, new ParsePosition(0)); - } catch (ParseException e) { - throw new JsonSyntaxException(s, e); - } + } + + try { + return ISO8601Utils.parse(s, new ParsePosition(0)); + } catch (ParseException e) { + throw new JsonSyntaxException(s, e); } } 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 04b13ada81..6bbd680ab4 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 @@ -26,12 +26,10 @@ import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; -import java.sql.Timestamp; import java.util.ArrayList; import java.util.BitSet; import java.util.Calendar; import java.util.Currency; -import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; @@ -409,7 +407,7 @@ public void write(JsonWriter out, String value) throws IOException { out.value(value); } }; - + public static final TypeAdapter BIG_DECIMAL = new TypeAdapter() { @Override public BigDecimal read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { @@ -427,7 +425,7 @@ public void write(JsonWriter out, String value) throws IOException { out.value(value); } }; - + public static final TypeAdapter BIG_INTEGER = new TypeAdapter() { @Override public BigInteger read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { @@ -572,27 +570,6 @@ public void write(JsonWriter out, Currency value) throws IOException { }.nullSafe(); public static final TypeAdapterFactory CURRENCY_FACTORY = newFactory(Currency.class, CURRENCY); - public static final TypeAdapterFactory TIMESTAMP_FACTORY = new TypeAdapterFactory() { - @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal - @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { - if (typeToken.getRawType() != Timestamp.class) { - return null; - } - - final TypeAdapter dateTypeAdapter = gson.getAdapter(Date.class); - return (TypeAdapter) new TypeAdapter() { - @Override public Timestamp read(JsonReader in) throws IOException { - Date date = dateTypeAdapter.read(in); - return date != null ? new Timestamp(date.getTime()) : null; - } - - @Override public void write(JsonWriter out, Timestamp value) throws IOException { - dateTypeAdapter.write(out, value); - } - }; - } - }; - public static final TypeAdapter CALENDAR = new TypeAdapter() { private static final String YEAR = "year"; private static final String MONTH = "month"; diff --git a/gson/src/main/java/com/google/gson/internal/bind/SqlDateTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/sql/SqlDateTypeAdapter.java similarity index 91% rename from gson/src/main/java/com/google/gson/internal/bind/SqlDateTypeAdapter.java rename to gson/src/main/java/com/google/gson/internal/sql/SqlDateTypeAdapter.java index 5ec244f29e..b3da1fefd4 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/SqlDateTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/sql/SqlDateTypeAdapter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.google.gson.internal.bind; +package com.google.gson.internal.sql; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; @@ -35,8 +35,8 @@ * this class state. DateFormat isn't thread safe either, so this class has * to synchronize its read and write methods. */ -public final class SqlDateTypeAdapter extends TypeAdapter { - public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { +final class SqlDateTypeAdapter extends TypeAdapter { + static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { return typeToken.getRawType() == java.sql.Date.class @@ -46,6 +46,9 @@ public final class SqlDateTypeAdapter extends TypeAdapter { private final DateFormat format = new SimpleDateFormat("MMM d, yyyy"); + private SqlDateTypeAdapter() { + } + @Override public synchronized java.sql.Date read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { diff --git a/gson/src/main/java/com/google/gson/internal/bind/TimeTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/sql/SqlTimeTypeAdapter.java similarity index 86% rename from gson/src/main/java/com/google/gson/internal/bind/TimeTypeAdapter.java rename to gson/src/main/java/com/google/gson/internal/sql/SqlTimeTypeAdapter.java index 55d4b2f693..ee65726b4e 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TimeTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/sql/SqlTimeTypeAdapter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.google.gson.internal.bind; +package com.google.gson.internal.sql; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; @@ -32,21 +32,24 @@ import java.util.Date; /** - * Adapter for Time. Although this class appears stateless, it is not. + * Adapter for java.sql.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

If {@link #SUPPORTS_SQL_TYPES} is {@code true}, all other + * constants of this class will be non-{@code null}. However, if + * it is {@code false} all other constants will be {@code null} and + * there will be no support for {@code java.sql} types. + */ +public final class SqlTypesSupport { + /** + * {@code true} if {@code java.sql} types are supported, + * {@code false} otherwise + */ + public static final boolean SUPPORTS_SQL_TYPES; + + public static final DateType DATE_DATE_TYPE; + public static final DateType TIMESTAMP_DATE_TYPE; + + public static final TypeAdapterFactory DATE_FACTORY; + public static final TypeAdapterFactory TIME_FACTORY; + public static final TypeAdapterFactory TIMESTAMP_FACTORY; + + static { + boolean sqlTypesSupport; + try { + Class.forName("java.sql.Date"); + sqlTypesSupport = true; + } catch (ClassNotFoundException classNotFoundException) { + sqlTypesSupport = false; + } + SUPPORTS_SQL_TYPES = sqlTypesSupport; + + if (SUPPORTS_SQL_TYPES) { + DATE_DATE_TYPE = new DateType(java.sql.Date.class) { + @Override protected java.sql.Date deserialize(Date date) { + return new java.sql.Date(date.getTime()); + } + }; + TIMESTAMP_DATE_TYPE = new DateType(Timestamp.class) { + @Override protected Timestamp deserialize(Date date) { + return new Timestamp(date.getTime()); + } + }; + + DATE_FACTORY = SqlDateTypeAdapter.FACTORY; + TIME_FACTORY = SqlTimeTypeAdapter.FACTORY; + TIMESTAMP_FACTORY = SqlTimestampTypeAdapter.FACTORY; + } else { + DATE_DATE_TYPE = null; + TIMESTAMP_DATE_TYPE = null; + + DATE_FACTORY = null; + TIME_FACTORY = null; + TIMESTAMP_FACTORY = null; + } + } + + private SqlTypesSupport() { + } +} diff --git a/gson/src/main/java/module-info.java b/gson/src/main/java/module-info.java index 161fbdba7f..38c26e569c 100644 --- a/gson/src/main/java/module-info.java +++ b/gson/src/main/java/module-info.java @@ -8,5 +8,6 @@ exports com.google.gson.reflect; exports com.google.gson.stream; - requires transitive java.sql; + // Optional dependency on java.sql + requires static java.sql; } diff --git a/gson/src/test/java/com/google/gson/functional/CollectionTest.java b/gson/src/test/java/com/google/gson/functional/CollectionTest.java index 8aa36e21ea..261c5d02d3 100644 --- a/gson/src/test/java/com/google/gson/functional/CollectionTest.java +++ b/gson/src/test/java/com/google/gson/functional/CollectionTest.java @@ -37,7 +37,6 @@ import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import com.google.gson.common.MoreAsserts; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.reflect.TypeToken; 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 b7307c6fce..0dae4ede22 100644 --- a/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java +++ b/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java @@ -69,12 +69,14 @@ public class DefaultTypeAdaptersTest extends TestCase { private Gson gson; private TimeZone oldTimeZone; + private Locale oldLocale; @Override protected void setUp() throws Exception { super.setUp(); this.oldTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); + this.oldLocale = Locale.getDefault(); Locale.setDefault(Locale.US); gson = new Gson(); } @@ -82,6 +84,7 @@ protected void setUp() throws Exception { @Override protected void tearDown() throws Exception { TimeZone.setDefault(oldTimeZone); + Locale.setDefault(oldLocale); super.tearDown(); } @@ -146,7 +149,7 @@ public void testUriDeserialization() { URI target = gson.fromJson(json, URI.class); assertEquals(uriValue, target.toASCIIString()); } - + public void testNullSerialization() throws Exception { testNullSerializationAndDeserialization(Boolean.class); testNullSerializationAndDeserialization(Byte.class); @@ -175,14 +178,15 @@ public void testNullSerialization() throws Exception { testNullSerializationAndDeserialization(Date.class); testNullSerializationAndDeserialization(GregorianCalendar.class); testNullSerializationAndDeserialization(Calendar.class); - testNullSerializationAndDeserialization(Time.class); - testNullSerializationAndDeserialization(Timestamp.class); - testNullSerializationAndDeserialization(java.sql.Date.class); testNullSerializationAndDeserialization(Enum.class); testNullSerializationAndDeserialization(Class.class); } private void testNullSerializationAndDeserialization(Class c) { + testNullSerializationAndDeserialization(gson, c); + } + + public static void testNullSerializationAndDeserialization(Gson gson, Class c) { assertEquals("null", gson.toJson(null, c)); assertEquals(null, gson.fromJson("null", c)); } @@ -269,7 +273,7 @@ public void testBigIntegerFieldDeserialization() { ClassWithBigInteger actual = gson.fromJson(json, ClassWithBigInteger.class); assertEquals(expected.value, actual.value); } - + public void testOverrideBigIntegerTypeAdapter() throws Exception { gson = new GsonBuilder() .registerTypeAdapter(BigInteger.class, new NumberAsStringAdapter(BigInteger.class)) @@ -347,60 +351,19 @@ public void testDefaultDateDeserialization() { // Date can not directly be compared with another instance since the deserialization loses the // millisecond portion. @SuppressWarnings("deprecation") - private void assertEqualsDate(Date date, int year, int month, int day) { + public static void assertEqualsDate(Date date, int year, int month, int day) { assertEquals(year-1900, date.getYear()); assertEquals(month, date.getMonth()); assertEquals(day, date.getDate()); } @SuppressWarnings("deprecation") - private void assertEqualsTime(Date date, int hours, int minutes, int seconds) { + public static void assertEqualsTime(Date date, int hours, int minutes, int seconds) { assertEquals(hours, date.getHours()); assertEquals(minutes, date.getMinutes()); assertEquals(seconds, date.getSeconds()); } - public void testDefaultJavaSqlDateSerialization() { - java.sql.Date instant = new java.sql.Date(1259875082000L); - String json = gson.toJson(instant); - assertEquals("\"Dec 3, 2009\"", json); - } - - public void testDefaultJavaSqlDateDeserialization() { - String json = "'Dec 3, 2009'"; - java.sql.Date extracted = gson.fromJson(json, java.sql.Date.class); - assertEqualsDate(extracted, 2009, 11, 3); - } - - public void testDefaultJavaSqlTimestampSerialization() { - Timestamp now = new java.sql.Timestamp(1259875082000L); - String json = gson.toJson(now); - if (JavaVersion.isJava9OrLater()) { - assertEquals("\"Dec 3, 2009, 1:18:02 PM\"", json); - } else { - assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json); - } - } - - public void testDefaultJavaSqlTimestampDeserialization() { - String json = "'Dec 3, 2009 1:18:02 PM'"; - Timestamp extracted = gson.fromJson(json, Timestamp.class); - assertEqualsDate(extracted, 2009, 11, 3); - assertEqualsTime(extracted, 13, 18, 2); - } - - public void testDefaultJavaSqlTimeSerialization() { - Time now = new Time(1259875082000L); - String json = gson.toJson(now); - assertEquals("\"01:18:02 PM\"", json); - } - - public void testDefaultJavaSqlTimeDeserialization() { - String json = "'1:18:02 PM'"; - Time extracted = gson.fromJson(json, Time.class); - assertEqualsTime(extracted, 13, 18, 2); - } - public void testDefaultDateSerializationUsingBuilder() throws Exception { Gson gson = new GsonBuilder().create(); Date now = new Date(1315806903103L); @@ -524,42 +487,6 @@ public void testDateSerializationInCollection() throws Exception { } } - // http://code.google.com/p/google-gson/issues/detail?id=230 - public void testTimestampSerialization() throws Exception { - TimeZone defaultTimeZone = TimeZone.getDefault(); - TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - Locale defaultLocale = Locale.getDefault(); - Locale.setDefault(Locale.US); - try { - Timestamp timestamp = new Timestamp(0L); - Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); - String json = gson.toJson(timestamp, Timestamp.class); - assertEquals("\"1970-01-01\"", json); - assertEquals(0, gson.fromJson("\"1970-01-01\"", Timestamp.class).getTime()); - } finally { - TimeZone.setDefault(defaultTimeZone); - Locale.setDefault(defaultLocale); - } - } - - // http://code.google.com/p/google-gson/issues/detail?id=230 - public void testSqlDateSerialization() throws Exception { - TimeZone defaultTimeZone = TimeZone.getDefault(); - TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - Locale defaultLocale = Locale.getDefault(); - Locale.setDefault(Locale.US); - try { - java.sql.Date sqlDate = new java.sql.Date(0L); - Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); - String json = gson.toJson(sqlDate, Timestamp.class); - assertEquals("\"1970-01-01\"", json); - assertEquals(0, gson.fromJson("\"1970-01-01\"", java.sql.Date.class).getTime()); - } finally { - TimeZone.setDefault(defaultTimeZone); - Locale.setDefault(defaultLocale); - } - } - public void testJsonPrimitiveSerialization() { assertEquals("5", gson.toJson(new JsonPrimitive(5), JsonElement.class)); assertEquals("true", gson.toJson(new JsonPrimitive(true), JsonElement.class)); diff --git a/gson/src/test/java/com/google/gson/functional/TreeTypeAdaptersTest.java b/gson/src/test/java/com/google/gson/functional/TreeTypeAdaptersTest.java index ad737ec510..dd412ea131 100644 --- a/gson/src/test/java/com/google/gson/functional/TreeTypeAdaptersTest.java +++ b/gson/src/test/java/com/google/gson/functional/TreeTypeAdaptersTest.java @@ -172,6 +172,7 @@ private static class HistoryCourse { int numClasses; } + @SafeVarargs private static List createList(T ...items) { return Arrays.asList(items); } diff --git a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java b/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java index 2aeeeb7646..df595b796b 100644 --- a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java +++ b/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java @@ -280,6 +280,7 @@ private String toString(Node root) { } } + @SafeVarargs private void assertIterationOrder(Iterable actual, T... expected) { ArrayList actualList = new ArrayList(); for (T t : actual) { diff --git a/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java b/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java index 580d25a571..058de3367f 100644 --- a/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java +++ b/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java @@ -140,6 +140,7 @@ public void testEqualsAndHashCode() throws Exception { MoreAsserts.assertEqualsAndHashCode(map1, map2); } + @SafeVarargs private void assertIterationOrder(Iterable actual, T... expected) { ArrayList actualList = new ArrayList(); for (T t : actual) { diff --git a/gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java b/gson/src/test/java/com/google/gson/internal/bind/DefaultDateTypeAdapterTest.java similarity index 60% rename from gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java rename to gson/src/test/java/com/google/gson/internal/bind/DefaultDateTypeAdapterTest.java index 632a482d8c..2fdc64aeda 100644 --- a/gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java +++ b/gson/src/test/java/com/google/gson/internal/bind/DefaultDateTypeAdapterTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.google.gson; +package com.google.gson.internal.bind; import java.io.IOException; import java.text.DateFormat; @@ -23,7 +23,13 @@ import java.util.Locale; import java.util.TimeZone; +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; import com.google.gson.internal.JavaVersion; +import com.google.gson.internal.bind.DefaultDateTypeAdapter; +import com.google.gson.internal.bind.DefaultDateTypeAdapter.DateType; +import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; @@ -52,18 +58,18 @@ private void assertFormattingAlwaysEmitsUsLocale(Locale locale) { String afterYearLongSep = JavaVersion.isJava9OrLater() ? " at " : " "; String utcFull = JavaVersion.isJava9OrLater() ? "Coordinated Universal Time" : "UTC"; assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep), - new DefaultDateTypeAdapter(Date.class)); - assertFormatted("1/1/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT)); - assertFormatted("Jan 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM)); - assertFormatted("January 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG)); + DateType.DATE.createDefaultsAdapterFactory()); + assertFormatted("1/1/70", DateType.DATE.createAdapterFactory(DateFormat.SHORT)); + assertFormatted("Jan 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.MEDIUM)); + assertFormatted("January 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.LONG)); assertFormatted(String.format("1/1/70%s12:00 AM", afterYearSep), - new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT)); + DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT)); assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep), - new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); + DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertFormatted(String.format("January 1, 1970%s12:00:00 AM UTC", afterYearLongSep), - new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG)); + DateType.DATE.createAdapterFactory(DateFormat.LONG, DateFormat.LONG)); assertFormatted(String.format("Thursday, January 1, 1970%s12:00:00 AM %s", afterYearLongSep, utcFull), - new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL)); + DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -78,21 +84,21 @@ public void testParsingDatesFormattedWithSystemLocale() throws Exception { try { String afterYearSep = JavaVersion.isJava9OrLater() ? " à " : " "; assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep), - new DefaultDateTypeAdapter(Date.class)); - assertParsed("01/01/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT)); - assertParsed("1 janv. 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM)); - assertParsed("1 janvier 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG)); + DateType.DATE.createDefaultsAdapterFactory()); + assertParsed("01/01/70", DateType.DATE.createAdapterFactory(DateFormat.SHORT)); + assertParsed("1 janv. 1970", DateType.DATE.createAdapterFactory(DateFormat.MEDIUM)); + assertParsed("1 janvier 1970", DateType.DATE.createAdapterFactory(DateFormat.LONG)); assertParsed("01/01/70 00:00", - new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT)); + DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT)); assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep), - new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); + DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertParsed(String.format("1 janvier 1970%s00:00:00 UTC", afterYearSep), - new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG)); + DateType.DATE.createAdapterFactory(DateFormat.LONG, DateFormat.LONG)); assertParsed(JavaVersion.isJava9OrLater() ? (JavaVersion.getMajorJavaVersion() <11 ? "jeudi 1 janvier 1970 à 00:00:00 Coordinated Universal Time" : "jeudi 1 janvier 1970 à 00:00:00 Temps universel coordonné") : "jeudi 1 janvier 1970 00 h 00 UTC", - new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL)); + DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -105,18 +111,18 @@ public void testParsingDatesFormattedWithUsLocale() throws Exception { Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { - assertParsed("Jan 1, 1970 0:00:00 AM", new DefaultDateTypeAdapter(Date.class)); - assertParsed("1/1/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT)); - assertParsed("Jan 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM)); - assertParsed("January 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG)); + assertParsed("Jan 1, 1970 0:00:00 AM", DateType.DATE.createDefaultsAdapterFactory()); + assertParsed("1/1/70", DateType.DATE.createAdapterFactory(DateFormat.SHORT)); + assertParsed("Jan 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.MEDIUM)); + assertParsed("January 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.LONG)); assertParsed("1/1/70 0:00 AM", - new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT)); + DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT)); assertParsed("Jan 1, 1970 0:00:00 AM", - new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); + DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertParsed("January 1, 1970 0:00:00 AM UTC", - new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG)); + DateType.DATE.createAdapterFactory(DateFormat.LONG, DateFormat.LONG)); assertParsed("Thursday, January 1, 1970 0:00:00 AM UTC", - new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL)); + DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -131,8 +137,8 @@ public void testFormatUsesDefaultTimezone() throws Exception { try { String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " "; assertFormatted(String.format("Dec 31, 1969%s4:00:00 PM", afterYearSep), - new DefaultDateTypeAdapter(Date.class)); - assertParsed("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter(Date.class)); + DateType.DATE.createDefaultsAdapterFactory()); + assertParsed("Dec 31, 1969 4:00:00 PM", DateType.DATE.createDefaultsAdapterFactory()); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -140,17 +146,17 @@ public void testFormatUsesDefaultTimezone() throws Exception { } public void testDateDeserializationISO8601() throws Exception { - DefaultDateTypeAdapter adapter = new DefaultDateTypeAdapter(Date.class); - assertParsed("1970-01-01T00:00:00.000Z", adapter); - assertParsed("1970-01-01T00:00Z", adapter); - assertParsed("1970-01-01T00:00:00+00:00", adapter); - assertParsed("1970-01-01T01:00:00+01:00", adapter); - assertParsed("1970-01-01T01:00:00+01", adapter); - } - + TypeAdapterFactory adapterFactory = DateType.DATE.createDefaultsAdapterFactory(); + assertParsed("1970-01-01T00:00:00.000Z", adapterFactory); + assertParsed("1970-01-01T00:00Z", adapterFactory); + assertParsed("1970-01-01T00:00:00+00:00", adapterFactory); + assertParsed("1970-01-01T01:00:00+01:00", adapterFactory); + assertParsed("1970-01-01T01:00:00+01", adapterFactory); + } + public void testDateSerialization() throws Exception { int dateStyle = DateFormat.LONG; - DefaultDateTypeAdapter dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, dateStyle); + TypeAdapter dateTypeAdapter = dateAdapter(DateType.DATE.createAdapterFactory(dateStyle)); DateFormat formatter = DateFormat.getDateInstance(dateStyle, Locale.US); Date currentDate = new Date(); @@ -160,7 +166,7 @@ public void testDateSerialization() throws Exception { public void testDatePattern() throws Exception { String pattern = "yyyy-MM-dd"; - DefaultDateTypeAdapter dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, pattern); + TypeAdapter dateTypeAdapter = dateAdapter(DateType.DATE.createAdapterFactory(pattern)); DateFormat formatter = new SimpleDateFormat(pattern); Date currentDate = new Date(); @@ -168,33 +174,40 @@ public void testDatePattern() throws Exception { assertEquals(toLiteral(formatter.format(currentDate)), dateString); } - @SuppressWarnings("unused") public void testInvalidDatePattern() throws Exception { try { - new DefaultDateTypeAdapter(Date.class, "I am a bad Date pattern...."); + DateType.DATE.createAdapterFactory("I am a bad Date pattern...."); fail("Invalid date pattern should fail."); } catch (IllegalArgumentException expected) { } } public void testNullValue() throws Exception { - DefaultDateTypeAdapter adapter = new DefaultDateTypeAdapter(Date.class); + TypeAdapter adapter = dateAdapter(DateType.DATE.createDefaultsAdapterFactory()); assertNull(adapter.fromJson("null")); assertEquals("null", adapter.toJson(null)); } public void testUnexpectedToken() throws Exception { try { - DefaultDateTypeAdapter adapter = new DefaultDateTypeAdapter(Date.class); + TypeAdapter adapter = dateAdapter(DateType.DATE.createDefaultsAdapterFactory()); adapter.fromJson("{}"); fail("Unexpected token should fail."); } catch (IllegalStateException expected) { } } - private void assertFormatted(String formatted, DefaultDateTypeAdapter adapter) { + private static TypeAdapter dateAdapter(TypeAdapterFactory adapterFactory) { + TypeAdapter adapter = adapterFactory.create(new Gson(), TypeToken.get(Date.class)); + assertNotNull(adapter); + return adapter; + } + + private static void assertFormatted(String formatted, TypeAdapterFactory adapterFactory) { + TypeAdapter adapter = dateAdapter(adapterFactory); assertEquals(toLiteral(formatted), adapter.toJson(new Date(0))); } - private void assertParsed(String date, DefaultDateTypeAdapter adapter) throws IOException { + private static void assertParsed(String date, TypeAdapterFactory adapterFactory) throws IOException { + TypeAdapter adapter = dateAdapter(adapterFactory); assertEquals(date, new Date(0), adapter.fromJson(toLiteral(date))); assertEquals("ISO 8601", new Date(0), adapter.fromJson(toLiteral("1970-01-01T00:00:00Z"))); } diff --git a/gson/src/test/java/com/google/gson/internal/bind/RecursiveTypesResolveTest.java b/gson/src/test/java/com/google/gson/internal/bind/RecursiveTypesResolveTest.java index 730183fbee..a2260c373f 100644 --- a/gson/src/test/java/com/google/gson/internal/bind/RecursiveTypesResolveTest.java +++ b/gson/src/test/java/com/google/gson/internal/bind/RecursiveTypesResolveTest.java @@ -36,7 +36,7 @@ public class RecursiveTypesResolveTest extends TestCase { @SuppressWarnings("unused") private static class Foo1 { - public Foo2 foo2; + public Foo2 foo2; } @SuppressWarnings("unused") private static class Foo2 { @@ -48,6 +48,7 @@ private static class Foo2 { */ public void testRecursiveResolveSimple() { + @SuppressWarnings("rawtypes") TypeAdapter adapter = new Gson().getAdapter(Foo1.class); assertNotNull(adapter); } @@ -62,6 +63,7 @@ public void testIssue603PrintStream() { } public void testIssue440WeakReference() throws Exception { + @SuppressWarnings("rawtypes") TypeAdapter adapter = new Gson().getAdapter(WeakReference.class); assertNotNull(adapter); } @@ -105,11 +107,13 @@ private static class TestType2 { } public void testRecursiveTypeVariablesResolve1() throws Exception { + @SuppressWarnings("rawtypes") TypeAdapter adapter = new Gson().getAdapter(TestType.class); assertNotNull(adapter); } public void testRecursiveTypeVariablesResolve12() throws Exception { + @SuppressWarnings("rawtypes") TypeAdapter adapter = new Gson().getAdapter(TestType2.class); assertNotNull(adapter); } diff --git a/gson/src/test/java/com/google/gson/internal/sql/SqlTypesGsonTest.java b/gson/src/test/java/com/google/gson/internal/sql/SqlTypesGsonTest.java new file mode 100644 index 0000000000..03e2185541 --- /dev/null +++ b/gson/src/test/java/com/google/gson/internal/sql/SqlTypesGsonTest.java @@ -0,0 +1,124 @@ +package com.google.gson.internal.sql; + +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Locale; +import java.util.TimeZone; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.functional.DefaultTypeAdaptersTest; +import com.google.gson.internal.JavaVersion; + +import junit.framework.TestCase; + +public class SqlTypesGsonTest extends TestCase { + private Gson gson; + private TimeZone oldTimeZone; + private Locale oldLocale; + + @Override + protected void setUp() throws Exception { + super.setUp(); + this.oldTimeZone = TimeZone.getDefault(); + TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); + this.oldLocale = Locale.getDefault(); + Locale.setDefault(Locale.US); + gson = new Gson(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + TimeZone.setDefault(oldTimeZone); + Locale.setDefault(oldLocale); + } + + public void testNullSerializationAndDeserialization() { + testNullSerializationAndDeserialization(Date.class); + testNullSerializationAndDeserialization(Time.class); + testNullSerializationAndDeserialization(Timestamp.class); + } + + private void testNullSerializationAndDeserialization(Class c) { + DefaultTypeAdaptersTest.testNullSerializationAndDeserialization(gson, c); + } + + public void testDefaultSqlDateSerialization() { + java.sql.Date instant = new java.sql.Date(1259875082000L); + String json = gson.toJson(instant); + assertEquals("\"Dec 3, 2009\"", json); + } + + public void testDefaultSqlDateDeserialization() { + String json = "'Dec 3, 2009'"; + java.sql.Date extracted = gson.fromJson(json, java.sql.Date.class); + DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3); + } + + // http://code.google.com/p/google-gson/issues/detail?id=230 + public void testSqlDateSerialization() throws Exception { + TimeZone defaultTimeZone = TimeZone.getDefault(); + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + Locale defaultLocale = Locale.getDefault(); + Locale.setDefault(Locale.US); + try { + java.sql.Date sqlDate = new java.sql.Date(0L); + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); + String json = gson.toJson(sqlDate, Timestamp.class); + assertEquals("\"1970-01-01\"", json); + assertEquals(0, gson.fromJson("\"1970-01-01\"", java.sql.Date.class).getTime()); + } finally { + TimeZone.setDefault(defaultTimeZone); + Locale.setDefault(defaultLocale); + } + } + + public void testDefaultSqlTimeSerialization() { + Time now = new Time(1259875082000L); + String json = gson.toJson(now); + assertEquals("\"01:18:02 PM\"", json); + } + + public void testDefaultSqlTimeDeserialization() { + String json = "'1:18:02 PM'"; + Time extracted = gson.fromJson(json, Time.class); + DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2); + } + + public void testDefaultSqlTimestampSerialization() { + Timestamp now = new java.sql.Timestamp(1259875082000L); + String json = gson.toJson(now); + if (JavaVersion.isJava9OrLater()) { + assertEquals("\"Dec 3, 2009, 1:18:02 PM\"", json); + } else { + assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json); + } + } + + public void testDefaultSqlTimestampDeserialization() { + String json = "'Dec 3, 2009 1:18:02 PM'"; + Timestamp extracted = gson.fromJson(json, Timestamp.class); + DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3); + DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2); + } + + // http://code.google.com/p/google-gson/issues/detail?id=230 + public void testTimestampSerialization() throws Exception { + TimeZone defaultTimeZone = TimeZone.getDefault(); + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + Locale defaultLocale = Locale.getDefault(); + Locale.setDefault(Locale.US); + try { + Timestamp timestamp = new Timestamp(0L); + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); + String json = gson.toJson(timestamp, Timestamp.class); + assertEquals("\"1970-01-01\"", json); + assertEquals(0, gson.fromJson("\"1970-01-01\"", Timestamp.class).getTime()); + } finally { + TimeZone.setDefault(defaultTimeZone); + Locale.setDefault(defaultLocale); + } + } +} diff --git a/gson/src/test/java/com/google/gson/internal/sql/SqlTypesSupportTest.java b/gson/src/test/java/com/google/gson/internal/sql/SqlTypesSupportTest.java new file mode 100644 index 0000000000..ea496f4ac9 --- /dev/null +++ b/gson/src/test/java/com/google/gson/internal/sql/SqlTypesSupportTest.java @@ -0,0 +1,16 @@ +package com.google.gson.internal.sql; + +import junit.framework.TestCase; + +public class SqlTypesSupportTest extends TestCase { + public void testSupported() { + assertTrue(SqlTypesSupport.SUPPORTS_SQL_TYPES); + + assertNotNull(SqlTypesSupport.DATE_DATE_TYPE); + assertNotNull(SqlTypesSupport.TIMESTAMP_DATE_TYPE); + + assertNotNull(SqlTypesSupport.DATE_FACTORY); + assertNotNull(SqlTypesSupport.TIME_FACTORY); + assertNotNull(SqlTypesSupport.TIMESTAMP_FACTORY); + } +}