简体   繁体   English

Java Gson 解析 Json ZA8CFDE6331BD59EB2AC96F8911C4B66Z 到数组

[英]Java Gson parse Json object to array

I'm trying to parse the below Json using the Gson lib in Java.我正在尝试使用 Java 中的 Gson 库来解析以下 Json。 When using other languages, such as C#, this JSON is parsed into an array, however it seems Gson converts this into a set of java attributes (which to be honest, makes more sense to me). When using other languages, such as C#, this JSON is parsed into an array, however it seems Gson converts this into a set of java attributes (which to be honest, makes more sense to me). Does anyone know if I can change this behaviour of the Gson lib?有谁知道我是否可以更改 Gson 库的这种行为?

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

The below code demonstrates how Gson parses the array as a JsonObject.下面的代码演示了 Gson 如何将数组解析为 JsonObject。 To be clear, I realise I've referenced outer as a JsonObject but I was just doing this to demonstrate the code.需要明确的是,我意识到我已经将outer引用为JsonObject ,但我这样做只是为了演示代码。 If I try and reference outer as an JsonArray , the code fails.如果我尝试将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());

Result:结果:

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

//edit I'm using this current simple Json as an example, however my application of this code will be to parse Json that's of varying and unknown shape. //编辑我使用这个当前简单的 Json 作为示例,但是我对这段代码的应用将解析 Json,它具有不同的和未知的形状。 I therefore need Gson to automatically parse this to an array so that the isJsonArray returns true .因此,我需要 Gson 自动将其解析为数组,以便isJsonArray返回true

TL;DR: See "Using Deserializer" section at the bottom for parsing straight to array. TL;DR:请参阅底部的“使用反序列化器”部分以直接解析为数组。


That JSON does not contain any arrays. JSON 不包含任何 arrays。 An array would use the [...] JSON syntax.数组将使用[...] JSON 语法。

Normally, a JSON object would map to a POJO, with the name in the name/value pairs mapping to a field of the POJO.通常,JSON object 将 map 映射到 POJO, name /值对中的名称映射到 POJO 的字段。

However, a JSON object can also be mapped to a Map , which is especially useful when the names are dynamic, since POJO fields are static. However, a JSON object can also be mapped to a Map , which is especially useful when the names are dynamic, since POJO fields are static.

Using Map使用 Map

The JSON object with numeric values as names can be mapped to a Map<Integer, ?> , eg to parse that JSON to POJOs, do it like this: JSON object 可以将数值作为名称映射到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 + "]";
    }
}

Test测试

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);

Output Output

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

Get as Array获取为数组

You can then add a helper method to the Root class to get that as an array:然后,您可以将辅助方法添加到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;
}

Test测试

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

Output Output

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

Using Deserializer使用解串器

However, it would likely be more useful if the conversion to array is done while parsing, so you need to write a JsonDeserializer and tell Gson about it using @JsonAdapter :但是,如果在解析时完成转换为数组可能会更有用,因此您需要编写一个JsonDeserializer并使用@JsonAdapter

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

Same Outer class and test code as above.与上面相同的Outer class 和测试代码。

Output Output

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

I'll asume your JsonObject is a POJO class such like:我假设您的JsonObject是 POJO class ,例如:

public Inner[] outer;

If you want an array of objects you can change your code to:如果您想要一个对象数组,您可以将代码更改为:

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

Please refer below code 1.To get an array of Objects (outerArray) 2.You can extract a JsonArray (outerJsonArray) containing values of inner objects in Outer (in case keys aren't significant for further use)请参考下面的代码 1.获取对象数组(outerArray) 2.您可以提取包含Outer中内部对象值的JsonArray (outerJsonArray)(以防键对进一步使用不重要)

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);
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());
        }

You can use the JsonNode class's method findParent findValue and findPath which reduce your code as compare to another parsing library.您可以使用 JsonNode 类的方法 findParent findValue 和 findPath 与另一个解析库相比,它们会减少您的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM