Fix date adapters to work when run in any time zone.

This commit is contained in:
Jesse Wilson 2011-09-28 17:56:54 +00:00
parent cebda2b119
commit 3f26144165
4 changed files with 81 additions and 48 deletions

View File

@ -30,6 +30,7 @@ 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.SqlDateTypeAdapter;
import com.google.gson.internal.bind.TimeTypeAdapter;
import com.google.gson.internal.bind.TypeAdapter;
import com.google.gson.internal.bind.TypeAdapters;
@ -259,8 +260,8 @@ public final class Gson {
.factory(DateTypeAdapter.FACTORY)
.factory(TypeAdapters.CALENDAR_FACTORY)
.factory(TimeTypeAdapter.FACTORY)
.factory(TypeAdapters.SQL_DATE_FACTORY)
.factory(TypeAdapters.SQL_TIMESTAMP_FACTORY)
.factory(SqlDateTypeAdapter.FACTORY)
.factory(TypeAdapters.TIMESTAMP_FACTORY)
.factory(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization))
.factory(ArrayTypeAdapter.FACTORY)
.factory(TypeAdapters.ENUM_FACTORY)

View File

@ -29,7 +29,7 @@ import java.util.Locale;
import java.util.TimeZone;
/**
* Adapter for Time. Although this class appears stateless, it is not.
* Adapter for Date. 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.

View File

@ -0,0 +1,59 @@
/*
* 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;
/**
* Adapter for java.sql.Date. 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 SqlDateTypeAdapter extends TypeAdapter<java.sql.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() == java.sql.Date.class
? (TypeAdapter<T>) new SqlDateTypeAdapter() : null;
}
};
private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");
@Override
public synchronized java.sql.Date read(JsonReader reader) throws IOException {
try {
final long utilDate = format.parse(reader.nextString()).getTime();
return new java.sql.Date(utilDate);
} catch (ParseException e) {
throw new JsonSyntaxException(e);
}
}
@Override
public synchronized void write(JsonWriter writer, java.sql.Date value) throws IOException {
writer.value(format.format(value));
}
}

View File

@ -29,9 +29,6 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Date;
@ -53,7 +50,7 @@ public final class TypeAdapters {
int i = 0;
JsonToken tokenType = reader.peek();
while (tokenType != JsonToken.END_ARRAY) {
boolean set = false;
boolean set;
switch (tokenType) {
case NUMBER:
set = reader.nextInt() != 0;
@ -411,52 +408,27 @@ public final class TypeAdapters {
public static final TypeAdapter.Factory UUID_FACTORY = newFactory(UUID.class, UUID);
private static final class TimestampTypeAdapter extends TypeAdapter<Timestamp> {
private final MiniGson context;
public TimestampTypeAdapter(MiniGson context) {
this.context = context;
}
@Override
public Timestamp read(JsonReader reader) throws IOException {
TypeAdapter<Date> dateTypeAdapter = context.getAdapter(Date.class);
Date date = dateTypeAdapter.read(reader);
return new java.sql.Timestamp(date.getTime());
}
@Override
public void write(JsonWriter writer, Timestamp value) throws IOException {
TypeAdapter<Date> dateTypeAdapter = context.getAdapter(Date.class);
dateTypeAdapter.write(writer, value);
}
};
public static final TypeAdapter.Factory SQL_TIMESTAMP_FACTORY = new TypeAdapter.Factory() {
@SuppressWarnings("unchecked")
public static final TypeAdapter.Factory TIMESTAMP_FACTORY = new TypeAdapter.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() == Timestamp.class
? (TypeAdapter<T>) new TimestampTypeAdapter(context) : null;
}
};
public static final TypeAdapter<java.sql.Date> SQL_DATE = new TypeAdapter<java.sql.Date>() {
private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");
@Override
public java.sql.Date read(JsonReader reader) throws IOException {
try {
synchronized (format) {
Date date = format.parse(reader.nextString());
return new java.sql.Date(date.getTime());
}
} catch (ParseException e) {
throw new JsonSyntaxException(e);
if (typeToken.getRawType() != Timestamp.class) {
return null;
}
}
@Override
public void write(JsonWriter writer, java.sql.Date value) throws IOException {
writer.value(format.format(value));
final TypeAdapter<Date> dateTypeAdapter = context.getAdapter(Date.class);
return (TypeAdapter<T>) new TypeAdapter<Timestamp>() {
@Override public Timestamp read(JsonReader reader) throws IOException {
Date date = dateTypeAdapter.read(reader);
return new Timestamp(date.getTime());
}
@Override public void write(JsonWriter writer, Timestamp value) throws IOException {
dateTypeAdapter.write(writer, value);
}
};
}
};
public static final TypeAdapter.Factory SQL_DATE_FACTORY = newFactory(java.sql.Date.class, SQL_DATE);
public static final TypeAdapter<Calendar> CALENDAR = new TypeAdapter<Calendar>() {
private static final String YEAR = "year";
private static final String MONTH = "month";
@ -633,4 +605,5 @@ public final class TypeAdapters {
}
};
}
}