fische
fische

Reputation: 603

Java 8 LocalDateTime deserialized using Gson

I have JSONs with a date-time attribute in the format "2014-03-10T18:46:40.000Z", which I want to deserialize into a java.time.LocalDateTime field using Gson.

When I tried to deserialize, I get the error:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING

Upvotes: 58

Views: 72773

Answers (6)

rvazquezglez
rvazquezglez

Reputation: 2454

To further amplify @Nicholas Terry answer:

You might also need a serializer:

String dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
GSON gson = new GsonBuilder()
    .registerTypeAdapter(
        LocalDateTime.class,
        (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) ->
            ZonedDateTime.parse(json.getAsJsonPrimitive().getAsString()).toLocalDateTime()
    )
    .registerTypeAdapter(
        LocalDateTime.class,
        (JsonSerializer<LocalDateTime>) (localDate, type, jsonSerializationContext) ->
            new JsonPrimitive(formatter.format(localDate)
    )
    .create();

Or the kotlin version:

val dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
val formatter = DateTimeFormatter.ofPattern(dateFormat)
val gson: Gson = GsonBuilder()
    .registerTypeAdapter(
        LocalDateTime::class.java,
        JsonDeserializer { json, type, jsonDeserializationContext -> 
            ZonedDateTime.parse(json.asJsonPrimitive.asString).toLocalDateTime()
        } as JsonDeserializer<LocalDateTime?>
    )
    .registerTypeAdapter(
        LocalDateTime::class.java,
        JsonSerializer<LocalDateTime?> { localDate, type, jsonDeserializationContext ->
            JsonPrimitive(formatter.format(localDate))
        }
    )
    .create()

Upvotes: 1

Syakur Rahman
Syakur Rahman

Reputation: 2102

As mentioned in the comments above, you could also use already available serializer.

https://github.com/gkopff/gson-javatime-serialisers

You include it in your project.

<dependency>
  <groupId>com.fatboyindustrial.gson-javatime-serialisers</groupId>
  <artifactId>gson-javatime-serialisers</artifactId>
  <version>1.1.2</version>
</dependency>

Then include it to the GsonBuilder process

final Gson gson = Converters.registerOffsetDateTime(new GsonBuilder()).create();
final OffsetDateTime original = OffsetDateTime.now();

final String json = gson.toJson(original);
final OffsetDateTime reconstituted = gson.fromJson(json, OffsetDateTime.class);

Just in case its not clear, there exist different methods for different class types.

Upvotes: 2

greenhorn
greenhorn

Reputation: 654

Following worked for me.

Java:

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() { 
@Override 
public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 

return LocalDateTime.parse(json.getAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); } 

}).create();

Test test = gson.fromJson(stringJson, Test.class);

where stringJson is a Json which is stored as String type

Json:

"dateField":"2020-01-30 15:00"

where dateField is of LocalDateTime type which is present in the stringJson String variable.

Upvotes: 8

Nicholas Terry
Nicholas Terry

Reputation: 1930

To even further extend @Evers answer:

You can further simplify with a lambda like so:

GSON GSON = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) ->
    ZonedDateTime.parse(json.getAsJsonPrimitive().getAsString()).toLocalDateTime()).create();

Upvotes: 33

Evers
Evers

Reputation: 1908

To extend @Randula's answer, to parse a zoned date time string (2014-03-10T18:46:40.000Z) to JSON:

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
@Override
public LocalDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
    return ZonedDateTime.parse(json.getAsJsonPrimitive().getAsString()).toLocalDateTime();
}
}).create();

Upvotes: 35

Randula
Randula

Reputation: 1597

The error occurs when you are deserializing the LocalDateTime attribute because GSON fails to parse the value of the attribute as it's not aware of the LocalDateTime objects.

Use GsonBuilder's registerTypeAdapter method to define the custom LocalDateTime adapter. Following code snippet will help you to deserialize the LocalDateTime attribute.

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
    @Override
    public LocalDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        Instant instant = Instant.ofEpochMilli(json.getAsJsonPrimitive().getAsLong());
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }
}).create();

Upvotes: 55

Related Questions