Skip to content

Commit

Permalink
Remove DateTypeAdapter to avoid code duplication (#2546)
Browse files Browse the repository at this point in the history
The same functionality exists in `DefaultDateTypeAdapter` (with some slight
overhead), and there is currently code duplication between these classes.
  • Loading branch information
Marcono1234 authored Nov 19, 2023
1 parent 08174e2 commit ea4ffde
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 120 deletions.
4 changes: 2 additions & 2 deletions gson/src/main/java/com/google/gson/Gson.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import com.google.gson.internal.Streams;
import com.google.gson.internal.bind.ArrayTypeAdapter;
import com.google.gson.internal.bind.CollectionTypeAdapterFactory;
import com.google.gson.internal.bind.DateTypeAdapter;
import com.google.gson.internal.bind.DefaultDateTypeAdapter;
import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory;
import com.google.gson.internal.bind.JsonTreeReader;
import com.google.gson.internal.bind.JsonTreeWriter;
Expand Down Expand Up @@ -369,7 +369,7 @@ public Gson() {
factories.add(TypeAdapters.LOCALE_FACTORY);
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
factories.add(TypeAdapters.BIT_SET_FACTORY);
factories.add(DateTypeAdapter.FACTORY);
factories.add(DefaultDateTypeAdapter.DEFAULT_STYLE_FACTORY);
factories.add(TypeAdapters.CALENDAR_FACTORY);

if (SqlTypesSupport.SUPPORTS_SQL_TYPES) {
Expand Down
116 changes: 0 additions & 116 deletions gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

package com.google.gson.internal.bind;

import com.google.gson.Gson;
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;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
Expand All @@ -35,17 +37,48 @@
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;

/**
* This type adapter supports subclasses of date by defining a {@link
* DefaultDateTypeAdapter.DateType} and then using its {@code createAdapterFactory} methods.
*
* <p><b>Important:</b> Instances of this class (or rather the {@link SimpleDateFormat} they use)
* capture the current default {@link Locale} and {@link TimeZone} when they are created. Therefore
* avoid storing factories obtained from {@link DateType} in {@code static} fields, since they only
* create a single adapter instance and its behavior would then depend on when Gson classes are
* loaded first, and which default {@code Locale} and {@code TimeZone} was used at that point.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
public final class DefaultDateTypeAdapter<T extends Date> extends TypeAdapter<T> {
private static final String SIMPLE_NAME = "DefaultDateTypeAdapter";

/** Factory for {@link Date} adapters which use {@link DateFormat#DEFAULT} as style. */
public static final TypeAdapterFactory DEFAULT_STYLE_FACTORY =
// Because SimpleDateFormat captures the default TimeZone when it was created, let the factory
// always create new DefaultDateTypeAdapter instances (which are then cached by the Gson
// instances) instead of having a single static DefaultDateTypeAdapter instance
// Otherwise the behavior would depend on when an application first loads Gson classes and
// which default TimeZone is set at that point, which would be quite brittle
new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
return typeToken.getRawType() == Date.class
? (TypeAdapter<T>)
new DefaultDateTypeAdapter<>(
DateType.DATE, DateFormat.DEFAULT, DateFormat.DEFAULT)
: null;
}

@Override
public String toString() {
return "DefaultDateTypeAdapter#DEFAULT_STYLE_FACTORY";
}
};

public abstract static class DateType<T extends Date> {
public static final DateType<Date> DATE =
new DateType<Date>(Date.class) {
Expand Down Expand Up @@ -123,8 +156,6 @@ private DefaultDateTypeAdapter(DateType<T> dateType, int dateStyle, int timeStyl
}
}

// These methods need to be synchronized since JDK DateFormat classes are not thread-safe
// See issue 162
@Override
public void write(JsonWriter out, Date value) throws IOException {
if (value == null) {
Expand All @@ -134,6 +165,7 @@ public void write(JsonWriter out, Date value) throws IOException {

DateFormat dateFormat = dateFormats.get(0);
String dateFormatAsString;
// Needs to be synchronized since JDK DateFormat classes are not thread-safe
synchronized (dateFormats) {
dateFormatAsString = dateFormat.format(value);
}
Expand All @@ -152,6 +184,7 @@ public T read(JsonReader in) throws IOException {

private Date deserializeToDate(JsonReader in) throws IOException {
String s = in.nextString();
// Needs to be synchronized since JDK DateFormat classes are not thread-safe
synchronized (dateFormats) {
for (DateFormat dateFormat : dateFormats) {
try {
Expand Down

0 comments on commit ea4ffde

Please sign in to comment.