Reputation: 603
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
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
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
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
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
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
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