Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSON throwing “Expected Expected a name but was NUMBER at line 1 column 8”?

I'm trying to parse a JSON string like this one ( generated URL with http://www.json-generator.com)

{
"total": 86, 
"jsonrpc": "2.0", 
"id": 1, 
"result": [
    {
        "startDate": "14/03/2012", 
        "meetingId": "1330", 
        "creator": "Jhon", 
        "lastModified": "02/04/2012", 
        "meetingTitle": "task clarification", 
        "location": "Conf hall", 
        "startTime": "02:00 PM", 
        "createdDate": "14/03/2012", 
        "owner": "Peter", 
        "endTime": "02:30 PM"
    }, 
    {
        "startDate": "20/03/2012", 
        "meetingId": "1396", 
        "creator": "Mr.Hobbs", 
        "lastModified": "07/09/2012", 
        "meetingTitle": "Design Work", 
        "location": "South conf Room", 
        "startTime": "03:30 PM", 
        "createdDate": "19/03/2012", 
        "owner": "Steve Jobs", 
        "endTime": "04:30 PM"
    }, 
    {
        "startDate": "22/03/2012", 
        "meetingId": "1432", 
        "creator": "Robin", 
        "lastModified": "21/03/2012", 
        "meetingTitle": "Do something new", 
        "location": "NA", 
        "startTime": "10:00 AM", 
        "createdDate": "21/03/2012", 
        "owner": "Mr.Bean", 
        "endTime": "11:00 AM"
    }
  ]

}

Here's an object class I'm using:

public class Country {

String startDate;
 String meetingId;
 String creator;
 String lastModified;
 String meetingTitle;
 String location;
 String startTime;
 String createdDate;
 String owner;
 String endTime;

 public String getStartDate() {
    return startDate;
}
public void setStartDate(String startDate) {
    this.startDate = startDate;
}
public String getMeetingId() {
    return meetingId;
}
public void setMeetingId(String meetingId) {
    this.meetingId = meetingId;
}
public String getCreator() {
    return creator;
}
public void setCreator(String creator) {
    this.creator = creator;
}
public String getLastModified() {
    return lastModified;
}
public void setLastModified(String lastModified) {
    this.lastModified = lastModified;
}
public String getMeetingTitle() {
    return meetingTitle;
}
public void setMeetingTitle(String meetingTitle) {
    this.meetingTitle = meetingTitle;
}
public String getLocation() {
    return location;
}
public void setLocation(String location) {
    this.location = location;
}
public String getStartTime() {
    return startTime;
}
public void setStartTime(String startTime) {
    this.startTime = startTime;
}
public String getCreatedDate() {
    return createdDate;
}
public void setCreatedDate(String createdDate) {
    this.createdDate = createdDate;
}
public String getOwner() {
    return owner;
}
public void setOwner(String owner) {
    this.owner = owner;
}
public String getEndTime() {
    return endTime;
}
public void setEndTime(String endTime) {
    this.endTime = endTime;
}




} 

But it throws me with:

     W/JSONStreamReader(1153): java.lang.IllegalStateException: Expected a name but was NUMBER at line 1 column 8
08-09 01:21:37.629: W/JSONStreamReader(1153): java.lang.IllegalStateException: Expected a name but was NUMBER at line 1 column 8
08-09 01:21:37.629: W/JSONStreamReader(1153):   at com.google.gson.stream.JsonReader.nextName(JsonReader.java:785)
08-09 01:21:37.629: W/JSONStreamReader(1153):   at com.example.gsontest.MainActivity$MyAsyncTask.doInBackground(MainActivity.java:162)

in Json "id": 1, is the number! is that is the reason? I'm generating JSON with http://www.json-generator.com

