首页 > 解决方案 > 解析多个 json 对象时出现问题,每个对象都有来自经过验证的 JSON 格式的多个数组-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 "[{},{},{}]" 以解析并在代码中进行必要的更改(不知道如何处理数组),那么我得到了控制台中没有结果。在发现我的错误时感到麻痹。请帮忙。在调整代码方面挣扎了将近一天。

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 ]

标签: javajsonparsinggson

解决方案


JSON有一个棘手的元素 - 标签数组包含one-element JSON object. 我们可以使用自定义反序列化器解开它。为此,让我们创建POJO适合有效负载的简单结构JSONJSON[所以这意味着我们需要将它解析为一个数组。所有元素都具有相同的结构。我们可以像下面这样定义它:

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

当我们想使用另一个名称来Java比较我们使用的属性时,JSON我们使用SerializedName注释。为了通知Gson库我们希望以特定方式处理给定元素,我们使用JsonAdapter注释。如果我们不知道如何编写自定义反序列化器,Map<String, Object>对未知或随机JSON对象使用类型总是安全的。如果我们有可以使用的对象列表List<Map<String, Object>>。让我们为标签数组编写简单的反序列化器:

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列表中,这是我们反序列化过程的结果。示例用法,可能如下所示:

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

另请阅读:


推荐阅读