Reputation: 871
I'm trying to parse some JSON generated by the Redmine API with GSON, using this tutorial as a base. Unfortunately I can't give you the URL for my JSON because it only works internally but it looks like this:
{
"limit": 25,
"total_count": 653,
"offset": 0,
"time_entries": [
{
"spent_on": "2013-02-14",
"activity": {
"name": "Blah1",
"id": 10
},
"project": {
"name": "TEST",
"id": 10
},
"id": 661,
"hours": 1,
"updated_on": "2013-02-14T14:32:19Z",
"user": {
"name": "USER1",
"id": 7
},
"issue": {
"id": 467
},
"comments": "COMMENT 1",
"created_on": "2013-02-14T14:32:19Z"
},
{
"spent_on": "2013-02-14",
"activity": {
"name": "Bla2",
"id": 10
},
"project": {
"name": "TEST TEST",
"id": 10
},
"id": 660,
"hours": 1,
"updated_on": "2013-02-14T11:52:13Z",
"user": {
"name": "USER2",
"id": 4
},
"issue": {
"id": 466
},
"comments": "COMMENT 2.",
"created_on": "2013-02-14T11:52:13Z"
}
]
}
I get a NullPointerException
but I'm not sure if it's from failing to get the JSON or modelling it wrong. I'm concerned I'm missing something to do with the inner classes. If it's as simple as the JSON being fetched incorrectly I'll be really annoyed at myself.
My devices are all running with WIFI connected to the internal network and I can see the JSON when I use the browser so I don't think it's a networking issue.
Here Is my LogCat:
02-20 21:11:11.175: E/AndroidRuntime(14450): FATAL EXCEPTION: main
02-20 21:11:11.175: E/AndroidRuntime(14450): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.javacodegeeks.android.json/com.javacodegeeks.android.json.JsonParsingActivity}: java.lang.NullPointerException
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.ActivityThread.access$600(ActivityThread.java:141)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.os.Handler.dispatchMessage(Handler.java:99)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.os.Looper.loop(Looper.java:137)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.ActivityThread.main(ActivityThread.java:5041)
02-20 21:11:11.175: E/AndroidRuntime(14450): at java.lang.reflect.Method.invokeNative(Native Method)
02-20 21:11:11.175: E/AndroidRuntime(14450): at java.lang.reflect.Method.invoke(Method.java:511)
02-20 21:11:11.175: E/AndroidRuntime(14450): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
02-20 21:11:11.175: E/AndroidRuntime(14450): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
02-20 21:11:11.175: E/AndroidRuntime(14450): at dalvik.system.NativeStart.main(Native Method)
02-20 21:11:11.175: E/AndroidRuntime(14450): Caused by: java.lang.NullPointerException
02-20 21:11:11.175: E/AndroidRuntime(14450): at com.javacodegeeks.android.json.JsonParsingActivity.onCreate(JsonParsingActivity.java:46)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.Activity.performCreate(Activity.java:5104)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
02-20 21:11:11.175: E/AndroidRuntime(14450): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
My JsonParsingActivity
:
public class JsonParsingActivity extends Activity {
String url = "URL";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
InputStream source = retrieveStream(url);
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
RedmineResponse response = gson.fromJson(reader, RedmineResponse.class);
Toast.makeText(this, response.query, Toast.LENGTH_SHORT).show();
List<Result> results = response.results;
for (Result result : results) {
if (result.comments != null) {
Toast.makeText(this, result.comments, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "EMPTY", Toast.LENGTH_SHORT).show();
}
}
}
private InputStream retrieveStream(String url) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
} catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
}
My Result
class:
public class Result {
@SerializedName("id")
public String time_entry_ID;
@SerializedName("spent_on")
public String spent_on;
@SerializedName("created_on")
public String created_on;
public Project project;
@SerializedName("hours")
public String hours;
@SerializedName("comments")
public String comments;
@SerializedName("iso_language_code")
public String isoLanguageCode;
@SerializedName("to_user_id_str")
public String toUserIdStr;
public String source;
}
My RedmineResponse
class:
public class RedmineResponse {
public List<Result> results;
@SerializedName("limit")
public int limit;
@SerializedName("offset")
public int offset;
public String query;
}
My Activity
class:
public class Activity {
@SerializedName("id")
public String activity_ID;
@SerializedName("name")
public String activity_name;
}
My Issue
class:
public class Issue {
@SerializedName("id")
public String issue_ID;
}
My Project
class:
public class Issue {
@SerializedName("id")
public String issue_ID;
}
My User
class:
public class User {
@SerializedName("id")
public String user_ID;
@SerializedName("name")
public String user_name;
}
Upvotes: 3
Views: 2618
Reputation: 80598
You need to define the serialized property name for the results
collection in your RedmineResponse
mapping:
public class RedmineResponse {
@SerializedName("time_entries") // This is the name you are using in JSON
public List<Result> results;
}
On a complete tangent, its better to define properties on your Javabeans (aka private variables with getter/setters), because this helps to encapsulate them better.
Upvotes: 3