My Aysc Code for Parsing Json:

 private class MyAsyncTask extends AsyncTask<String, Void, Void> {

        private static final int REGISTRATION_TIMEOUT = 3 * 1000;
        private static final int WAIT_TIMEOUT = 30 * 1000;
        private final HttpClient httpclient = new DefaultHttpClient();

        final HttpParams params = httpclient.getParams();
        private boolean error = false;

        protected Void doInBackground(String... urls) {

            String URL = null;
            Log.d("ConnManagerParams", "ok?");
            try {

                // URL passed to the AsyncTask
                URL = urls[0];
                HttpConnectionParams.setConnectionTimeout(params,
                        REGISTRATION_TIMEOUT);
                HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT);
                ConnManagerParams.setTimeout(params, WAIT_TIMEOUT);

                Log.d("ConnManagerParams", "ok?");
                HttpPost httpPost = new HttpPost(URL);
                Log.d("httpPost", "ok?");
                // Response from the Http Request
                HttpResponse response = httpclient.execute(httpPost);
                Log.d("response", "ok?");
                // Check the Http Request for success
                StatusLine statusLine = response.getStatusLine();
                Log.d("statusLine", response.getStatusLine().toString());
                // Log.d("RESPONSE",
                // EntityUtils.toString(response.getEntity()));

                if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
                    // Log.d("statusok", statusLine.getStatusCode());
                    Gson gson = new Gson();
                    // create a new JSON reader from the response input stream
                    Log.d("gson", "gson?");
                    JsonReader jsonReader = new JsonReader(
                            new InputStreamReader(response.getEntity()
                                    .getContent(), "UTF-8"));
                    // begin parsing
                    Log.d("AFTjsonReader", "AFTjsonReader?");
                    jsonReader.beginObject();
                    Log.d("beginObject", "beginObject?");
                    // stay in loop as long as there are more data elements
                    while (jsonReader.hasNext()) {
                        // get the element name
                        Log.d("whilejsonReader", "whilejsonReader?");
                        // String name = jsonReader.nextName();
                        Log.d("nextName", jsonReader.nextName());
                        String name = jsonReader.nextName();

                        Log.d("nextNametest2", "nextName?");

                        if (name.equals("result")) {

                            Log.d("result", "result?");
                            jsonReader.beginArray();

                            while (jsonReader.hasNext()) {
                                // parse every element and convert that to a
                                // country object
                                Country country = gson.fromJson(jsonReader,
                                        Country.class);
                                // add the country object to the list
                                countryList.add(country);

                            }
                            jsonReader.endArray();
                        }

                        // success = jsonReader.nextBoolean();
                        success = true;

                    }
                    // end reader and close the stream
                    jsonReader.endObject();
                    jsonReader.close();

                } else {
                    // Closes the connection.
                    Log.d("Closes the connection.", "Closes the connection.?");
                    Log.w(LOG_TAG, statusLine.getReasonPhrase());
                    response.getEntity().getContent().close();
                    throw new IOException(statusLine.getReasonPhrase());
                }

            } catch (Exception e) {
                Log.d("catch", "catch");
                Log.w(LOG_TAG, e);

                error = true;
                cancel(true);
            }

            return null;

        }

        protected void onCancelled() {
            Log.e(LOG_TAG, "Error occured during data download");
        }

        protected void onPostExecute(Void unused) {
            if (error) {
                Log.e(LOG_TAG, "Data download ended abnormally!");
            } else {
                displayCountries();
            }
        }

    }

}

Any ideas how should I fix it?

Thanks!

like image 864
LOG_TAG Avatar asked Aug 09 '13 05:08

LOG_TAG


3 Answers

The problem in your code was that you loop on names (json keys):

while (jsonReader.hasNext()) {

you get the next name:

String name = jsonReader.nextName();

but then you consume the value only if this name is equal to result.

Think of the JsonReader as a way to move a cursor forward in your json: reading it token by token. Every command you give to it either read what the cursor is pointing to or move the cursor, sometimes you can move the cursor and read the value with a single command (like with nextName()).

When the name is not result the jsonReader stay in the position where you left it: the name or key you just read with nextName().

So the next time it calls nextName() the cursor move from the key to the value (next) and it expect to find a name and instead it found the value of the previous name, in your case NUMBER because the first value in your json is a number (name: "total", value: 56).

if you are not reading the value because you don't care about it you should call

jsonReader.skipValue();

meaning you should change your code in

if (name.equals("result")) {
  // read it
} else {
  jsonReader.skipValue();
}

That said: you should either use annotation or, if you can't for some reason, register one or more TypeAdapter for the job of parsing your custom objects.

The code inside those adapter is very similar to the one you wrote but it is limited to a single part of the json that match your object.

So for example, if you create a class CountriesResult containing your total, and result of type List<Country>

public class CountriesResult {
  private int total;
  @SerializedName("result")
  private List<Country> countries;
}

You already have a class for Country with the fields you need.

Then you ask GSon to parse your CountriesResult object it will automatically parse it.

gson.fromJson(jsonString, CountriesResult.class);

If you need to parse Country in a custom way you just need a TypeAdatper for Country, see this example. And to register the type adapter or use the @JsonAdapter annotation.

like image 200
Daniele Segato Avatar answered Nov 19 '22 11:11

Daniele Segato


If you're going to use JsonReader and parse the stream manually, you don't use the automatic deserialization via Gson.fromJson().

You either need to extract the fields from each object while traversing that array once you're in your loop, or simply use the automatic deserialization with an appropriate class (which, honestly, is what you should be doing):

class Response {
    private int total;
    private String jsonrpc;
    private int id;
    private List<Country> result;

   // getters and setters ...
}

And then simply:

InputStreamReader isr = new InputStreamReader(response.getEntity()
                                .getContent(), "UTF-8"));
Response r = gson.fromJson(isr, Response.class);
like image 35
Brian Roach Avatar answered Nov 19 '22 12:11

Brian Roach


I am also face the same problem. I found that, issue was every if condition I am getting the jsonReader.nextName(). It is not correct way. I think your also doing the same way.

From your code these two lines create the problem.

  // here the jsonReader moving one step.
  Log.d("nextName", jsonReader.nextName());

  //again your trying to getting the "jsonReader.nextName()" it is wrong in the above line already you got the name and reader move to next line. So  Exception may be comes here.                                    
   String name = jsonReader.nextName();   

we should use "jsonReader.nextName()" one time only for each iteration in while loop like

 while (reader.hasNext())
 {

            String name=reader.nextName();
            if(name.equals(Constants.AUTH)){
                authDetails.setAuth(reader.nextString());

            }else if(name.equals(Constants.STATUS)){
                authDetails.setStatus(reader.nextInt());
            }else if(name.equals(Constants.MESSAGE)){
                authDetails.setMessage(reader.nextString());
            }else {
                reader.skipValue();
            }

    }
like image 27
Kona Suresh Avatar answered Nov 19 '22 11:11

Kona Suresh