Gson, как анализировать различные типы данных в одном массиве? - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть ответ API, который включает метеорологические данные METAR, а также ответы на строковые ошибки, которые содержатся в одном и том же массиве данных. Я использую Gson для анализа ответа JSON на Android. Это прекрасно работает, пока я не получу ответ об ошибке строки. Я попытался написать собственный десериализатор Gson, но безуспешно. Может ли кто-нибудь дать мне рабочий пример или указать правильное направление, как с этим справиться?

Ответ выглядит так:

{
    "results": 4,
    "data": [
        {
            "icao": "KAJO",
            "name": "Corona Municipal",
            "observed": "05-11-2018 @ 18:56Z",
            "raw_text": "KAJO 051856Z AUTO VRB03KT 10SM CLR 23/08      A2989 RMK AO2 SLP129 T02330078 $",
            "barometer": {
                "hg": 29.890000000000001,
                "kpa": 101.22,
                "mb": 1012.9
            },
            "clouds": [
                {
                    "code": "CLR",
                    "text": "Clear skies",
                    "base_feet_agl": 0,
                    "base_meters_agl": 0
                }
            ],
            "dewpoint": {
                "celsius": 8,
                "fahrenheit": 46
            },
            "elevation": {
                "feet": 535,
                "meters": 163
            },
            "flight_category": "VFR",
            "humidity_percent": 38,
            "temperature": {
                "celsius": 23,
                "fahrenheit": 73
            },
            "visibility": {
                "miles": "10",
                "meters": "16,093"
            },
            "wind": {
                "degrees": 0,
                "speed_kts": 3,
                "speed_mph": 3,
                "speed_mps": 2
            }
        },
        "KGNG METAR Currently Unavailable",
        "CXCY Invalid Station ICAO"
    ]
}

Как видите, массив "data" может возвращать объект metar (у меня эта часть работает) или строку без имени. Когда я получаю строку с ошибкой, мой анализ не выполняется.

В качестве теста я написал следующее. Но это тоже не работает. Как я могу разобрать как необработанную безымянную строку, так и объект metar?

import com.google.gson.*;

import java.lang.reflect.Type;
import java.util.List;

public class Main {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Response.class, new MyDeserializer())
                .registerTypeAdapter(String.class, new String())
                .create();

        Response response = gson.fromJson(str_json, Response.class);
        System.out.println("Hello World!");
    }

    static class MyDeserializer implements JsonDeserializer<Response> {
        @Override
        public Response deserialize(JsonElement json, Type typeOfT
                ,JsonDeserializationContext context) throws JsonParseException {
            // Get the "data" element from the parsed json
            JsonElement data = json.getAsJsonObject().get("data    ");
            // Deserialize it. You use a new instance of Gson to avoid
            // infinite recursion
            return new Gson().fromJson(data, Response.class);

        }
    }
    /*===============================
     * Data Definitions
     *==============================*/
    class Response {
           public String  results;
           public List<Station> Stations;
    }

    class Station {
        public String name;
        public String icao;
    }

    public static String str_json = "{\n" +
            "    \"results\": 3,\n" +
            "    \"data\": [\n" +
            "        {\n" +
            "           \"name\": \"Billings Logan Intl\"," +
            "           \"icao\":\"KBIL\"," +
            "        },\n" +
            "        \"CYPG METAR Currently Unavailable\",\n" +
            "        \"KGNG METAR Currently Unavailable\"\n" +
            "    ]\n" +
            "}";
}

1 Ответ

0 голосов
/ 05 ноября 2018

Во-первых, было бы немного хуже, если бы вы немного изменили DTO для Response

public class Response {
    public String results;
    public List<Station> data; // it is named data in JSON not Stations
}

Затем все остальное делается в зависимости от того, как вы хотите обработать текст ошибки. Одним простым способом было бы просто добавить поле ошибки к вашему Station так, чтобы оно было:

public class Station {
    public String name;
    public String icao;
    public String error;  // used if there is only error string
}

С пользовательским десериализатором, например:

public class StationDeserializer implements JsonDeserializer<Station> {

    private final Gson gson = new Gson();

    @Override
    public Station deserialize(JsonElement json, Type typeOfT
                ,JsonDeserializationContext context)
        throws JsonParseException {         
        try {
            return gson.fromJson(json, Station.class);
        } catch (JsonSyntaxException e) {
            // it was not a Station object
            Station station = new Station();
            // so try to set the error string
            station.error = json.getAsString();
            return station;
        }
    }

}

Попытка десериализации:

Response response = new GsonBuilder()
        .registerTypeAdapter(Station.class, new StationDeserializer())
        .create()
        .fromJson(str_json, Response.class);

Проверяя, есть ли строка error в Station или нет, вы можете увидеть, действительны ли данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...