Webservice returns an Array, and I’m unable to insert it into an Array<Minhaclasse>

Asked

Viewed 603 times

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 here’s what I’m doing:

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 he presents the following error:

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

2 answers

1

The answer 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 [), once you pass as kind to deserialize a list of Pluviometro, but there is a {, that is, the beginning of an object.

There are some ways you can do this, I’ll just quote 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 answer the name of the object is cemaden, To be more readable the object we need to speak the name of 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 from cemaden and not pluviometros, if you wish, 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 outcome:

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

The second way is to use a custom deserializer. Starting from his attempt to immediately return a list of rain gauges, we will make the custom deserializer then return a List<Pluviometro>.

The work here is a little bigger, because we must take the element JSON and read each property. It should be 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 recover the object cemaden, which is a JsonObject. As we know that there is an array of rain gauges, we can recover a JsonArray. After this, we just recover each element (which is the representation JSON of the object Pluviometro) and recover its attributes.

This way, by deserializar, you will already get directly to 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

Then use the approach you consider best in your context.

Observing: I’m using the version 2.3.1 in the examples, if there is an error there, check the version of the library you are using.

EDITION: including solution to date format error

The date on 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 be like this:

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

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

  • @Afonsooliveiraneto if the answer has helped you, consider accepting it. Thank you

0

The brother, it worked and solved the error that was... But a new error has arisen:

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 also did not solve:

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
  • Afonso instead of creating an answer, you can comment on the question or the answer. As to this error, it is the date format that is wrong. Consider removing this question and, if it has helped, accepting the answer that has been asked. If other problems have appeared, consider creating a new question that represents what you have evolved and the new error.

  • Excuse my ignorance regarding a new answer rather than comment... But regarding the date error, does anyone have any suggestions?

  • @Afonsooliveiraneto I edited my reply with the appropriate date format, as I had said in a previous comment the date pattern is wrong. If the answer has helped, consider accepting it. Also, prefer to make comments in my reply, in this way I am warned that there was a comment.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.