WebService returns an Array, and I am not able to insert into an ArrayMyClass

1
{
 "cemaden":[
  {
     "codestacao":"520310401A",
     "latitude":-16.196,
     "longitude":-52.546,
     "cidade":"BALIZA",
     "nome":"Setor Central",
     "tipo":"Pluviom\u00E9trica",
     "uf":"GO",
     "chuva":0.0,
     "nivel":null,
     "dataHora":"2015-05-05 11:00:00.0"
  },
  {
     "codestacao":"520310401A",
     "latitude":-16.196,
     "longitude":-52.546,
     "cidade":"BALIZA",
     "nome":"Setor Central",
     "tipo":"Pluviom\u00E9trica",
     "uf":"GO",
     "chuva":0.2,
     "nivel":null,
     "dataHora":"2015-05-05 11:10:00.0"
  },
  ...
 ]
}

This is the return of the webservice.

And I'm doing the following:

public String sendGet(String site) throws Exception {
    URL url = new URL(site);
    HttpURLConnection conexao = (HttpURLConnection) url.openConnection();
    conexao.setRequestProperty("User-Agent", USER_AGENT);
    conexao.setRequestMethod("GET");
    InputStreamReader input = new InputStreamReader(conexao.getInputStream());
    BufferedReader buffer = new BufferedReader(input);
    String inputLine;
    StringBuffer response = new StringBuffer();
    while((inputLine = buffer.readLine()) != null) {
        response.append(inputLine);
    }
    input.close();

    return response.toString();
}

public void arrayPluviometros() throws Exception {
    String json = sendGet("http://150.163.255.240/CEMADEN/resources/parceiros/GO/1");
    Gson g = new Gson();
    Pluviometro t = g.fromJson(json, Pluviometro.class);
    Type pluviometroType = new TypeToken<ArrayList<Pluviometro>>() {}.getType();                
    List<Pluviometro> p = g.fromJson(json, pluviometroType);
}

And it has the following error:

  

Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

    
asked by anonymous 05.05.2015 / 16:17

2 answers

1

The response you are getting is a JSON object and not an array of objects. This error happens because an array is expected at the beginning of JSON (starting with [ ), since you pass as type to deserialize a list of Pluviometro , but there is { , ie the beginning of an object.

There are some ways you can do this, I'll name just two.

The simplest way is to define another object, let's call it CEMADENResponse , which will add a list of rain gauges. As in the response the name of the object is cemaden , to be more readable the object we need to speak the name the attribute to GSON. So this object should look like this:

public class CEMADENResponse {

    @SerializedName("cemaden")
    private List<Pluviometro> pluviometros;

    // getter e setter

}

You can call the list of cemaden and not pluviometros , if you want, and remove the annotation @SerializedName , if you prefer.

Created the object, to deserialize to an instance of CEMADENResponse , just do something like this:

final String jsonResponse = sendGet("http://150.163.255.240/CEMADEN/resources/parceiros/GO/1");
final Gson gson = new Gson();
final CEMADENResponse response = gson.fromJson(jsonResponse, CEMADENResponse.class);

From there, just retrieve the list of rain gauges and do what you need, for example print the value of all of them:

final List<Pluviometro> pluviometros = response.getPluviometros();
for (Pluviometro pluviometro : pluviometros) {
    System.out.println("codestacao: " + pluviometro.getCodestacao());
    System.out.println("latitude: " + pluviometro.getLatitude());
    System.out.println("longitude: " + pluviometro.getLongitude());
    // outros atributos
}

That will generate something like this according to the result:

codestacao: 520310401A
latitude: -16.196
longitude: -52.546

The second way is to use a custom deserializer. Starting with your attempt to return a list of rain gauges soon, let's have the custom deserializer then return a List<Pluviometro> .

The work here is a bit larger, as we should get the JSON element and read each property. It should look something like this:

public class PluviometroDeserializer implements JsonDeserializer<List<Pluviometro>> {

    @Override
    public List<Pluviometro> deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException {
        final List<Pluviometro> result = new ArrayList<>();

        final JsonObject jsonObject = json.getAsJsonObject();
        final JsonElement cemaden = jsonObject.get("cemaden");
        final JsonArray pluvs = cemaden.getAsJsonArray();

        final int pluvsSize = pluvs.size();
        for (int i = 0; i < pluvsSize; i++) {
            final JsonObject element = pluvs.get(i).getAsJsonObject();

            final Pluviometro pluv = new Pluviometro();
            pluv.setCodestacao(element.get("codestacao").getAsString());;
            pluv.setLatitude(element.get("latitude").getAsDouble());
            pluv.setLongitude(element.get("longitude").getAsDouble());
            // demais atributos

            result.add(pluv);
        }

        return result;
    }
}

That is, first we retrieve the object cemaden , which is a JsonObject . Since we know there is an array of rain gauges in it, we can retrieve a JsonArray . After that, just recover each element (which is the JSON representation of the object Pluviometro ) and retrieve its attributes.

In this way, when you deserialize, you will directly get the list of rain gauges, doing something like this:

final String jsonResponse = sendGet("http://150.163.255.240/CEMADEN/resources/parceiros/GO/1");
final Type type = new TypeToken<List<Pluviometro>>() {}.getType();
final Gson gson = new GsonBuilder().registerTypeAdapter(type, new PluviometroDeserializer()).create();
final List<Pluviometro> pluviometros = gson.fromJson(jsonResponse, type);;
for (final Pluviometro pluviometro : pluviometros) {
    System.out.println("codestacao: " + pluviometro.getCodestacao());
    System.out.println("latitude: " + pluviometro.getLatitude());
    System.out.println("longitude: " + pluviometro.getLongitude());
    // demais atributos
}

This will also generate something like the previous example:

codestacao: 520310401A
latitude: -16.196
longitude: -52.546

So, use the approach that best fits your context.

Note : I'm using the 2.3.1 version in the examples, if you get any errors out there, check the version of the library you're using.

EDITION : including solution for date format error

The date in the return is coming this way: 2015-05-05 11:00:00.0 . To build an instance of Gson use this pattern: yyyy-MM-dd HH:mm:ss . An example would look like this:

final Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

I noticed that in the return milliseconds are always zeroed , but if you want them too, you can default this here: yyyy-MM-dd HH:mm:ss.S .

    
15.05.2015 / 21:59
0

Brother, it worked and solved the error that was ... But a new error appeared:

  

Exception in thread "main" com.google.gson.JsonSyntaxException: 2015-05-17 13: 00: 00.0       at com.google.gson.DefaultDateTypeAdapter.deserializeToDate (DefaultDateTypeAdapter.java:107)

I tried the code below but it did not solve either:

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
    
17.05.2015 / 18:03