2

I have an API response that includes METAR weather data as well as string error responses, both contained in the same "data" array. I am using Gson to parse the json response on Android. This works great until I get a string error response. I've tried my hand at trying to write a custom Gson deserializer with no luck. Can someone give me a working example or point me in the correct direction on how to handle this?

The response looks like this:

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

As you can see the "data" array may return a metar object (I have this part working) or an unnamed error string. It is when I get the error string returned that my parsing fails.

As a test I wrote the following. But it is also not working. How can I parse the both the raw unnamed string and the metar object?

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" +
            "}";
}
0

1 Answer 1

1

First it would make thing seasier if you changed the DTOs a bit, for the Response

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

Then the rest is done depending on how you would like to handle the error text. One easy way would be to just add error field to your Station so that it would be:

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

With a custom deserialiser like:

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

}

The try to deserialize:

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

Checking if there is an error string in a Station or not you can see if the data is valid.

Sign up to request clarification or add additional context in comments.

4 Comments

How can I get the getJsonTestResourceReader() method? I have Gson included using maven in my sample test project but cannot find this method.
@user693336 By coding it :) Sorry it was my copy/paste error. It was meant to be your JSON. That was just a method used to read a resource file.
Yes, I just replaced it with the str_json. Still getting errors when parsing though...
Thank you SOOOOO MUCH! I got it to work. You've no idea how I struggled with this!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.