我需要将JsonArray反序列化为布尔值。如果数组存在且不为空,则该值应设置为" true"。 问题是,我的自定义反序列化器在功能上打破了其余字段的反序列化 - 它们被设置为null。
对象:
private static class TestObject {
private String name;
@JsonProperty("arr")
@JsonDeserialize(using = Deserializer.class)
private Boolean exists = null;
private Integer logins;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getExists() {
return exists;
}
public void setExists(boolean exists) {
this.exists = exists;
}
public Integer getLogins() {
return logins;
}
public void setLogins(Integer logins) {
this.logins = logins;
}
@Override
public String toString() {
return "TestObject{" +
"name='" + name + '\'' +
", exists=" + exists +
", logins=" + logins +
'}';
}
}
解串器:
public class Deserializer extends JsonDeserializer<Boolean> {
@Override
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
if (jp.getCurrentToken() == JsonToken.START_ARRAY) {
return true;
}
return false;
}
}
测试
@Test
public void test() throws JsonParseException, IOException {
Boolean result = deserialize();
}
private Boolean deserialize() throws IOException, JsonParseException,
JsonProcessingException {
TestObject testObject = mapper.readValue("{\n" +
" \"arr\": [\n" +
" {\"value\": \"New\"}\n" +
" ],\n" +
" \"name\": \"name\",\n" +
" \"logins\": 36" +
"}",
TestObject.class);
System.out.println(testObject.toString());
return testObject.getExists();
}
如果我删除&#34; arr&#34;数组或移动到Json的底部,一切都很好。如果我把它放在顶部 - TestObject{name='null', exists=true, logins=null}
。
有一个类似的问题(Jackson Custom Deserializer breaks default ones),但不幸的是它没有答案。 由于代码在重新排列Json时正常工作,所以看起来并不像自定义反序列化器用于所有字段,而是Jackson在执行自定义反序列化器时停止反序列化。
答案 0 :(得分:1)
我的建议是不要将数组反序列化为布尔值。将数组反序列化为数组/列表/集,并让getExists
返回arr != null
或其他类似的数组。
例如,如果您要反序列化的JSON如下所示:
{
"arr": [{"value": "New"}],
"name": "name",
"logins": 36
}
像这样写下您的实体:
private static class TestObject
{
private List<Map<String, String>> arr;
// other getters/setters removed for brevity
public boolean getExists()
{
return arr !=null && !arr.isEmpty();
}
}
答案 1 :(得分:1)
您的反序列化程序可能对数组的内容不感兴趣,但仍必须提升解析器上的读取标记。
您可以立即阅读arr
的值,并根据集合的大小决定:
@Override
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
JsonNode node = jp.getCodec().readTree(jp);
return node.size() != 0;
}
确定集合的 size 而不是集合的存在是必要的,因为你的字符串化对象包含一个arr或{{1}永远不会执行。在这种情况下,属性Deserializer.deserialize()
将为exist
。因此,表达的唯一可能语义不存在是一个空集合。
为了好奇,我尝试了第二种更明确的方法来保持解析器的正常运行。对于现实世界的使用,上述版本绝对是首选。
null
答案 2 :(得分:0)
实际上有第三种方法可以做到这一点,这符合我的情况 - 当JsonArray没有丢失时,它总是至少包含一个元素,所以我需要的是正确推进读取标记,然后返回true
:
if (jp.getCurrentToken().equals(JsonToken.START_ARRAY)) {
while (!jp.getCurrentToken().equals(JsonToken.END_ARRAY)){
jp.nextToken();
}
}
return true;
除非您不需要数组内容进行其他工作,否则只需移动标记比readTree
快几毫秒。