How can I use Jackson to parse JSON with variable object names?

The Google cAdvisor API provides JSON output as follows:

{ /system.slice/docker-13b18253fa70d837e9707a1c28e45a3573e82751f964b66d7c4cbc2256abc266.scope: {}, /system.slice/docker-747f797d19931b4ef33cda0c519f935b592a0b828d16b8cafc350568ab2c1d28.scope: {}, /system.slice/docker-bf947bfabf61cd5168bd599162cf5f5c2ea2350eece1ded018faebf598f7ee5b.scope: {}, /system.slice/docker-e8e02d508400438603151dd462ef036d59fada8239f66be8e64813880b59a77d.scope: { name: "/system.slice/docker-e8e02d508400438603151dd462ef036d59fada8239f66be8e64813880b59a77d.scope", aliases: [...], namespace: "docker", spec: {...}, stats: [...] } } 

I would describe it as 4 identically typed JSON objects with variable / anonymous names stored in an anonymous object.

My first thought would just do something like mapper.readValue(response, Containers.class) , where:

 public class Containers extends BaseJsonObject { @JsonProperty public List<Container> containerList; } 

and

 public class Container extends BaseJsonObject { @JsonProperty private String name; @JsonProperty public String[] aliases; @JsonProperty private String namespace; @JsonProperty private String spec; @JsonProperty public Stats[] stats; } 

But I can imagine all the variations of this to get the same result: some permutation com.xyz.Containers@45c7e403 [containerList=<null>] or com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "/system.slice/docker-13b18253fa70d837e9707a1c28e45a3573e82751f964b66d7c4cbc2256abc266.scope" (class com.xyz.Containers), not marked as ignorable (one known property: "containerList"]) at [Source: java.io.StringReader@3d285d7e ; line: 1, column: 97] (through reference chain: com.xyz.Containers["/system.slice/docker-13b18253fa70d837e9707a1c28e45a3573e82751f964b66d7c4cbc2256abc266.scope"]) com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "/system.slice/docker-13b18253fa70d837e9707a1c28e45a3573e82751f964b66d7c4cbc2256abc266.scope" (class com.xyz.Containers), not marked as ignorable (one known property: "containerList"]) at [Source: java.io.StringReader@3d285d7e ; line: 1, column: 97] (through reference chain: com.xyz.Containers["/system.slice/docker-13b18253fa70d837e9707a1c28e45a3573e82751f964b66d7c4cbc2256abc266.scope"]) , with ACCEPT_SINGLE_VALUE_AS_ARRAY = false .

I tried:

  • mapper.readValue(response, Container[].class)
  • mapper.readValue(response, Containers.class)
  • mapper.readValues(jsonParser, Container.class)

In addition to the following configurations:

  • mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  • mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

How can I parse JSON objects with variable / anonymous names stored in a non-array? What is called?

+5
source share
1 answer

You can use the @JsonAnySetter annotation as follows and put objects with variable names in a Map<String, Container> map.

Here is an example:

 public class JacksonVariableNames { static final String JSON = "{\n" + " \"a\": {\n" + " \"value\": \"1\"\n" + " },\n" + " \"b\": {\n" + " \"value\": \"2\"\n" + " },\n" + " \"c\": {\n" + " \"value\": \"3\"\n" + " }\n" + "}"; static class Value { private final String value; @JsonCreator Value(@JsonProperty("value") final String value) {this.value = value;} @Override public String toString() { return "Value{" + "value='" + value + '\'' + '}'; } } static class Values { private final Map<String, Value> values = new HashMap<>(); @JsonAnySetter public void setValue(final String property, final Value value) { values.put(property, value); } @Override public String toString() { return "Values{" + "values=" + values + '}'; } } public static void main(String[] args) throws IOException { final ObjectMapper mapper = new ObjectMapper(); System.out.println(mapper.readValue(JSON, Values.class)); } } 

Output:

 Values{values={a=Value{value='1'}, b=Value{value='2'}, c=Value{value='3'}}} 
+2
source

All Articles