Vladimir Tagakov
Vladimir Tagakov

Reputation: 107

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.

Upvotes: 1

Views: 2631

Answers (2)

Michał Ziober
Michał Ziober

Reputation: 38655

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}

Upvotes: 0

ccleve
ccleve

Reputation: 15799

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.

Upvotes: 2

Related Questions