Java Jackson自定义反序列化程序中断其他字段的反序列化
我需要将JsonArray反序列化为布尔值。如果数组存在且不为空,则该值应设置为“true”。 问题是,我的自定义反序列化程序在运行时会中断其余字段的反序列化-它们被设置为null 对象:Java Jackson自定义反序列化程序中断其他字段的反序列化,java,json,serialization,jackson,Java,Json,Serialization,Jackson,我需要将JsonArray反序列化为布尔值。如果数组存在且不为空,则该值应设置为“true”。 问题是,我的自定义反序列化程序在运行时会中断其余字段的反序列化-它们被设置为null 对象: private static class TestObject { private String name; @JsonProperty("arr") @JsonDeserialize(using = Deserializer.class) private Boolean e
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;
}
}
如果我删除“arr”数组或将其移动到Json的底部,一切都很好。如果我把它放在顶部-TestObject{name='null',exists=true,logins=null}
有一个类似的问题(),但不幸的是它没有答案。
由于重新排列Json时代码工作正常,因此看起来并非所有字段都使用自定义反序列化程序,而是Jackson在执行自定义反序列化程序时停止反序列化。我的建议是不要将数组反序列化为布尔值。将数组反序列化为数组/列表/集合,并让
getExists
returnarr!=空值
或类似值
例如,如果要反序列化的JSON如下所示:
{
“arr”:[{“value”:“New”}],
“名称”:“名称”,
“登录”:36
}
按如下方式编写实体:
私有静态类TestObject
{
私人名单;
//为简洁起见,删除了其他getter/setter
公共布尔getExists()
{
返回arr!=null&!arr.isEmpty();
}
}
反序列化程序可能对数组的内容不感兴趣,但仍必须在解析器上提前读取标记
您可以立即读取arr
的值,并根据集合的大小决定:
@Override
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
JsonNode node = jp.getCodec().readTree(jp);
return node.size() != 0;
}
决定集合的大小而不是集合的存在是必要的,因为字符串化对象包含arr或反序列化器。反序列化()从不执行。在这种情况下,属性exist
将为null
。因此,唯一可能表达的语义是不存在的空集合
出于好奇,我尝试了第二种更明确的方法来保持解析器正常运行。对于现实世界的使用,上述版本绝对是可取的
@Override
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
if (jp.currentToken() == JsonToken.START_ARRAY) {
jp.nextToken();
int recursionLevel = 1;
while(recursionLevel > 0) {
switch (jp.currentToken()) {
case START_ARRAY:
// just in case of nested arrays
recursionLevel++;
break;
case END_ARRAY:
recursionLevel--;
break;
}
jp.nextToken();
}
return true;
}
return false;
}
实际上还有第三种方法,适合我的情况——当JsonArray不丢失时,它将始终包含至少一个元素,因此我只需要正确地推进读取标记,然后返回true
:
if (jp.getCurrentToken().equals(JsonToken.START_ARRAY)) {
while (!jp.getCurrentToken().equals(JsonToken.END_ARRAY)){
jp.nextToken();
}
}
return true;
除非您不需要数组的内容来做一些额外的工作,否则移动标记比readTree
快几毫秒。我的建议是不要将数组反序列化为布尔值。将数组反序列化为数组/列表/集合,并让getExists
returnarr!=null
或类似的东西。@Paul这确实有效,谢谢你的主意,不知怎的,我没有想到这一点。问题是它看起来有点难看和晦涩,但如果没有其他方法,我会这样做。有时你必须从两个难看的解决方案中选择更漂亮的:)我很高兴我能帮上忙…我会回答我的评论。这是正确的解决方案JsonDeserializer
javadoc提到,在从反序列化程序返回之前,必须将读取标记移动到下一个元素,以便Jackson可以开始处理下一个元素。在我的例子中,它是一个数组,所以像我尝试过的那样移动它一次是不够的,在到达END\u array
之前,必须移动它多次readTree
,据我从javadoc所知,它读取整个数组,构建一个树,并在一个包中推进读取标记。
if (jp.getCurrentToken().equals(JsonToken.START_ARRAY)) {
while (!jp.getCurrentToken().equals(JsonToken.END_ARRAY)){
jp.nextToken();
}
}
return true;