Java Gson 解析 Json 对象到数组

Java Gson parse Json object to array

我正在尝试使用 Java 中的 Gson 库解析以下 Json。当使用其他语言(例如 C#)时,这个 JSON 被解析为一个数组,但是 Gson 似乎将其转换为一组 java 属性(老实说,这对我来说更有意义)。有谁知道我是否可以改变 Gson 库的这种行为?

{
  "Outer": {
    "0": {
      "Attr1": 12345,
      "Attr2": 67890
    },
    "1": {
      "Attr1": 54321,
      "Attr2": 09876
    }
  }
}

下面的代码演示了 Gson 如何将数组解析为 JsonObject。明确地说,我意识到我已经将 outer 引用为 JsonObject,但我这样做只是为了演示代码。如果我尝试将 outer 引用为 JsonArray,代码将失败。

String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder()
            .disableHtmlEscaping()
            .setLenient()
            .serializeNulls()
            .create();

JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");

System.out.println(outer);
System.out.println(outer.isJsonArray());

结果:

{"0":{"Attr1":12345,"Attr2":67890},"1":{"Attr1":54321,"Attr2":"09876"}}
false

//编辑 我使用这个当前简单的 Json 作为示例,但是我对这段代码的应用将解析 Json 的变化和未知形状。因此,我需要 Gson 自动将其解析为数组,以便 isJsonArray returns true.

我假设您的 JsonObject 是一个 POJO class,例如:

public Inner[] outer;

如果您想要一个对象数组,您可以将代码更改为:

Inner[] jo = gson.fromJson(json, Inner[].class);

请参考以下代码 1.To 获取对象数组 (outerArray) 2.You 可以提取 JsonArray (outerJsonArray),其中包含 Outer 中的内部对象的值(以防键对进一步使用不重要)

String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().serializeNulls().create();
JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");

Object[] outerArray = outer.entrySet().toArray();
// outerArray: [0={"Attr1":12345,"Attr2":67890}, 1={"Attr1":54321,"Attr2":"09876"}]

JsonArray outerJsonArray = new JsonArray();
outer.keySet().stream().forEach(key -> {
outerJsonArray.add(outer.get(key));
});
//jsonArray=[{"Attr1":12345,"Attr2":67890},{"Attr1":54321,"Attr2":"09876"}]

System.out.println(outer);
System.out.println(outerJsonArray.isJsonArray() + " " + outerJsonArray);

TL;DR: 请参阅底部的 "Using Deserializer" 部分以直接解析为数组。


JSON 不包含任何数组。数组将使用 [...] JSON 语法。

通常,JSON 对象会映射到 POJO,name/value 对中的 name 映射到 POJO 的字段。

但是,JSON 对象也可以映射到 Map,这在名称是动态的时候特别有用,因为 POJO 字段是静态的。

使用地图

以数值作为名称的 JSON 对象可以映射到 Map<Integer, ?>,例如要将 JSON 解析为 POJO,请这样做:

class Root {
    @SerializedName("Outer")
    public Map<Integer, Outer> outer;
    @Override
    public String toString() {
        return "Root[outer=" + this.outer + "]";
    }
}
class Outer {
    @SerializedName("Attr1")
    public int attr1;
    @SerializedName("Attr2")
    public int attr2;
    @Override
    public String toString() {
        return "Outer[attr1=" + this.attr1 + ", attr2=" + this.attr2 + "]";
    }
}

测试

Gson gson = new GsonBuilder().create();
Root root;
try (BufferedReader in = Files.newBufferedReader(Paths.get("test.json"))) {
    root = gson.fromJson(in, Root.class);
}
System.out.println(root);

输出

Root[outer={0=Outer[attr1=12345, attr2=67890], 1=Outer[attr1=54321, attr2=9876]}]

获取数组

然后您可以将辅助方法添加到 Root class 以将其作为数组获取:

public Outer[] getOuterAsArray() {
    if (this.outer == null)
        return null;
    if (this.outer.isEmpty())
        return new Outer[0];
    int maxKey = this.outer.keySet().stream().mapToInt(Integer::intValue).max().getAsInt();
    Outer[] arr = new Outer[maxKey + 1];
    this.outer.forEach((k, v) -> arr[k] = v);
    return arr;
}

测试

System.out.println(Arrays.toString(root.getOuterAsArray()));

输出

[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]

使用解串器

但是,如果在解析时转换为数组可能会更有用,因此您需要编写一个 JsonDeserializer 并使用 @JsonAdapter:[=28= 告诉 Gson ]

class Root {
    @SerializedName("Outer")
    @JsonAdapter(OuterArrayDeserializer.class)
    public Outer[] outer;

    @Override
    public String toString() {
        return "Root[outer=" + Arrays.toString(this.outer) + "]";
    }
}
class OuterArrayDeserializer implements JsonDeserializer<Outer[]> {
    @Override
    public Outer[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        // Parse JSON array normally
        if (json.isJsonArray())
            return context.deserialize(json, Outer[].class);

        // Parse JSON object using names as array indexes
        JsonObject obj = json.getAsJsonObject();
        if (obj.size() == 0)
            return new Outer[0];
        int maxKey = obj.keySet().stream().mapToInt(Integer::parseInt).max().getAsInt();
        Outer[] arr = new Outer[maxKey + 1];
        for (Entry<String, JsonElement> e : obj.entrySet())
            arr[Integer.parseInt(e.getKey())] = context.deserialize(e.getValue(), Outer.class);
        return arr;
    }
}

相同Outer class和上面的测试代码。

输出

Root[outer=[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]]
Jackson – Marshall String to JsonNode will be useful in your case.with following pom:- 


    //POM FILE


        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>

//JAVA CODE
    //read json file data to String


     byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

        //create ObjectMapper instance
        ObjectMapper objectMapper = new ObjectMapper();

        //read JSON like DOM Parser
        JsonNode rootNode = objectMapper.readTree(jsonData);
        JsonNode idNode = rootNode.path("id");
        System.out.println("id = "+idNode.asInt());

        JsonNode phoneNosNode = rootNode.path("phoneNumbers");
        Iterator<JsonNode> elements = phoneNosNode.elements();
        while(elements.hasNext()){
            JsonNode phone = elements.next();
            System.out.println("Phone No = "+phone.asLong());
        }

您可以使用 JsonNode class 的方法 findParent findValue 和 findPath,与另一个解析库相比,它们减少了您的代码。