如何使用jackson(Java)反序列化对象中的json对象?

Posted

技术标签:

【中文标题】如何使用jackson(Java)反序列化对象中的json对象?【英文标题】:How to deserialize json Object in Object with jackson(Java)? 【发布时间】:2019-12-01 13:54:13 【问题描述】:

如何使用 jackson(Java) 在 Object 中反序列化 json 对象(在我的情况下,Offer 对象存在于 current 字段中)?

输入字符串:

message.getMessage();

"header":"OFFER","message":"\"author\":\"Peter Smith\",\"previous\":null,\"current\":\"id\ ":\"eOUQieQdvB\",\"authorUserId\":\"foo\""

ObjectMapper mapper = new ObjectMapper();
PushEventMessage<PushEvent<Offer>> pushEventMessage = mapper.readValue(message.getMessage(), PushEventMessage.class);
pushEventMessage.getMessage();

"author":"Peter Smith","previous":null,"current":"id":"eOUQieQdvB","authorUserId":"foo"

PushEvent<Offer> pushEvent = mapper.readValue(pushEventMessage.getMessage(), PushEvent.class);
pushEvent.getAuthor(); // is OK and contain "Peter Smith"

pushEvent.getCurrent() // is KO and contain id=eOUQieQdvB, authorUserId=foo

我要反序列化:

Offer offer= mapper.readValue(pushEvent.getCurrent() + "", Offer.class);

我的错误是:

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('i' (code 105)): was expecting double-quote to start field name
 at [Source: (String)"id=eOUQieQdvB, authorUserId=foo,

EDIT 1,我添加PushEvent&lt;T&gt; 类。

import lombok.*;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class PushEvent<T> 
    String author;
    T previous;
    T current;
    String error;

EDIT 2,我试试这个,但结果是一样的

PushEvent<Offer> pushEvent = mapper.readValue(pushEventMessage.getMessage().replaceAll("\\\"", "\""), PushEvent.class);

我采用@Smutje 的解决方案,这解决了第一个问题。!!

编辑 3,我在 Offer 对象中有一个 java.time.ZonedDateTime

"author":"Peter Smith","previous":null,"current":"id":"00Yno9WwsL","authorUserId":"foo","createdAt":"offset": "totalSeconds":0,"id":"Z","rules":"transitionRules":[],"transitions":[],"fixedOffset":true,"zone":"id": "UTC","rules":"transitionRules":[],"transitions":[],"fixedOffset":true,"dayOfMonth":11,"dayOfWeek":"SUNDAY","dayOfYear":42 ,"月":"二月","年":2018,"小时":1,"分钟":0,"纳米":0,"秒":0,"月值":2,"年表": "id":"ISO","calendarType":"iso8601"

我有这个错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.ZonedDateTime` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)""id":"00Yno9WwsL","authorUserId":"foo", ....."createdAt":"offset":"totalSeconds":0,...

EDIT 4,我添加Offer 类。

@Slf4j
@Data
@NoArgsConstructor
public class Offer 

    @Id
    protected String id;

    protected String authorUserId;

    protected ZonedDateTime createdAt;


【问题讨论】:

pushEvent.getCurrent()有什么返回类型? 为什么不用另一个 POJO?无法反序列化为Offer,因为它没有id,还有剩余字段,你能显示Offer 类吗? @Smutje,在我的例子中是 LinkedHashMap,因为所有双引号都被撤销(我不知道为什么?)我想要一个对象“Offer”。 请添加您的“PushEvent”类。 @Smutje,我用PushEvent&lt;T&gt; class 编辑了我的问题。 【参考方案1】:

由于许多映射框架无法使用泛型或继承层次结构正确反序列化对象,因此以下是丑陋的,但应该是可能的

PushEvent<Offer> pushEvent = mapper.readValue(pushEventMessage.getMessage(), PushEvent.class);
String serializedOffer = mapper.writeValueAsString(pushEventMessage.getCurrent());
Offer offer = mapper.readValue(serializedOffer, Offer.class);
pushEvent.setCurrent(offer);

说明:Jackson 将您的内部对象反序列化不是您所说的 Offer,而是作为 LinkedHashMap 在将 JSON 对象读取为实际 Offer 之前再次序列化为 JSON 对象。

您尝试将LinkedHashMap 读入Offer 失败,因为您(隐含地)使用LinkedHashMaptoString 表示来解析 生成有效JSON 的哪个。 p>

编辑 4 答案:,如果 Object 包含 ZonedDateTime。读写时使用:

ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
mapper.setDateFormat(new StdDateFormat());

【讨论】:

谢谢,我还有最后一个问题。我的 Offer 对象包含 ZonedDateTime \"createdAt\":\"offset\":\"totalSeconds\":0,\"id\":\"Z\",\"rules\":\ "transitionRules\":[],\"transitions\":[],\"fixedOffset\":true,\"zone\":\"id\":\"UTC\",\"rules\ ":\"transitionRules\":[],\"transitions\":[],\"fixedOffset\":true,\"dayOfMonth\":11,\"dayOfWeek\":\"SUNDAY\" ,\"dayOfYear\":42,\"month\":\"FEBRUARY\",\"year\":2018,\"hour\":1,\"minute\":0,\"nano\" :0,\"second\":0,\"monthValue\":2,\"chronology\":\"id\":\"ISO\",\"calendarType\":\"iso8601\" 请扩展您的问题,cmets 不适合长行代码 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 无法构造java.time.ZonedDateTime 的实例(没有创建者,如默认构造,存在):无法从对象值反序列化(没有委托或属性-基于创建者)在 [Source: (String)""id":"00Yno9WwsL","authorUserId":"foo", ....."createdAt":"offset":"totalSeconds":0,. .. 简而言之:忽略反序列化字段并手动填充它与您的序列化策略相反。【参考方案2】:

错误消息告诉您问题出在哪里:“期望用双引号来开始字段名称”。

通过简单检查,您读取 json 字符串的代码看起来是正确的,因此请确保您提供的数据有效。

提示:您可以通过简单地序列化演示对象来生成已知良好的数据:

new ObjectMapper().writeValueAsString(demoObject);

然后您可以尝试使用该字符串运行您的代码,这将告诉您您的输入是否有效。

【讨论】:

以上是关于如何使用jackson(Java)反序列化对象中的json对象?的主要内容,如果未能解决你的问题,请参考以下文章

Java Jackson json 到对象反序列化。如何处理 OWASP 不安全的反序列化?

如何使用 Jackson 解析 JSON 数组项中的原始值?

如何使用 Jackson 反序列化来自 json 对象的对象数组

在 Java 中的 Jackson JSON 反序列化期间忽略丢失的属性

如何根据json中的属性编写jackson反序列化器

Jackson序列化(8)— 支持泛型的反序列化