Deserialize duplicate keys to list using Jackson

为君一笑 提交于 2021-01-27 17:16:17

问题


I'm trying to deserialize json into object. However, the json has duplicate keys. I cannot change the json and I would like to use Jackson to change duplicate keys to a list.

Here is an example of the json I retrieve:

{
  "myObject": {
    "foo": "bar1",
    "foo": "bar2"
  }
}

And here is what I would like after deserialization:

{
  "myObject": {
    "foo": ["bar1","bar2"]
  }
}

I created my class like so:

public class MyObject {
    private List<String> foo;
    // constructor, getter and setter
}

I tried to use DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY from objectMapper but all it does is taking the last key and add it to the list like this:

{
  "myObject": {
    "foo": ["bar2"]
  }
}

Here is my objectMapperconfiguration:

new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

Is there a way to deserialize duplicate keys to a list using Jackson?


回答1:


You need to use com.fasterxml.jackson.annotation.JsonAnySetter annotation:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        Root root = mapper.readValue(jsonFile, Root.class);
        root.getMyObject().getFoos().forEach(System.out::println);
    }
}

class Root {

    private MyObject myObject;

    // getters, setters, toString
}

class MyObject {

    private List<String> foos = new ArrayList<>();

    @JsonAnySetter
    public void manyFoos(String key, String value) {
        foos.add(value);
    }

    // getters, setters, toString
}

On Java side you have a list with values:

bar1
bar2



回答2:


Supplementing answer from @Michał Ziober: if you need to handle case of mixing single values and lists/maps:

{  
  "myObject": {
     "foo": "bar1",
     "foo": ["bar2", "bar3"],
     "foo": {"bar": "baz"}
  }
}

this can be done in the same manyFoos:

@SuppressWarnings("unchecked")
@JsonAnySetter
public void manyFoos(String key, Object value) {
    System.out.println("key = " + key + " -> " + value.getClass() + ": " + value);
    if (value instanceof String)
        foos.add((String)value);
    else if (value instanceof Collection<?>) {
        foos.addAll((Collection<? extends String>)value);
    }
    else if (value instanceof Map<?, ?>) {
        Map<? extends String, ? extends String> subFoo = (Map<? extends String, ? extends String>) value;
        subFoo.entrySet().forEach(e -> foos.add(e.getKey() + ":" + e.getValue()));  
    }
}

Then the result will be:

{
  "myObject" : {
    "foos" : [ "bar1", "bar2", "bar3", "bar:baz" ]
  }
}


来源:https://stackoverflow.com/questions/61528937/deserialize-duplicate-keys-to-list-using-jackson

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!