如何使用Jackson来解析带有可变对象名称的JSON?

时间:2022-08-28 15:54:08

Google's cAdvisor API gives JSON output like this:

Google的cAdvisor API提供了如下的JSON输出:

{
  /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 this as 4 same-typed JSON objects with variable/anonymous names, held in an anonymous object.

我将此描述为4个具有变量/匿名名称的相同类型的JSON对象,保存在匿名对象中。

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

我的第一个想法是做mapper.readValue(response,Containers.class)之类的事情,其中​​:

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 all of the variations on this I can think of yield the same result: some permutation of 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"]), with ACCEPT_SINGLE_VALUE_AS_ARRAY = false .

但是我可以想到的所有变体产生相同的结果:com.xyz.Containers@45c7e403 [containerList = ]或com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:无法识别的字段“/的一些排列” system.slice / docker-13b18253fa70d837e9707a1c28e45a3573e82751f964b66d7c4cbc2256abc266.scope“(com.xyz.Containers),未标记为可忽略(一个已知属性:”containerList“])在[来源:java.io.StringReader@3d285d7e; line:1,column:97](通过引用链:com.xyz.Containers [“/ system.slice / docker-13b18253fa70d837e9707a1c28e45a3573e82751f964b66d7c4cbc2256abc266.scope”]),ACCEPT_SINGLE_VALUE_AS_ARRAY = false。

I've tried:

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

As well as 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, held in a non-array? What is this called?

如何解析具有变量/匿名名称的JSON对象,保存在非数组中?这个叫什么?

1 个解决方案

#1


2  

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

您可以按如下方式使用@JsonAnySetter注释,并将具有变量名称的对象放入Map 的映射中。 ,container>

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'}}}

#1


2  

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

您可以按如下方式使用@JsonAnySetter注释,并将具有变量名称的对象放入Map 的映射中。 ,container>

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'}}}