AniSkywalker AniSkywalker - 3 months ago 14
JSON Question

How can I store key-value pairs in JSON to be deserialized in Java?

I have data in JSON like so:

{
"foo": "bar",
"key": true,
"otherKey": 10
}


The key is a String and the value is a primitive (int, float, double, long, etc.) or a String. I want a simple, cast-free wrapper for each of the above.

Here's my wrapper class:

public final class Wrapper<T> {

private String key;
private T value;

}


If I specified
Wrapper[] wrappedValues
in an object to be deserialized, could I (using Jackson or GSON) deserialize the map to a list of the wrapper?

Thanks for any replies!

Answer

First of all, the input you specified can never be deserialized into an array or collection because it isn't one. a json collection of pairs of key-value looks like this

[
    {"foo": "bar"},
    {"key": true},
    {"otherKey": 10}
] 

and it can be deserialized into a collection of Wrappers if you make the class like this

public class Wrapper<T> {
    private String key;
    private T value;
    @JsonAnySetter
    public void set(String key, Object value) {
        this.key = key;
        this.value = (T)value;
    }
    public String toString() {  // just for nice printing
        return key + "=" + value.toString();
    }
}

and then you have to tell Jackson what is the generic type of the collection that will host the deserialized json:

public static void main(String[] args)
{
    String str = "[ {\"foo\": \"bar\"}, {\"key\": true}, {\"otherKey\": 10} ]";

    try (InputStream is = new ByteArrayInputStream(str.getBytes("UTF-8"))) {
        ObjectMapper objectMapper = new ObjectMapper();
        JavaType listWrappersType = objectMapper.getTypeFactory()
                .constructCollectionType(List.class, Wrapper.class);
        List<Wrapper> list = objectMapper.readValue(is, listWrappersType);
        System.out.println(list);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

output:

[foo=bar, key=true, otherKey=10]

If you just want to load pairs of key-value and not worry about type of value, then with Jackson you can load it all into Map<String, ?>

public static void main(String[] args)
{
    String str = "{ \"foo\": \"bar\", \"key\": true, \"otherKey\": 10 }";
    try (InputStream is = new ByteArrayInputStream(str.getBytes("UTF-8")))  {
        Map<String, ?> map = new ObjectMapper().readValue(is, Map.class);
        // print map contents
        System.out.println(map);
        // print type of map values
        System.out.print(entry.getKey() + "=" + entry.getValue().getClass()+ ", "));
        System.out.println();

entry.getValue().getClass())); } catch (Exception e) { e.printStackTrace(); } }

output

{foo=bar, key=true, otherKey=10}
foo=class java.lang.String, key=class java.lang.Boolean, otherKey=class java.lang.Integer,