java - 如何使用杰克逊有条件地(在其他属性上)反序列化属性?
问题描述
我正在尝试创建一个 POJO 作为模板来反映传入的 JSON。
public class Item {
@JsonProperty("special")
@NotNull
private Boolean special;
@JsonProperty("specialCriteria")
private SpecialCriteria specialCriteria;
}
我想用IllegalArgumentException
if special 为 true 并且 JSON 中没有提供 specialCriteria 参数来使请求无效。
我尝试使用@JsonSetter
以下内容,HTTP 200
但当我发出一个 JSON 请求时收到了接受,其中 special 为 true 且未包含 specialCriteria。
@JsonSetter("specialCriteria")
public void setSpecialCriteria(@JsonProperty("specialCriteria") SpecialCriteria specialCriteria) {
if(this.special == false)
specialCriteria = null;
if(this.special == true && specialCriteria != null)
this.specialCriteria = specialCriteria;
else
throw new IllegalArgumentException("Invalid JSON. Please provide Special Criteria.");
}
我还尝试了以下方法:
public void setSpecialCriteria(@JsonProperty("specialCriteria") SpecialCriteria specialCriteria, @JsonProperty("special") Boolean special) {
我如何告诉杰克逊在创建 pojo 时设置这些限制?
跟进:如果我想在 SpecialCriteria 类中添加额外的参数限制,@Valid
您给定的解决方案是否仍会坚持使用?
解决方案
您的方法提出了两个重要问题:
1)您在特定设置器中的验证方式不一致,因为您不知道杰克逊在反序列化过程(JSON 到 java 对象)期间将按哪些顺序设置字段。所以一个字段可能是null
因为它还没有被初始化。所以验证可能不一致。
2)Jackson 被优化为在反序列化期间使用 setter 设置字段,仅当值存在时。它解析 JSON 并反序列化发现的令牌,不多也不少。
因此,如果 JSON 中的值为空,则永远不会在 Java 对象上调用 setter。
该信息不容易发现,但就是在这里:
com.fasterxml.jackson.databind.deser.BeanDeserializer
:
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
// common case first
if (p.isExpectedStartObjectToken()) {
if (_vanillaProcessing) {
return vanillaDeserialize(p, ctxt, p.nextToken());
}
// 23-Sep-2015, tatu: This is wrong at some many levels, but for now... it is
// what it is, including "expected behavior".
p.nextToken();
if (_objectIdReader != null) {
return deserializeWithObjectId(p, ctxt);
}
return deserializeFromObject(p, ctxt);
}
return _deserializeOther(p, ctxt, p.getCurrentToken());
}
这里 p.nextToken();
根据接收到的 JSON 返回下一个要反序列化的 token。
主迭代方法,它将推进流足以确定下一个令牌的类型(如果有)。如果没有剩余(流在结束前除了可能的空白之外没有其他内容),将返回 null。
长话短说,您必须使用 API 或旨在验证模型的方法,而不是尝试在 setter 中执行验证逻辑,这是不正确的方法。
一些选项:
1) Bean 验证 API。这可能会有所帮助:http ://hibernate.org/validator/documentation/getting-started/ 。
这对于字段的注释约束非常有用。
2) 对于代码中的结构化验证:根据某些规则不同的验证,您不能依赖字段上的注释约束。
因此,要么创建验证函数,要么作为替代方案,您可以在类的构造函数中包含逻辑验证。如果你用 注释构造函数,这是可能的@JsonCreator
。
推荐阅读
- c++ - 在从 int 到非标量类型“point”的 c++ 转换中出现错误:
- reactjs - Apollo useSubscription 挂钩不发出新数据
- android - 问题用房间数据库填充微调器 android kotlin
- r - r Plotly 无法让 xaxis tickmode="array" 为日期工作
- node.js - 使用 NodeJS 插入数据库
- python - 一个接受两个参数的函数 - 一个函数 f 和一个列表 l 并将该函数应用于列表的元素并将它们作为列表返回
- oracle - 我可以在 oracle pl/sql developer 中使用此代码吗
- javascript - 想在javascript中使用面部的位置来控制玩家
- python - 如何在 python 中找到 .builtin 函数的帮助?
- python - Discord.py:如何在不和谐机器人上添加状态?