简体   繁体   中英

How to parse JSON object by Jackson if type of one field is unknown

I have a JSON response that I try to parse with Jackson, and type of one of fields is unknown.

Exapmle:

{"name" : "Catalina"}

OR

{"name" : {"First" : "Catalina", "Last" : "Kyle"}}

How I can deserialize that object into POJO:

class NamesHolder {
    public String singleName;
    public Map<String, String> nameMap;
}

This is synthetic example but I hope it clear for understanding.

In first case I want to have object with singleName == "Catalina" and nameMap == null, and vice versa in other case.

UPDATE

I am really sorry, at the end of day I misspelled the property name. In both cases they are the same: name.

Try making your name field an object:

class MyPojo {
  public Object name;
}

The you'll have to check at runtime to see if it deserialized as a String or as a Map.

The easiest way is to rename your POJO properties to the same which you have in JSON . See below example:

class NamesHolder {
    public String name;
    public Map<String, String> names;

    @Override
    public String toString() {
        return "NamesHolder{" +
                "name='" + name + '\'' +
                ", names=" + names +
                '}';
    }
}

If you do not want to rename properties you can use @JsonProperty annotation. See below example:

class NamesHolder {

    @JsonProperty("name")
    public String singleName;

    @JsonProperty("names")
    public Map<String, String> nameMap;

    @Override
    public String toString() {
        return "NamesHolder{" +
                "name='" + singleName + '\'' +
                ", names=" + nameMap +
                '}';
    }
}

Two above classes work for your JSON examples. See below program:

ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue("{\"names\" : {\"First\" : \"Catalina\", \"Last\" : \"Kyle\"}}", NamesHolder.class));
System.out.println(mapper.readValue("{\"name\" : \"Catalina\"}", NamesHolder.class));

which prints:

NamesHolder{name='null', names={First=Catalina, Last=Kyle}}
NamesHolder{name='Catalina', names=null}

EDIT 1


In this case you have to handle it manually using Object type. See below example:

public class JacksonTest {

    public static void main(String[] args) throws Exception {
        String json = "{\"name\" : \"Catalina\"}";
        ObjectMapper deserializerMapper = new ObjectMapper();
        NamesHolder namesHolder = deserializerMapper.readValue(json, NamesHolder.class);
        System.out.println(toString(namesHolder));

        json = "{\"name\" : {\"First\" : \"Catalina\", \"Last\" : \"Kyle\"}}";
        namesHolder = deserializerMapper.readValue(json, NamesHolder.class);
        System.out.println(toString(namesHolder));
    }

    private static String toString(NamesHolder namesHolder) {
        if (namesHolder.hasStringName()) {
            return "Type: String, Value: " + namesHolder.getStringName();
        } else if (namesHolder.hasMapNames()) {
            return "Type: Map, Value: " + namesHolder.getMapNames();
        }
        return "Type: Unknown, Value: " + namesHolder;
    }
}

class NamesHolder {

    public Object name;

    public boolean hasStringName() {
        return name instanceof String;
    }

    public String getStringName() {
        return name.toString();
    }

    public boolean hasMapNames() {
        return name instanceof Map;
    }

    public Map<String, String> getMapNames() {
        return (Map<String, String>) name;
    }

    @Override
    public String toString() {
        return String.valueOf(name);
    }
}

Above example prints:

Type: String, Value: Catalina
Type: Map, Value: {First=Catalina, Last=Kyle}

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