从经过验证的JSON格式-JavaString解析每个具有多个数组的多个json对象时出现问题 [英] Problem in parsing multiple json objects each having multiple Arrays from a validated JSON format-JavaString
问题描述
要处理以下JSON字符串(已通过jsonlint.com验证)
[{
"label": "Hospital",
"domain": "Health_Care",
"synonymlabels": [{
"label": "SHCO"
}, {
"label": "HCO"
}],
"childrenlabels": [{
"label": "Childern_Hospital"
}, {
"label": "Mental_Hospital"
}, {
"label": "Heart_Hospital"
}, {
"label": "Orthopadic_Hospital"
}, {
"label": "General_Hospital"
}, {
"label": "Gynac_Hospital"
}, {
"label": "Cancer_Hospital"
}, {
"label": "Burn_Hospital"
}, {
"label": "Trauma_Care_Hospital"
}]
},
{
"label": "Doctor",
"domain": "Health_Care",
"synonymlabels": [{
"label": "Clinician"
}, {
"label": "Physician"
}, {
"label": "Medical_Practitioner"
}],
"childrenlabels": [{
"label": "Cardiaologist"
}, {
"label": "Allergist"
}, {
"label": "Nurologist"
}, {
"label": "Gynacologist"
}, {
"label": "General_Physician"
}, {
"label": "Anesthetist"
}, {
"label": "Physiotherapist"
}, {
"label": "Urologist"
}, {
"label": "Oncologist"
}, {
"label": "Homeopath"
}, {
"label": "Dentist"
}]
}
]
示例代码
我能够运行以下示例代码,并能够获得所需的输出.如果我将JSON字符串(即对象"{}"更改为JSON ARRAY"[{},{},{}]")进行解析,并在代码中进行了必要的更改(不知道如何处理数组),那么我会得到在控制台中没有结果.在发现我的错误时感到麻痹.请帮忙.在调整代码方面费了将近一天的时间.
Sample Code
I am able to run the following sample code and able to get the desired output. If I change JSON string i.e. object "{}" to JSON ARRAY "[{},{},{}]" to parse and necessary change in the code (no idea that how to deal with the Array) then I'm getting no results in the console. Feeling paralytic in finding my error. Please help. Struggled for almost a day in tweaking the code.
import java.io.IOException;
import java.io.StringReader;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
public class gsontester {
public static void main(String args[]) {
String jsonString =
"{ \"name\":\"Mahesh Kumar\", \"age\":21,\"verified\":false,\"marks\": [100,90,85,100,14,95]}";
JsonReader reader = new JsonReader(new StringReader(jsonString));
try {
handleJsonObject(reader);
}
catch (IOException e) {
e.printStackTrace();
}
}
private static void handleJsonObject(JsonReader reader) throws IOException {
reader.beginObject();
String fieldname = null;
while (reader.hasNext()) {
JsonToken token = reader.peek();
if (token.equals(JsonToken.BEGIN_ARRAY)) {
System.out.print("Marks [ ");
handleJsonArray(reader);
System.out.print("]");
} else if (token.equals(JsonToken.END_OBJECT)) {
reader.endObject();
return;
} else {
if (token.equals(JsonToken.NAME)) {
//get the current token
fieldname = reader.nextName();
}
if ("name".equals(fieldname)) {
//move to next token
token = reader.peek();
System.out.println("Name: "+reader.nextString() );
}
if("age".equals(fieldname)) {
//move to next token
token = reader.peek();
System.out.println("Age:" + reader.nextInt());
}
if("verified".equals(fieldname)) {
//move to next token
token = reader.peek();
System.out.println("Verified:" + reader.nextBoolean());
}
}
}
}
输出
Name: Mahesh Kumar
Age:21
Verified:false
Marks [ 100 90 85 100 14 95 ]
推荐答案
您的JSON
有一个棘手的元素-标签数组包含one-element
JSON object
.我们可以使用自定义反序列化器对其进行解包.为此,让我们创建适合JSON
有效负载的简单POJO
结构. JSON
从[
开始,因此这意味着我们需要将其解析为数组.所有元素都具有相同的结构.我们可以如下定义它:
Your JSON
has one tricky element - label arrays contain one-element
JSON object
. We can unwrap it using custom deserialiser. To do that let's create simple POJO
structure which fit's JSON
payload. JSON
starts from [
so it means we need to parse it as an array. All elements have the same structure. We can define it like below:
class Phrase {
private String label;
private String domain;
@JsonAdapter(StringWrapperJsonDeserializer.class)
@SerializedName("synonymlabels")
private List<String> synonymLabels;
@JsonAdapter(StringWrapperJsonDeserializer.class)
@SerializedName("childrenlabels")
private List<String> childrenLabels;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public List<String> getSynonymLabels() {
return synonymLabels;
}
public void setSynonymLabels(List<String> synonymLabels) {
this.synonymLabels = synonymLabels;
}
public List<String> getChildrenLabels() {
return childrenLabels;
}
public void setChildrenLabels(List<String> childrenLabels) {
this.childrenLabels = childrenLabels;
}
@Override
public String toString() {
return "Phrase{" +
"label='" + label + '\'' +
", domain='" + domain + '\'' +
", synonymLabels=" + synonymLabels +
", childrenLabels=" + childrenLabels +
'}';
}
}
与JSON
中的属性相比,当我们想对Java
中的属性使用其他名称时,我们使用SerializedName
注释.为了通知Gson
库我们希望以特定的方式处理给定的元素,我们使用JsonAdapter
批注.如果我们不知道如何编写自定义反序列化器,则对于未知或随机的JSON
对象使用Map<String, Object>
类型始终是安全的.如果我们有对象列表,则可以使用List<Map<String, Object>>
.让我们为标签数组编写简单的反序列化器:
When we want to use another name for property in Java
comparing to what we have in JSON
we use SerializedName
annotation. To inform Gson
library that we would like to handle given element in a specific way we use JsonAdapter
annotation. In case we do not know how to write custom deserialiser it is always safe to use Map<String, Object>
type for unknown or random JSON
object. In case we have list of objects we can use List<Map<String, Object>>
. Let's write simple deserialiser for labels arrays:
class StringWrapperJsonDeserializer implements JsonDeserializer<List<String>> {
@Override
public List<String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonArray()) {
final JsonArray array = (JsonArray) json;
final int size = array.size();
if (size == 0) {
return Collections.emptyList();
}
List<String> labels = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
JsonObject jsonElement = (JsonObject) array.get(i);
Set<String> keys = jsonElement.keySet();
for (String key : keys) {
labels.add(jsonElement.getAsJsonPrimitive(key).getAsString());
}
}
return labels;
}
return Collections.emptyList();
}
}
算法非常简单:如果给定元素是数组,则对其进行迭代并逐个获取每个对象.对于每个对象,获取所有键并将相应的值添加到labels
列表中,这是我们反序列化过程的结果.用法示例如下所示:
Algorithm is quite simple: if given element is an array, iterate over it and take each object one-by-one. For each object get all keys and add corresponding values to labels
list which is our result of deserialisation process. Example usage, could look like this:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
public class GsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
Phrase[] phrases = gson.fromJson(new FileReader(jsonFile), Phrase[].class);
Stream.of(phrases).forEach(System.out::println);
}
}
上面的代码显示:
Phrase{label='Hospital', domain='Health_Care', synonymLabels=[SHCO, HCO], childrenLabels=[Childern_Hospital, Mental_Hospital, Heart_Hospital, Orthopadic_Hospital, General_Hospital, Gynac_Hospital, Cancer_Hospital, Burn_Hospital, Trauma_Care_Hospital]}
Phrase{label='Doctor', domain='Health_Care', synonymLabels=[Clinician, Physician, Medical_Practitioner], childrenLabels=[Cardiaologist, Allergist, Nurologist, Gynacologist, General_Physician, Anesthetist, Physiotherapist, Urologist, Oncologist, Homeopath, Dentist]}
另请参阅:
- JsonAdapter
- Serializing and Deserializing a List with Gson
这篇关于从经过验证的JSON格式-JavaString解析每个具有多个数组的多个json对象时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!