简体   繁体   中英

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.

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.

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("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?

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?

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). So a field may be null because it was not still initialized. 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. It parses the JSON and deserializes the discovered token, not more, not less.

So if the value is empty in the JSON, the setter will never be invoked on the Java object.
The information is not easy to spot but that is here : 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(); returns the next token to deserialize according to the received JSON.

JSONParser.nextToken() is defined as :

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.


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.

Some options :

1) Bean Validation API . That could be helpful : 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.
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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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