#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, в этом случае гораздо лучше хранить в файле, загружать и кэшировать на случай, если он будет интенсивно использоваться. Это может быть обратная разработка, если кто-то возьмет под контроль только сервер.