diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 27f3ee92..a7938c84 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.JsonTreeWriter; 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 final class 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 2c8dbe03..b2fd74ed 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 java.util.Map; 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 final class GsonBuilder { * 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 @@ -604,23 +605,33 @@ public final class GsonBuilder { private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle, List factories) { - DefaultDateTypeAdapter dateTypeAdapter; - TypeAdapter timestampTypeAdapter; - TypeAdapter javaSqlDateTypeAdapter; - if (datePattern != null && !"".equals(datePattern.trim())) { - dateTypeAdapter = DefaultDateTypeAdapter.DateType.DATE.createAdapter(datePattern); - timestampTypeAdapter = DefaultDateTypeAdapter.DateType.SQL_TIMESTAMP.createAdapter(datePattern); - javaSqlDateTypeAdapter = DefaultDateTypeAdapter.DateType.SQL_DATE.createAdapter(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 = DefaultDateTypeAdapter.DateType.DATE.createAdapter(dateStyle, timeStyle); - timestampTypeAdapter = DefaultDateTypeAdapter.DateType.SQL_TIMESTAMP.createAdapter(dateStyle, timeStyle); - javaSqlDateTypeAdapter = DefaultDateTypeAdapter.DateType.SQL_DATE.createAdapter(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/DefaultDateTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/DefaultDateTypeAdapter.java similarity index 73% 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 81b809be..9ac948f7 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,9 @@ import java.util.Date; 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.JavaVersion; import com.google.gson.internal.PreJava9DateFormatProvider; import com.google.gson.internal.bind.util.ISO8601Utils; @@ -35,54 +37,49 @@ import com.google.gson.stream.JsonToken; 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"; - static abstract class DateType { - private DateType() { - } - - public static final DateType DATE = new DateType() { - @Override - protected Date deserialize(Date date) { + public static abstract class DateType { + public static final DateType DATE = new DateType(Date.class) { + @Override protected Date deserialize(Date date) { return date; } }; - public static final DateType SQL_DATE = new DateType() { - @Override - protected java.sql.Date deserialize(Date date) { - return new java.sql.Date(date.getTime()); - } - }; - public static final DateType SQL_TIMESTAMP = new DateType() { - @Override - protected Timestamp deserialize(Date date) { - return new Timestamp(date.getTime()); - } - }; + + private final Class dateClass; + + protected DateType(Class dateClass) { + this.dateClass = dateClass; + } protected abstract T deserialize(Date date); - public DefaultDateTypeAdapter createAdapter(String datePattern) { - return new DefaultDateTypeAdapter(this, datePattern); + private final TypeAdapterFactory createFactory(DefaultDateTypeAdapter adapter) { + return TypeAdapters.newFactory(dateClass, adapter); } - public DefaultDateTypeAdapter createAdapter(int style) { - return new DefaultDateTypeAdapter(this, style); + public final TypeAdapterFactory createAdapterFactory(String datePattern) { + return createFactory(new DefaultDateTypeAdapter(this, datePattern)); } - public DefaultDateTypeAdapter createAdapter(int dateStyle, int timeStyle) { - return new DefaultDateTypeAdapter(this, dateStyle, timeStyle); + public final TypeAdapterFactory createAdapterFactory(int style) { + return createFactory(new DefaultDateTypeAdapter(this, style)); } - public DefaultDateTypeAdapter createDefaultsAdapter() { - return new DefaultDateTypeAdapter(this, DateFormat.DEFAULT, DateFormat.DEFAULT); + 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)); } } @@ -162,11 +159,12 @@ final class DefaultDateTypeAdapter extends TypeAdapter { 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 354ce5a1..af790e2c 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 @@ -23,12 +23,10 @@ import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -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; @@ -406,7 +404,7 @@ public final class TypeAdapters { out.value(value); } }; - + public static final TypeAdapter BIG_DECIMAL = new TypeAdapter() { @Override public BigDecimal read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { @@ -424,7 +422,7 @@ public final class TypeAdapters { out.value(value); } }; - + public static final TypeAdapter BIG_INTEGER = new TypeAdapter() { @Override public BigInteger read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { @@ -569,27 +567,6 @@ public final class TypeAdapters { }.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 5ec244f2..b3da1fef 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 @@ import java.text.SimpleDateFormat; * 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 55d4b2f6..ee65726b 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.text.SimpleDateFormat; 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 161fbdba..38c26e56 100644 --- a/gson/src/main/java/module-info.java +++ b/gson/src/main/java/module-info.java @@ -8,5 +8,6 @@ module com.google.gson { 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/DefaultDateTypeAdapterTest.java b/gson/src/test/java/com/google/gson/internal/bind/DefaultDateTypeAdapterTest.java similarity index 64% 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 e626ea7a..2fdc64ae 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,8 +23,13 @@ import java.util.Date; import java.util.Locale; import java.util.TimeZone; -import com.google.gson.DefaultDateTypeAdapter.DateType; +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; @@ -53,18 +58,18 @@ public class DefaultDateTypeAdapterTest extends TestCase { String afterYearLongSep = JavaVersion.isJava9OrLater() ? " at " : " "; String utcFull = JavaVersion.isJava9OrLater() ? "Coordinated Universal Time" : "UTC"; assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep), - DateType.DATE.createDefaultsAdapter()); - assertFormatted("1/1/70", DateType.DATE.createAdapter(DateFormat.SHORT)); - assertFormatted("Jan 1, 1970", DateType.DATE.createAdapter(DateFormat.MEDIUM)); - assertFormatted("January 1, 1970", DateType.DATE.createAdapter(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), - DateType.DATE.createAdapter(DateFormat.SHORT, DateFormat.SHORT)); + DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT)); assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep), - DateType.DATE.createAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); + DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertFormatted(String.format("January 1, 1970%s12:00:00 AM UTC", afterYearLongSep), - DateType.DATE.createAdapter(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), - DateType.DATE.createAdapter(DateFormat.FULL, DateFormat.FULL)); + DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -79,21 +84,21 @@ public class DefaultDateTypeAdapterTest extends TestCase { try { String afterYearSep = JavaVersion.isJava9OrLater() ? " à " : " "; assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep), - DateType.DATE.createDefaultsAdapter()); - assertParsed("01/01/70", DateType.DATE.createAdapter(DateFormat.SHORT)); - assertParsed("1 janv. 1970", DateType.DATE.createAdapter(DateFormat.MEDIUM)); - assertParsed("1 janvier 1970", DateType.DATE.createAdapter(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", - DateType.DATE.createAdapter(DateFormat.SHORT, DateFormat.SHORT)); + DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT)); assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep), - DateType.DATE.createAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); + DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertParsed(String.format("1 janvier 1970%s00:00:00 UTC", afterYearSep), - DateType.DATE.createAdapter(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", - DateType.DATE.createAdapter(DateFormat.FULL, DateFormat.FULL)); + DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -106,18 +111,18 @@ public class DefaultDateTypeAdapterTest extends TestCase { Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { - assertParsed("Jan 1, 1970 0:00:00 AM", DateType.DATE.createDefaultsAdapter()); - assertParsed("1/1/70", DateType.DATE.createAdapter(DateFormat.SHORT)); - assertParsed("Jan 1, 1970", DateType.DATE.createAdapter(DateFormat.MEDIUM)); - assertParsed("January 1, 1970", DateType.DATE.createAdapter(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", - DateType.DATE.createAdapter(DateFormat.SHORT, DateFormat.SHORT)); + DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT)); assertParsed("Jan 1, 1970 0:00:00 AM", - DateType.DATE.createAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); + DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertParsed("January 1, 1970 0:00:00 AM UTC", - DateType.DATE.createAdapter(DateFormat.LONG, DateFormat.LONG)); + DateType.DATE.createAdapterFactory(DateFormat.LONG, DateFormat.LONG)); assertParsed("Thursday, January 1, 1970 0:00:00 AM UTC", - DateType.DATE.createAdapter(DateFormat.FULL, DateFormat.FULL)); + DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -132,8 +137,8 @@ public class DefaultDateTypeAdapterTest extends TestCase { try { String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " "; assertFormatted(String.format("Dec 31, 1969%s4:00:00 PM", afterYearSep), - DateType.DATE.createDefaultsAdapter()); - assertParsed("Dec 31, 1969 4:00:00 PM", DateType.DATE.createDefaultsAdapter()); + DateType.DATE.createDefaultsAdapterFactory()); + assertParsed("Dec 31, 1969 4:00:00 PM", DateType.DATE.createDefaultsAdapterFactory()); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); @@ -141,17 +146,17 @@ public class DefaultDateTypeAdapterTest extends TestCase { } public void testDateDeserializationISO8601() throws Exception { - DefaultDateTypeAdapter adapter = DateType.DATE.createDefaultsAdapter(); - 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 = DateType.DATE.createAdapter(dateStyle); + TypeAdapter dateTypeAdapter = dateAdapter(DateType.DATE.createAdapterFactory(dateStyle)); DateFormat formatter = DateFormat.getDateInstance(dateStyle, Locale.US); Date currentDate = new Date(); @@ -161,7 +166,7 @@ public class DefaultDateTypeAdapterTest extends TestCase { public void testDatePattern() throws Exception { String pattern = "yyyy-MM-dd"; - DefaultDateTypeAdapter dateTypeAdapter = DateType.DATE.createAdapter(pattern); + TypeAdapter dateTypeAdapter = dateAdapter(DateType.DATE.createAdapterFactory(pattern)); DateFormat formatter = new SimpleDateFormat(pattern); Date currentDate = new Date(); @@ -171,30 +176,38 @@ public class DefaultDateTypeAdapterTest extends TestCase { public void testInvalidDatePattern() throws Exception { try { - DateType.DATE.createAdapter("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 = DateType.DATE.createDefaultsAdapter(); + TypeAdapter adapter = dateAdapter(DateType.DATE.createDefaultsAdapterFactory()); assertNull(adapter.fromJson("null")); assertEquals("null", adapter.toJson(null)); } public void testUnexpectedToken() throws Exception { try { - DefaultDateTypeAdapter adapter = DateType.DATE.createDefaultsAdapter(); + 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/sql/SqlTypesSupportTest.java b/gson/src/test/java/com/google/gson/internal/sql/SqlTypesSupportTest.java new file mode 100644 index 00000000..ea496f4a --- /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); + } +}