Java 使用具有字段依赖性的Jackson反序列化JSON

Java 使用具有字段依赖性的Jackson反序列化JSON,java,android,json,jackson,Java,Android,Json,Jackson,在我们的项目中,我们使用Jackson解析JSON。我们通过字段channelId设置字段保存的。问题是channelId字段的解析时间晚于保存的时间。因此,在我们想要设置fieldsavedfieldchannelId为空时。如何在JSON反序列化中设置字段依赖关系,以便在channelId之后设置字段saved 这是我们JSON数据的一部分: "message":{ "data":{ "text":"Some text"

在我们的项目中,我们使用Jackson解析JSON。我们通过字段
channelId
设置字段
保存的
。问题是
channelId
字段的解析时间晚于
保存的时间。因此,在我们想要设置field
saved
field
channelId
为空时。如何在JSON反序列化中设置字段依赖关系,以便在
channelId
之后设置字段
saved

这是我们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();
    }

    }

这有点老土,但是通过将
消息
类作为自己的反序列化生成器,您可以获得一种“准备创建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 {
       ...
    }
}
@JsonDeserialize(builder=Message.class)
公共类消息{
...
@JsonSetter(“保存人”)
公共void setSavedBy(Set savedBy){
//只需存储值以备将来使用。
this.savedBy=savedBy;
}
...
公共消息生成(){
//计算“已保存”字段的值。
this.saved=this.savedBy.contains(getUserIdByChannelId(this.channelId));
归还这个;
}
//处理额外的挑战。
@JsonProperty(“数据”)
public void setData(JsonNode数据)引发JsonProcessingException{
...
}
}

上面利用了
JsonPOJOBuilder
注释的默认设置,即
buildMethodName
的默认值是
build
,这有点黑客,但是通过将
消息
类作为自己的反序列化生成器,您可以得到一种“准备好创建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 {
       ...
    }
}
@JsonDeserialize(builder=Message.class)
公共类消息{
...
@JsonSetter(“保存人”)
公共void setSavedBy(Set savedBy){
//只需存储值以备将来使用。
this.savedBy=savedBy;
}
...
公共消息生成(){
//计算“已保存”字段的值。
this.saved=this.savedBy.contains(getUserIdByChannelId(this.channelId));
归还这个;
}
//处理额外的挑战。
@JsonProperty(“数据”)
public void setData(JsonNode数据)引发JsonProcessingException{
...
}
}


以上利用了
JsonPOJOBuilder
注释的默认设置,也就是说,
buildMethodName
的默认值是
build

是否可以从构造函数而不是通过设置字段来重建此值?如果字段
saved
始终依赖于
channelId
,那么为什么不在
setChannelId()中设置字段
saved
?不保证JSON顺序。例如,在一些手机中,我得到了正确的字段顺序,在其他手机中,顺序不同。在
setChannelId
中,我们可能还没有
saved_by
值。显示完整的json文件…是否可以从构造函数而不是通过设置字段来重建此文件?如果字段
saved
始终依赖于
channelId
,那么为什么不设置该字段
保存在
setChannelId()中
?不保证JSON顺序。例如,在一些手机中,我得到了正确的字段顺序,而在其他手机中,顺序是不同的。在
setChannelId
中,我们可能还没有
saved_by
值。显示完整的json文件…我尝试了您的代码,但没有设置所有字段。我需要在
build()
方法中设置所有字段吗?不,只要有setter,就应该使用它们。你有没有试着设置几个断点来看看它们是否被击中?我刚刚重新运行了我的沙盒测试,它们确实有效。你看到什么错误了吗?使用如下方式进行反序列化:
messagemessage=om.readValue(json,Message.class)?是的,我们像这样反序列化。我在这个类中添加了
setData()
方法,当我添加你的方法
build()时,这个方法导致了问题。
在添加方法
build()'之后,它不再被调用,但是没有被调用的
build()。我们使用它从JSONAdding
@JsonProperty(“数据”)
中的
data
字段设置多个参数,该方法似乎可以解决您添加的问题。请试一试。我试过你的代码,但没有设置所有字段。我需要在
build()
方法中设置所有字段吗?不,只要有setter,就应该使用它们。你有没有试着设置几个断点来看看它们是否被击中?我刚刚重新运行了我的沙盒测试,它们确实有效。你看到什么错误了吗?使用如下方式进行反序列化:
messagemessage=om.readValue(json,Message.class)?是的,我们像这样反序列化。我在这个类中添加了
setData()
方法,当我添加你的方法
build()时,这个方法导致了问题。
在添加方法
build()'之后,它不再被调用,但是没有被调用的
build()。我们使用它从JSONAdding
@JsonProperty(“数据”)
中的
data
字段设置多个参数,该方法似乎可以解决您添加的问题。请试一试。