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
307 views
in Technique[技术] by (71.8m points)

java - Jackson deserialization of type with different objects

I have a result from a web service that returns either a boolean value or a singleton map, e.g.

Boolean result:

{
    id: 24428,
    rated: false
}

Map result:

{
    id: 78,
    rated: {
        value: 10
    }
}

Individually I can map both of these easily, but how do I do it generically?

Basically I want to map it to a class like:

public class Rating {
    private int id;
    private int rated;
    ...
    public void setRated(?) {
        // if value == false, set rated = -1;
        // else decode "value" as rated
    }
}

All of the polymorphic examples use @JsonTypeInfo to map based on a property in the data, but I don't have that option in this case.


EDIT
The updated section of code:
@JsonProperty("rated")
public void setRating(JsonNode ratedNode) {
    JsonNode valueNode = ratedNode.get("value");
    // if the node doesn't exist then it's the boolean value
    if (valueNode == null) {
        // Use a default value
        this.rating = -1;
    } else {
        // Convert the value to an integer
        this.rating = valueNode.asInt();
    }
}
See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

No no no. You do NOT have to write a custom deserializer. Just use "untyped" mapping first:

public class Response {
  public long id;
  public Object rated;
}
// OR
public class Response {
  public long id;
  public JsonNode rated;
}
Response r = mapper.readValue(source, Response.class);

which gives value of Boolean or java.util.Map for "rated" (with first approach); or a JsonNode in second case.

From that, you can either access data as is, or, perhaps more interestingly, convert to actual value:

if (r.rated instanced Boolean) {
    // handle that
} else {
    ActualRated actual = mapper.convertValue(r.rated, ActualRated.class);
}
// or, if you used JsonNode, use "mapper.treeToValue(ActualRated.class)

There are other kinds of approaches too -- using creator "ActualRated(boolean)", to let instance constructed either from POJO, or from scalar. But I think above should work.


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

...