java - Jackson ObjectMapper 在转换为 POJO 时会忽略某些键
问题描述
这是我的课
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.*;
public class Util {
public static void main(String[] args) throws JsonProcessingException {
String json = "{ \"argA\" : 5, \"unneededkey\" : 6}";
ObjectMapper mapper = new ObjectMapper();
MyObject object3 = mapper.readValue(json, MyObject.class);
System.out.println(object3);
}
@ToString
@RequiredArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public static class MyObject {
public MyObject(int argA) {
this.argA = argA;
}
public MyObject(int argA, boolean argB) {
this.argA = argA;
this.argB = argB;
}
public MyObject(int argA, int argC, int argD) {
this.argA = argA;
this.argC = argC;
this.argD = argD;
}
public MyObject(int argA, String argE) {
this.argA = argA;
this.argE = argE;
}
public int argA = 1;
public boolean argB;
public int argC = 4;
public int argD = 5;
public String argE;
}
}
@JsonIgnoreProperties(ignoreUnknown = true) 有效,但这会忽略所有不需要的键。如果我只想忽略某些不需要的键,并且如果我得到一个不属于我的对象构造函数或在不需要的集合中的键,它会抛出异常。
解决方案
我建议的方法:
@JsonIgnoreProperties(ignoreUnknown = true)
将注释保留在您的班级上。
假设以下输入 JSON:
{
"argA": 5,
"unneededkey": 6,
"unexpectedKey": 99
}
创建一个包含允许的字段名称的集合(其中“允许”是您的类中存在的字段MyObject
,或者可以安全地忽略它):
Set<String> allowedFields = new HashSet(Arrays.asList(
"argA", "argB", "argC", "argD", "argE",
"unneededkey", "unneededkey2"));
然后对 JSON 进行如下处理:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(json);
Iterator<String> fieldNames = rootNode.fieldNames();
boolean fieldFailure = false;
Set<String> unexpectedFields = new HashSet();
while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
if (!allowedFields.contains(fieldName)) {
fieldFailure = true;
unexpectedFields.add(fieldName);
}
}
然后,您可以根据布尔值选择如何进行fieldFailure
。要么抛出异常(使用意外字段名称列表获取信息),要么以通常的方式创建对象:
MyObject object = mapper.readValue(json, MyObject.class);
不利的一面是它可能会遍历 JSON 两次——一次检查问题,再一次(假设没有问题)反序列化数据。
注意事项:
(1) 上面的代码假定一个扁平的 JSON 结构 - 没有嵌入对象 - 这与您在问题中的内容相匹配。为了获得更大的灵活性,您可以使用以下findKeys
方法递归访问所有节点:
Map<String, Object> treeMap = mapper.readValue(json, Map.class);
List<String> keys = Lists.newArrayList();
List<String> result = findKeys(treeMap, keys);
private List<String> findKeys(Map<String, Object> treeMap, List<String> keys) {
treeMap.forEach((key, value) -> {
if (value instanceof LinkedHashMap) {
Map<String, Object> map = (LinkedHashMap) value;
findKeys(map, keys);
}
keys.add(key);
});
return keys;
}
致谢:有关详细信息,请参阅此答案。
(2) 我考虑了一个自定义反序列化器:
public class MyDeserializer extends StdDeserializer<Util.MyObject> {
...
}
但是您仍然会遇到同样的问题 - 更不用说调用正确的构造函数所需的额外工作,具体取决于它找到的非空字段值的特定组合。
推荐阅读
- objective-c - 如何在没有 <__NSSingleObjectArrayI 0x600002f1df50> 之类的任何信息的情况下将 __NSSingleObjectArrayI 转换为 String
- excel - PowerQuery - 将文件名添加为列
- d3.js - d3.js 动态图片库示例
- javascript - 停止 onclick 事件处理程序
- bash - 在 bash 中为 cmd 命名,无需编辑脚本
- c - 为什么多线程不能提高这个程序中寻找素数的性能?
- google-apps-script - Gmail API 似乎将消息的时间戳四舍五入到分钟
- python - discord.py(重写)如何向特定频道发出命令
- python - 寻找一种检查数学运算的方法
- html - 如何使难度条动态化?