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!
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.
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);
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With