Adam Vukich
Adam Vukich

Reputation: 303

Jackson deserialization from variable types in JSON

I am trying to deserialize JSON using Jackson that contains a list of items in which individual list items can be Strings or they can be a sublist of Strings. What is the preferred way to deal with this situation?

Example Json:

"anObject" : {
    "stuff": [
        "a",
        "b",
        ["x","y","z"]
    ]
}

I got it working with the following:

public AnObject {
    private List<Object> stuff;
}

TypeReference<HashMap<String, List<AnObject>>> typeRef =
        new TypeReference<HashMap<String, List<AnObject>>>() {};
try {
    HashMap<String, List<AnObject>> map = mapper.readValue(json, typeRef);
} catch (IOException e) {
    e.printStackTrace();
}

BUT, I feel like this is not the ideal way. Can someone share with me how I might better deal with this? Thanks in advance!

Upvotes: 2

Views: 356

Answers (1)

Mark Probst
Mark Probst

Reputation: 7367

You can use quicktype to generate the code to deserialize this. Basically you'll have to write your own deserializer for the type "string or array of strings":

package io.quicktype;

import java.util.Map;
import java.io.IOException;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.*;

@JsonDeserialize(using = Stuff.Deserializer.class)
@JsonSerialize(using = Stuff.Serializer.class)
public class Stuff {
    public String stringValue;
    public String[] stringArrayValue;

    static class Deserializer extends JsonDeserializer {
        @Override
        public Stuff deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            Stuff value = new Stuff();
            switch (jsonParser.getCurrentToken()) {
            case VALUE_STRING:
                value.stringValue = jsonParser.readValueAs(String.class);
                break;
            case START_ARRAY:
                value.stringArrayValue = jsonParser.readValueAs(String[].class);
                break;
            default: throw new IOException("Cannot deserialize Stuff");
            }
            return value;
        }
    }

    static class Serializer extends JsonSerializer {
        @Override
        public void serialize(Stuff obj, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (obj.stringValue != null) {
                jsonGenerator.writeObject(obj.stringValue);
                return;
            }
            if (obj.stringArrayValue != null) {
                jsonGenerator.writeObject(obj.stringArrayValue);
                return;
            }
            throw new IOException("Stuff must not be null");
        }
    }
}

Upvotes: 1

Related Questions