简体   繁体   English

如何使用Jackson在有条件的情况下(在其他属性上)反序列化属性?

[英]How to deserialize property conditionally (on other properties) with Jackson?

I am trying to create a POJO as a template to reflect incoming JSON's onto. 我试图创建一个POJO作为模板以反映传入的JSON。

public class Item {
    @JsonProperty("special")
    @NotNull
    private Boolean special;

    @JsonProperty("specialCriteria")
    private SpecialCriteria specialCriteria;
 }

I want to invalidate the request with an IllegalArgumentException if special is true and no specialCriteria parameter is provided in the JSON. 如果special为true,并且JSON中没有提供specialCriteria参数,我想使用IllegalArgumentException使请求无效。

I have tried using @JsonSetter the following but received a HTTP 200 accepted when I made a JSON request with special being true and no specialCriteria included. 我已经尝试使用以下@JsonSetter ,但是在发出JSON请求时收到了HTTP 200接受,其中的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.");
}

I also tried the following: 我还尝试了以下方法:

public void setSpecialCriteria(@JsonProperty("specialCriteria") SpecialCriteria specialCriteria, @JsonProperty("special") Boolean special) {

How do I tell Jackson to set these restrictions when creating the pojo? 创建pojo时,如何告诉Jackson设置这些限制?

Follow up : If I wanted to add additional restrictions on parameters within the SpecialCriteria class, would using @Valid still be adhered to with your given solution? 后续:如果我想对SpecialCriteria类中的参数添加其他限制,是否可以在给定的解决方案中坚持使用@Valid

Your approach presents two important issues : 您的方法存在两个重要问题:

1) Your way of validating that is in a specific setter is not consistent because you don't know in which orders the fields will be set by Jackson during the deserialization process (JSON to java Object). 1)您在特定设置器中进行验证的方式不一致,因为您不知道在反序列化过程(JSON到Java Object)中,Jackson将按哪些顺序设置字段。 So a field may be null because it was not still initialized. 因此,字段可能为null因为它尚未初始化。 So the validation may be inconsistent . 因此,验证可能不一致

2) Jackson is optimized to set a field with setter during the deserialization only if the value is present. 2)仅在存在值的情况下,Jackson进行了优化,以在反序列化期间使用setter设置字段。 It parses the JSON and deserializes the discovered token, not more, not less. 它解析JSON并反序列化发现的令牌(不多也不少)。

So if the value is empty in the JSON, the setter will never be invoked on the Java object. 因此,如果JSON中的值为空,则setter将永远不会在Java对象上被调用。
The information is not easy to spot but that is here : com.fasterxml.jackson.databind.deser.BeanDeserializer : 该信息不容易发现,但位于以下位置: 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());
}

Here p.nextToken(); 在这里p.nextToken(); returns the next token to deserialize according to the received JSON. 根据接收到的JSON返回下一个要反序列化的令牌。

JSONParser.nextToken() is defined as : JSONParser.nextToken()定义为:

Main iteration method, which will advance stream enough to determine type of the next token, if any. 主迭代方法,它将使流足够推进以确定下一个令牌的类型(如果有)。 If none remaining (stream has no content other than possible white space before ending), null will be returned. 如果没有剩余的内容(流在结束之前除了可能的空白以外没有其他内容),将返回null。


Long story short, you have to use an API or a way designed to validate model rather that trying to perform a validation logic inside the setters that is not the right approach. 简而言之,您必须使用API​​或旨在验证模型的方法,而不是尝试在setter内执行验证逻辑,而不是正确的方法。

Some options : 一些选择:

1) Bean Validation API . 1) Bean验证API That could be helpful : http://hibernate.org/validator/documentation/getting-started/ . 这可能会有所帮助: http : //hibernate.org/validator/documentation/getting-started/
That is very good for annotation constraints on fields. 这对字段的注释约束非常有用。

2) For structured validations like in your code : validations that differ according to some rules, you could not rely on annotation constraints on fields. 2)对于代码中的结构化验证:根据某些规则的验证有所不同,您不能依赖字段的注释约束。
So either create validation functions or as alternative you could include the logic validation in the constructor of the class. 因此,要么创建验证函数,要么可以将逻辑验证包括在类的构造函数中。 That is possible if you annotate the constructor with @JsonCreator . 如果使用@JsonCreator注释构造函数,则有@JsonCreator

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM