Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.8k views
in Technique[技术] by (71.8m points)

json - Jackson JsonTypeInfo.As.EXTERNAL_PROPERTY doesn't work as expected

I am using Jackson to parse JSON that I have no control over. The JSON looks like this:

{
    "status":"0"
    "type":"type1"
    "info": {
       // additional fields
    }
}

My class looks like this

public class Response {
    private String status;
    private String type;
    private Info info
}

The subclass of Info that I use depends on the type property, so my mapping for info is

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
@JsonSubTypes(value = {
        @JsonSubTypes.Type(value = Type1Info.class, name = "type1"),
        @JsonSubTypes.Type(value = Type2Info.class, name = "type2") })
public abstract class Info {
    // some fields
}

As far as I can tell this is the correct way to use type info when the distinguishing element is at the same level as the element that has to be casted. But this doesn't work, I always get the same error:

com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'type' that is to contain type id

If I change EXTERNAL_PROPERTY to PROPERTY I still get the same error. Is my understanding of EXTERNAL_PROPERTY wrong?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

From Javadoc:

Inclusion mechanism similar to PROPERTY, except that property is included one-level higher in hierarchy, i.e. as sibling property at same level as JSON Object to type. Note that this choice can only be used for properties, not for types (classes). Trying to use it for classes will result in inclusion strategy of basic PROPERTY instead.

Noticed that can only be used for properties is bolded. Source: JsonTypeInfo.As.EXTERNAL_PROPERTY.

So, you have to move all annotation from Info class to property info or setInfo method in Response class.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
@JsonSubTypes(value = { @JsonSubTypes.Type(value = Type1Info.class, name = "type1"),
        @JsonSubTypes.Type(value = Type2Info.class, name = "type2") })
public void setInfo(Info info) {
    this.info = info;
}

For me, you should also remove type property from Response class. It will be generated dynamically during serialization process. In deserialization you do not need it because Jackson cares about types. Your class could look like this:

class Response {

    private String status;
    private Info info;

    //getters, setters
}

See also this question: JSON nest class data binding.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...