Why is my DateTime deserializer truncating DateTime minute / second / millisecond?
I have a class which is deserializes
a JSON
.
public class DateTimeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime>
{
private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateHourMinuteSecondMillis();
@Override
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context)
{
final DateTimeFormatter fmt = ISODateTimeFormat.dateHourMinuteSecondMillis();
return new JsonPrimitive(fmt.print(src));
}
@Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
final String dateAsString = json.getAsString();
System.out.println(dateAsString);
if (json.isJsonNull() || dateAsString.length()==0)
{
return null;
}
else
{
return DATE_FORMAT.parseDateTime(json.getAsString());
}
}
}
However, my method Deserialize
on typing:
2015-07-29T11:00:00.000Z
I get:
2015-07-29T11
of System.out.println(dateAsString);
Why is this truncating my input?
I think my problem is within my test class:
I have built an object DateTime
to be used with Google Gson. However, I think the default constructor for DateTimeType
does not support minute / second / millisecond. Is there a way to extend DateTimeType
to support it?
Here is my test class:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.joda.time.DateTime;
import org.junit.Test;
import java.lang.reflect.Type;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* Tests {@link DateTimeConverter}.
*/
public class DateTimeConverterTest {
String testTime = "2015-07-29T11:00:00.001Z";
@Test
public void testDateTimeConverter() throws Exception {
final Gson gson = initCustomGSON();
Type DateTimeType = new TypeToken<DateTime>() {
}.getType();
System.out.println(testTime);
DateTimeConverter timeConverter = new DateTimeConverter();
DateTime m = (gson.fromJson(testTime, DateTimeType));
assertThat("11", is(m.hourOfDay().getAsText()));
}
public Gson initCustomGSON() {
final GsonBuilder builder = new GsonBuilder();
JodaTimeConverters converter = new JodaTimeConverters();
converter.registerAll(builder);
return builder.create();
}
}
source to share
You have several problems with this code.
-
Your first problem is what
:
is the operator in Json. You interpret unescapedString
with:
it, so Gson interprets it askey
:value
. Your test string should surround the entire text date with quotes so that this doesn't happen, for example.String testTime = "\"2015-07-29T11:00:00.001Z\"";
-
You used
ISODateTimeFormat.dateHourMinuteSecondMillis()
in your code. However, the format template for this isyyyy-MM-dd'T'HH:mm:ss.SSS
, which, as you can see, does not include the timezone. You want to useISODateTimeFormat.dateTime()
whose templateyyyy-MM-dd'T'HH:mm:ss.SSSZZ
that has a timezone.private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateTime();
-
After these two changes, the object
DateTime
is finally created correctly ... but it will be created in your local timezone, not UTC (it will adjust the time correctly in your zone. You can easily switch it back to UTC by doing the following:DateTime m = ((DateTime) (gson.fromJson(testTime, DateTimeType))).withZone(DateTimeZone.UTC);
Once you make these three changes, your tests will pass. However: I highly recommend using JsonSerializer
and JsonDeserializer
, they are deprecated in favor of TypeAdapter
whose streaming API is significantly more performant:
New applications should prefer
TypeAdapter
whose streaming API is more efficient than this API tree of interfaces.
I know the user manual provides code for how to do this using API JsonSerializer
/ JsonDeserializer
, but that's only because they haven't updated it yet.
It would just be like this:
public class DateTimeAdapter extends TypeAdapter<DateTime> {
private static final DateTimeFormatter FORMAT = ISODateTimeFormat.dateTime();
public DateTime read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
String dateString = reader.nextString();
if(dateString.length() == 0) return null;
return FORMAT.parseDateTime(dateString);
}
public void write(JsonWriter writer, DateTime value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(FORMAT.print(value));
}
}
source to share