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,与另一个解析库相比,它们减少了您的代码。
我正在尝试使用 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,与另一个解析库相比,它们减少了您的代码。