使用带有字段依赖的 Jackson 反序列化 JSON
Posted
技术标签:
【中文标题】使用带有字段依赖的 Jackson 反序列化 JSON【英文标题】:Deserialize JSON with Jackson with field dependency 【发布时间】:2017-04-04 10:14:31 【问题描述】:在我们的项目中,我们使用 Jackson 解析 JSON。我们通过字段channelId
设置字段saved
。问题是channelId
字段的解析晚于saved
。所以当时我们要设置字段saved
字段channelId
为null。 JSON反序列化中如何设置字段依赖,使saved
字段设置在channelId
之后?
这是我们 JSON 数据的一部分:
"message":
"data":
"text":"Some text"
,
"saved_by":[
2715,
1234
],
"some_boolean_field":false,
"channel_id":8162
这是我们的实体类:
@JsonIgnoreProperties(ignoreUnknown = true)
@org.parceler.Parcel(org.parceler.Parcel.Serialization.BEAN)
public class Message
@JsonProperty("channel_id")
protected long channelId;
protected boolean saved;
@JsonSetter("saved_by")
public void setSavedBy(Set<Long> savedBy)
saved = savedBy.contains(getUserIdByChannelId(channelId));
public long getChannelId()
return channelId;
public void setChannelId(long channelId)
this.channelId = channelId;
public boolean isSaved()
return saved;
public void setSaved(boolean saved)
this.saved = saved;
public void setData(JsonNode data) throws JsonProcessingException
JsonNode textNode = data.get("text");
text = textNode != null ? textNode.asText() : "";
components = new ArrayList<>();
JsonNode mediaNode = data.get("media");
if (mediaNode != null)
MessageComponent[] parsedComponents = AppSession.getInstance().getObjectMapper().treeToValue(mediaNode, MessageComponent[].class);
List<MessageComponent> components = Arrays.asList(parsedComponents).subList(0, parsedComponents.length < 4 ? parsedComponents.length : 4);
this.components.addAll(components);
mediaCount = components.size();
完整的 JSON:
"data":
"serial":66,
"updated_entity":"bookmark",
"bookmark":
"message":
"data":
"text":"hello"
,
"counted_serial":748,
"saved_by":[
26526,
27758
],
"type":"UserMessage",
"is_reviewed":false,
"channel_id":8128,
"id":2841531,
"replied_message_data":null,
"is_blocked":false,
"is_deleted":false,
"updated_at":"2016-11-21T05:59:52.471Z",
"spam_reported_by":[
],
"created_at":"2016-11-19T15:40:17.027Z",
"uuid":"0b6ba58e-f5e1-4ee5-a9da-041dfc2c85cd",
"liked_by":[
],
"user":
"last_name":"M",
"id":4537,
"first_name":"John",
"is_deleted":false,
"avatar_thumb":"https:\/\/cdn.site.org\/uploads\/99ef4d68-6eaf-4ba6-aafa-74d1cf895d71\/thumb.jpg"
,
"serial":934
,
"id":6931,
"created_at":"2016-11-21T05:59:52.459Z",
"is_deleted":false,
"updated_at":"2016-11-21T05:59:52.459Z"
,
"type":"action_performed"
【问题讨论】:
是否可以从构造函数而不是通过设置字段来重建它? 如果saved
字段总是依赖于channelId
,那么为什么不在setChannelId()
中设置saved
字段呢?
不保证 JSON 顺序。例如,在某些手机中我得到了正确的字段顺序,在其他手机中顺序不同。
在setChannelId
我们可能还没有saved_by
值。
显示完整的 json 文件...
【参考方案1】:
这有点老套,但是通过将 Message
类设为自己的反序列化构建器,您将获得一种“准备创建 bean”的事件,您可以在其中访问所有属性。
我的建议是您尝试以下方法:
@JsonDeserialize(builder = Message.class)
public class Message
...
@JsonSetter("saved_by")
public void setSavedBy(Set<Long> savedBy)
// Merely store the value for later use.
this.savedBy = savedBy;
...
public Message build()
// Calculate value of "saved" field.
this.saved = this.savedBy.contains(getUserIdByChannelId(this.channelId));
return this;
// Handling the added challenge.
@JsonProperty("data")
public void setData(JsonNode data) throws JsonProcessingException
...
上面利用了JsonPOJOBuilder
注解的默认设置,即buildMethodName
的默认值为build
。
【讨论】:
我试过你的代码,但对象没有设置所有字段。我需要在build()
方法中设置所有字段吗?
不,只要有setter,就应该使用。您是否尝试设置几个断点以查看它们是否被命中?
我刚刚重新运行了我的沙盒测试,它们确实有效。您是否看到任何错误?反序列化使用如下:Message message = om.readValue(json, Message.class);
?
是的,我们像这样反序列化。我添加了我们在此类中的setData()
方法,当我添加您的方法build().
后,它会导致问题。我们使用它从 JSON 中的data
字段设置多个参数
在方法中添加@JsonProperty("data")
似乎可以解决您添加的问题。请尝试一下。以上是关于使用带有字段依赖的 Jackson 反序列化 JSON的主要内容,如果未能解决你的问题,请参考以下文章
Java Jackson将空字段反序列化为POJO中的默认空列表
spring/jackson:实现对保存JSON字符串的字段自动序列化和反序列化
使用 Jackson 反序列化:获取 Json 对象设置的字段列表