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();
    }

}

      

+3


source to share


1 answer


You have several problems with this code.

  • Your first problem is what :

    is the operator in Json. You interpret unescaped String

    with :

    it, so Gson interprets it as key

    : 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 is yyyy-MM-dd'T'HH:mm:ss.SSS

    , which, as you can see, does not include the timezone. You want to use ISODateTimeFormat.dateTime()

    whose template yyyy-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));
  }
}

      

+3


source







All Articles