Проблема при разборе нескольких объектов json, каждый из которых имеет несколько массивов из проверенного формата JSON-JavaString

#java #json #parsing #gson

#java #json #синтаксический анализ #gson

Вопрос:

Хотите обработать следующую строку 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 «[{},{},{}]» для разбора и необходимых изменений в коде (понятия не имею, как обращаться с массивом), я не получаю результатов в консоли. Чувствую себя парализованным при поиске моей ошибки. Пожалуйста, помогите. Почти день боролся за настройку кода.

 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 ]
  

Комментарии:

1. Упомянутый JSON недопустим в jsonlint.com . Пожалуйста, проверьте себя, содержит ли ваш json обратную косую черту при каждом значении пары ключей?

2. @Tot Спасибо, что предложили очень полезный инструмент. Теперь я поместил проверенный json.

3. Выдает ли это какую-либо конкретную ошибку у пользователей / Optimight / eclipse-workspace /general/hs_err_pid4563.log?

4. @Tot Я еще не пробовал. Совершенно запутался… исчерпан… На самом деле новичок в программировании на Java — моем первом языке программирования. Пытаюсь создать древовидную карту с меткой (String) в качестве ключа и меткой (Object) в качестве значения.

5. Опубликуйте этот файл журнала. Давайте посмотрим, что внутри! Попробуйте запустить этот файл еще раз с чистым JSON.

Ответ №1:

У вашего JSON есть один сложный элемент — массивы меток содержат one-element JSON object . Мы можем развернуть его с помощью пользовательского десериализатора. Для этого давайте создадим простую POJO структуру, которая соответствует JSON полезной нагрузке. JSON начинается с [ , поэтому это означает, что нам нужно проанализировать его как массив. Все элементы имеют одинаковую структуру. Мы можем определить это следующим образом:

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

Читайте также:

Комментарии:

1. Спасибо Ziober. Реализовано; это сработало, как вы объяснили.

2. Что будет целесообразно — Сохранить файл test.json в папке ресурсов или жестко закодировать test.json как JavaString в классе GsonApp? Как защитить содержимое файла test.json от обратного проектирования?

3. @Optimight, я предполагаю, что вы говорите о Android приложении. Лучше использовать resource folder . Жестко закодированные String -ы создают много проблем при настройке и тестировании. Если вы хотите сохранить его в безопасности, вам нужно зашифровать его, и пользователю необходимо предоставить некоторый пароль для расшифровки. Попробуйте найти решение или задать новый вопрос с android тегом.

4. @ Michal Ziober Я думаю в терминах webapi — server-side.

5. @Optimight, в этом случае гораздо лучше хранить в файле, загружать и кэшировать на случай, если он будет интенсивно использоваться. Это может быть обратная разработка, если кто-то возьмет под контроль только сервер.