Use new instances of DateTypeAdapter and TimeTypeAdapter for each GSON; this guarantees that the TimeZone and Locale are what they should be
This commit is contained in:
parent
2f0fbf6bcc
commit
3b3a60d301
@ -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))
|
||||
|
@ -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<Date> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) 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);
|
||||
}
|
||||
}
|
@ -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<Time> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new TimeTypeAdapter() : null;
|
||||
}
|
||||
};
|
||||
|
||||
private final DateFormat format = new SimpleDateFormat("hh:mm:ss a");
|
||||
|
||||
@Override public synchronized Time read(JsonReader reader) throws IOException {
|
||||
try {
|
||||
Date date = format.parse(reader.nextString());
|
||||
return new Time(date.getTime());
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void write(JsonWriter writer, Time value) throws IOException {
|
||||
writer.value(format.format(value));
|
||||
}
|
||||
}
|
@ -16,12 +16,18 @@
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.internal.LazilyParsedNumber;
|
||||
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 java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
@ -32,17 +38,8 @@ import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.internal.LazilyParsedNumber;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Type adapters for basic types.
|
||||
*/
|
||||
@ -412,75 +409,8 @@ public final class TypeAdapters {
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static final TypeAdapter<Date> DATE = new TypeAdapter<Date>() {
|
||||
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();
|
||||
@Override
|
||||
public Date read(JsonReader reader) throws IOException {
|
||||
return deserializeToDate(reader.nextString());
|
||||
}
|
||||
|
||||
private Date deserializeToDate(String json) {
|
||||
synchronized (localFormat) {
|
||||
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 void write(JsonWriter writer, Date value) throws IOException {
|
||||
synchronized (localFormat) {
|
||||
String dateFormatAsString = enUsFormat.format(value);
|
||||
writer.value(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory DATE_FACTORY = newFactory(Date.class, DATE);
|
||||
|
||||
public static final TypeAdapter.Factory UUID_FACTORY = newFactory(UUID.class, UUID);
|
||||
|
||||
public static final TypeAdapter<Time> SQL_TIME = new TypeAdapter<Time>() {
|
||||
private final DateFormat format = new SimpleDateFormat("hh:mm:ss a");
|
||||
@Override
|
||||
public Time read(JsonReader reader) throws IOException {
|
||||
try {
|
||||
synchronized (format) {
|
||||
Date date = format.parse(reader.nextString());
|
||||
return new java.sql.Time(date.getTime());
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Time value) throws IOException {
|
||||
writer.value(format.format(value));
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory SQL_TIME_FACTORY = newFactory(Time.class, SQL_TIME);
|
||||
|
||||
private static final class TimestampTypeAdapter extends TypeAdapter<Timestamp> {
|
||||
private final MiniGson context;
|
||||
public TimestampTypeAdapter(MiniGson context) {
|
||||
|
Loading…
Reference in New Issue
Block a user