我有一些带有日期时间属性的JSON,格式为"2014-03-10T18:46:40.000Z",我想使用Gson将其反序列化为java.time.LocalDateTime字段。
当我尝试反序列化时,我遇到了错误:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING
当您对LocalDateTime属性进行反序列化时,会出现错误,因为GSON无法解析该属性的值,因为它不知道LocalDateTime对象。
使用GsonBuilder的registerTypeAdapter方法来定义自定义的LocalDateTime适配器。以下代码片段将帮助您反序列化LocalDateTime属性。
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();
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();
java.lang.reflect.Type
。 - LambartLocalDateTime
忽略了输入的指示器 Z
,该指示器表示与 UTC 的零小时-分钟-秒偏移量。 ZonedDateTime
用于表示时区上下文中的日期时间,但输入没有时区。 此输入的适当类别为 Instant
或 OffsetDateTime
。 - Basil Bourque进一步扩展@Evers的答案:
你可以使用lambda进一步简化,如下所示:
GSON GSON = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) ->
ZonedDateTime.parse(json.getAsJsonPrimitive().getAsString()).toLocalDateTime()).create();
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);
其中stringJson是以String类型存储的Json字符串。
Json:
"dateField":"2020-01-30 15:00"
其中dateField是 LocalDateTime 类型,在字符串变量stringJson中存在。
如上方的评论所提到的,您也可以使用已经可用的序列化器。
https://github.com/gkopff/gson-javatime-serialisers
你可以将它包含在你的项目中。
<dependency>
<groupId>com.fatboyindustrial.gson-javatime-serialisers</groupId>
<artifactId>gson-javatime-serialisers</artifactId>
<version>1.1.2</version>
</dependency>
然后将其包含到GsonBuilder过程中
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);
以防不清楚,不同的类类型存在着不同的方法。
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();
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()
{"key":"value"}
。你的 JSON 明显是无效的。就像我在 Gson 中所说的,{
是BEGIN_OBJECT
,它表示缺失了。只需使用println()
打印 JSON 来检查其是否正确。此外,你可以打印serialized
对象以查看 JSON 应该是什么样子的 :) - Svetlin ZarevOffsetDateTime
而不是LocalDateTime
。此外,你可能想看一下我为java.time
实体定制的序列化器:https://github.com/gkopff/gson-javatime-serialisers - Greg Kopff