java - LocalDateTime 字段:MismatchedInputException:无法从 START_OBJECT 令牌中反序列化 `java.lang.String` 的实例
问题描述
我有一个主要课程:
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class ContentModel implements Serializable {
@JsonProperty("serviceData")
private ServiceData serviceData;
}
和嵌套类:
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class ServiceData implements Serializable {
@JsonProperty ("dateTimeMessageSend")
private LocalDateTime dateTimeMessageSend;
}
我正在尝试通过使用自定义反序列化器来反序列化它:
public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
private static final long serialVersionUID = 1L;
protected LocalDateTimeDeserializer() {
super(LocalDateTime.class);
}
@Override
public LocalDateTime deserialize(final JsonParser jp, final DeserializationContext ctxt)
throws IOException {
return LocalDateTime.parse(jp.readValueAs(String.class));
}
}
这就是我如何配置我的 objectMapper:
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
this.objectMapper.registerModule(javaTimeModule);
this.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
this.objectMapper.registerModule(new Jdk8Module());
this.objectMapper.findAndRegisterModules();
应用程序在以下 json 之外接收:
{
"serviceData": {
"dateTimeMessageSend": {
"month": "APRIL",
"dayOfYear": 109,
"dayOfWeek": "MONDAY",
"nano": 183251000,
"year": 2021,
"monthValue": 4,
"dayOfMonth": 19,
"hour": 14,
"minute": 52,
"second": 44,
"chronology": {
"calendarType": "iso8601",
"id": "ISO"
}
},
}
}
在 LocalDateTime 反序列化时,我收到异常:
MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
我想,杰克逊将“dateTimeMessageSend”识别为一个对象并且无法将其解析为字符串。
解决问题的方法是什么?
- 修改源 json,例如将 LocalDateFormat 更改为 String。(什么是不受欢迎的)
- 进一步定制 objectMapper 或/和 LocalDateTimeDeserializer
解决方案
当杰克逊deserialize
调用您的LocalDateTimeSerializer
.
您不会只得到一个长字符串,例如
{ "month": "APRIL", "dayOfYear": 109, ... }
. 因此,您不能只是简单地调用
jp.readValueAs(String.class);
你在MismatchedInputExcpetion
这里得到了 a ,因为解析器遇到了 a{
而不是 string "something"
。
实际上,您会得到一个令牌流(以 开头{
),您应该将其消耗到关闭}
令牌,从中提取相关部分,并LocalDateTime
从这些部分构建一个对象。
例如,参见Baeldung - Jackson 中的反序列化入门,尤其是那里给出的自定义反序列化器示例。按照这个教程,你可以实现这样的deserialize
方法:
@Override
public LocalDateTime deserialize(final JsonParser jp, final DeserializationContext ctxt)
throws IOException {
JsonNode node = jp.getCodec().readTree(jp);
int year = ((NumericNode) node.get("year")).asInt();
int monthValue = ((NumericNode) node.get("monthValue")).asInt();
int dayOfMonth = ((NumericNode) node.get("dayOfMonth")).asInt();
int hour = ((NumericNode) node.get("hour")).asInt();
int minute = ((NumericNode) node.get("minute")).asInt();
int second = ((NumericNode) node.get("second")).asInt();
return LocalDateTime.of(year, monthValue, dayOfMonth, hour, minute, second);
}
请注意,在接收到的 JSON 树中存在相当多的冗余,表示LoclDateTime
. 例如:它包含"month": "APRIL"
和
"monthValue": 4
。因此,您不需要从树中提取所有值,而只需要提取其中一些。
推荐阅读
- javascript - 从 Javascript 使用 Web 服务
- python - 用数组切片熊猫数据框列?
- arrays - 使用条形码扫描保存为文件名
- python-3.x - Python函数参数的外部和内部关键字名称不同?
- android - 从 A -> B 的活动转换和生命周期序列
- javascript - Service Worker PostMessage 错误
- image - How to add tags to image with Powershell
- javascript - Dynamically create part of JavaScript block in aspx page from code behind
- sql - 使用十进制输出 SQL Server 2008 减去下一行中的列值
- wix - Wix 安装程序不会建立在 VSTS 上