Android: Using GSON to parse a response with dynamic fields - android

I need to parse a JSON response regarding events in an agenda, of which a field is dynamic. This field changes depending on the month in which the event takes place.
Now I've been parsing data with GSON before, but these all had static fields so it was quite easy to create the necessary POJO's. But how would I do this with dynamic fields?
The response i need to parse is like so:
{
"Agenda/Future": {
"November 2011/0": [
{
"id": "5675",
"eventid": "",
"name": "testing testing 123",
"startdate": "nov 25",
"datecompute": "2011-11-25T08:00:00",
"group_month": "November 2011",
"flg_Data": "Database"
}
],
"February 2012/1": [
{
"id": "5681",
"eventid": "",
"name": "dfd",
"startdate": "feb 3",
"datecompute": "2012-02-03T12:00:00",
"group_month": "February 2012",
"flg_Data": "Database"
},
{
"id": "5679",
"eventid": "",
"name": "vfvd",
"startdate": "feb 17",
"datecompute": "2012-02-17T12:00:00",
"group_month": "February 2012",
"flg_Data": "Database"
}
],
"February 2013/2": [
{
"id": "5680",
"eventid": "",
"name": "df",
"startdate": "feb 14",
"datecompute": "2013-02-14T12:00:00",
"group_month": "February 2013",
"flg_Data": "Database"
}
],
"September 2013/3": [
{
"id": "5677",
"eventid": "",
"name": "fsdfsd",
"startdate": "sep 14",
"datecompute": "2013-09-14T12:00:00",
"group_month": "September 2013",
"flg_Data": "Database"
}
],
"November 2015/4": [
{
"id": "5676",
"eventid": "",
"name": "fsdfsd",
"startdate": "nov 13",
"datecompute": "2015-11-13T12:00:00",
"group_month": "November 2015",
"flg_Data": "Database"
}
]
}
}
As you can see, the object title regarding months is dynamic. Both the value at the end of the title, as well as the title itself change based on the actual month and position in the array of months.
From what I've seen on other questions here at SO, I will need to work with Maps.
But I'm not quite sure how I would go about doing so.
Let's say I create a POJO called Event for the individual events contained in the array of the months, what would my initialization look like?
Regards
I have tried Amir's suggestion by using Jackson with the default Map.
Sadly, this creates a Map with a size of 1. The entire JSON response gets parsed into a single object. Ofcourse, this is not what I want, since I need to get the data from the individual events.
Does anyone have a suggestion as to how I might be able to do that? Normally I'd figure out these things quite quickly but I can't wrap my head around this one due to the dynamic object naming.
I have eventually managed to crack this problem. I ended up using plain JSONObjects, which worked eventually.
The code I used to get it to work is as follows:
JSONObject jsonObject = new JSONObject(response);
JSONObject agenda = jsonObject.getJSONObject("Agenda/Future");
if (agenda != null) {
System.out.println(agenda.length());
JSONArray events = agenda.names();
if (events.length() > 0) {
System.out.println("At least its bigger then 0. It's: "
+ events.length());
for (int i = 0; i < events.length(); i++) {
System.out.println(events.get(i).toString());
JSONArray test = agenda.getJSONArray(events.get(i)
.toString());
if (test != null) {
JSONObject testt = test.getJSONObject(0);
if (testt != null) {
System.out.println(testt.getString("name"));
} else {
System.out.println("Still empty, Check again.");
}
}
}
}
} else {
System.out.println("Agenda is completely empty, try again.");
}
As you can see, this still contains test-names, but at least it works.
Thanks for the help everyone!

Since the month data are not valid java identifiers, you 'll probably have to use custom serialization with GSON. You're talking about using Map objects but if you are going to do that you may as well us the org.json objects like JSONObject which are basically built on maps/hashtables anyway.

If all your fields, as you have said, are dynamic then you can create a super set of all fields in a pojo. But that doesn't really help and I think the Map is the best solution. With GSON, you can do
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> map = gson.fromJson("{'key1':'123','key2':'456'}", type);
This will return a map of strings.
I haven't actually used GSON to do this before though. I have been very happy with Jackson lib and with that you can do
new ObjectMapper().readValue("...json...", Map.class)
The above will return a map of maps which is what you want.

Related

REST Api JSON response with field changing

I have to consume a JSON Rest api (for mobile). This api returns a field that is changing like so : (string, int, null, array, object or array of object)
{"field": [{"id": 12, "value": "string value"}]} //array of object
{"field": 12345} //int
{"field": "string"} //string
{"field": {"id": 1, "value": "I'm an object now"}} //object
{"field": ["array", "of", "string"]} //array of string
I may be possible to change the server response to be able to do some standardisation, which could be great! Right now I had to create an adapter (with GSON) but this solution have is limitations, especially with performances and maintainability..
How could I create a good response that will be easy to understand and use?
You could find some relevant information here :
http://jsonapi.org/format/#introduction
https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
There isn't any json specifications, everybody can do whatever they want. But there are some best practices.
The simple & useful structure is as below:
{
"success": true,
"message": "It is done",
"data": {
"id": 123,
"value": "string",
"object":{
"object_value":"I'm an object now"
},
"array_object":[ {"key1":"value1"},{"key2":"value2"},{"key3":"value3"} ]
},
"string": "Hello World"
}

How to write and read contents containing complex json data?

friends:
I get a response from remote server as follows on Android:
{
"items": {
"persons": [
{
"id": "200120",
"name": "Bill"
},
{
"id": "200121",
"name": "Jim"
}
],
"tasks": [
{
"id": "001",
"name": "Fetch ten books",
"deadline": "5:30 p.m.",
"scores": "10"
},
{
"id": "002",
"name": "Fetch thirty books",
"deadline": "5:30 p.m.",
"scores": "30"
}
],
"intro": "This is a funny game."
},
"otherObj": []
}
And I want to save it to phones. I do not think it a good choice to save it into databases. However it read not fast if put the response to SharedPreferences file. Is there any other way?
No need to save this data into database as these value are dynamic and will change time to time.
In your Activity, call the API and get JSON as response and then parse this JSON and show it on device.
To store it on device u can use Singleton class also.
For JSON parser refer to http://www.tutorialspoint.com/android/android_json_parser.htm
You can first save your data into objects and at last into Object Array and then Save to database.(If your data is dynamic it is better you only deal with Object not database)
For saving to database you can use
db.beginTransaction();
for(object : ObjectArray){
db.dboperation();
}
db.setTransactionSuccessful();
db.endTransaction();

Android - Casting model that is not in the Adapter

I have a ListView that is using a custom adapter to populate its rows.
I want to get two String values from the adapter that I have clicked, so I used getItem method:
#Override
public UserItemsModel getItem(int i) {
return arrUserItems.get(i);
}
As you can see above, I'm suing UserItemsModel as a reference to get the item id.
So, in the list fragment, I retrieve the values I desired by using onListItemClicked method:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
UserItemsModel userItemsModel = (UserItemsModel) l.getAdapter().getItem(position);
String item_id = userItemsModel.getItem_id();
//String user_id = userItemsModel.getUser_id(); This is not in the UserItemsModel
mListener.onUserItemSelected(user_id, item_id);
}
However, the user_id is not in the UserItemsModel (as I have modeled from a Json format), instead user_id is in the other model that the adapter doesn't use.
UserItemsModel look like this:
public class UserItemsModel {
private String item_id; // i can get this
private String item_name;
No user_id that I wanted. But, it is in UserShopModel which is a parent of UserItemsModel
public class UserShopModel {
private String user_id; // i can't get this
private String username;
private String name;
When I run the app, it throws an error that says something like Cannot Cast UserShopModel into UserItemsModel
Anyone know how to get around this? If anything unclear please let me know.
UDPATE:
Here is how the JSON look like:
{
"results": {
"user_id": "2947",
"username": "100001235797881",
"name": "Fast Reload",
"email": "atiqahfatin76#yahoo.com",
"phone": "6Lparw1NrMmpu7gd2U18mg==",
"avatar": "http:\/\/ked.ai\/uploads\/avatar\/2947_avatar.png",
"shop_name": "FastReload",
"shop_desc": "our vision is to provide Fast And Easy reload service in malaysia. After One time registeration You can top up anytime anywhere at any number with lower price using sms system.24\/7, no internet connection required. Click here http:\/\/www.fastreload.tk\/ For more info and registeration .Thank You =)",
"shop_namespace": "FastReload",
"shop_canvas": "http:\/\/ked.ai\/uploads\/canvas\/2947_canvas.png",
"profile": [
{
"id": "1",
"title": "Shop Name",
"content": "FastReload"
},
{
"id": "2",
"title": "Shop Namespace",
"content": "FastReload"
},
{
"id": "3",
"title": "Shop Description",
"content": "our vision is to provide Fast And Easy reload service in malaysia. After One time registeration You can top up anytime anywhere at any number with lower price using sms system.24\/7, no internet connection required. Click here http:\/\/www.fastreload.tk\/ For more info and registeration .Thank You =)"
},
{
"id": "4",
"title": "Customer Service",
"content": "operation hours 9 am to 9 pm"
},
{
"id": "5",
"title": "Trust Level",
"content": "0%"
},
{
"id": "6",
"title": "Bank Details",
"content": null
}
],
"items": [
{
"item_id": "20321",
"name": "Fast And Easy Reload Service",
"price": "20",
"description": " our vision is to provide Fast And Easy reload service in malaysia. After One time registeration You can top up anytime anywhere at any number with lower price using sms system.24\/7, no internet connection required.Click here http:\/\/www.fastreload.tk\/ For more info and registeration .Thank You =)",
"category_id": "127",
"category": "Services",
"vanity": [
],
"thumbnail": {
"image50": "http:\/\/ked.ai\/uploads\/item\/100001235797881\/2947_1391259043.71a8deec82a92fc51acfa63c7a87c263_50.jpg",
"image100": "http:\/\/ked.ai\/uploads\/item\/100001235797881\/2947_1391259043.71a8deec82a92fc51acfa63c7a87c263_100.jpg"
}
}
],
"vanities": [
],
"categories": [
{
"category_id": "127",
"category_name": "Services",
"category_url": "http:\/\/ked.ai\/FastReload\/category\/services",
"count": "1"
}
]
},
"errors": ""
}
If you wish to obtain the user id from the ShopModel, then the only way you might want to do this, is:
1. Either pass the userShopModel as an argument to the constructor of the adapter.
The assumption you might want to make is, UserShopModel and UserItemModel
have the same number of items(that is the size is the same)
2. The other thing you could do is, inside every userItemModel create a property
of the type UserShopModel such that for every item that you click,
you not only get the item_id but also the user_id
Hope this helps.

Jackson deserializing JSON into multiple POJOs

Hi I have following JSON
{
"code": 0,
"response": {
"userObject": {
"User": {
"id": "355660",
"first_name": "Dummy",
"last_name": "dummy",
"email": "dumb#email.com",
"birthday": "2012-05-07",
"created": "2012-08-21 06:41:05",
"modified": "2012-08-21 06:41:05",
"image_url": null,
},
"Location": {
"id": "273550",
"name": "New York City",
"asciiName": "New York City",
"lat": "40.714272",
"lon": "-74.005966",
"geoname_modified": "2011-11-08 00:00:00",
"timeZone": "America/New_York",
"countryName": "United States",
"state": "New York",
"created": "2012-07-12 12:11:01",
"modified": "2012-08-20 14:27:24"
}
}
}
}
I have two classes, one each for Location and User
I know that I can get the objects if I create nested class like
response
->UserObject
*User
*Location
But i don't want to create two extra classes for UserObject and response just for wrapping the two POJO's .
Is there any simpler way to do it??
I am using Jackson Parser with Spring for android
You can also do it in two steps, if you really want to avoid throw-away classes, like:
JsonNode tree = mapper.readTree(...);
User user = mapper.treeToValue(tree.path("response").path("userObject").get("User"), User.class);
Location loc = mapper.convertValue(tree.path("response").path("userObject").get("Location"), Location.class);
but yeah I might go with silly struct-classes instead:
static class Response {
public UserObject userObject;
}
static class UserObject {
public Location Location;
public User User;
}
since it really isn't much more code.
Rather than creating classes you could create arrays or use hashmap. Personally, I would just create the classes. I think that this give you more flexibility in your app, and will allow you to work with the objects with less hassle. I know it takes time to set them up, but once you do that, you can use ArrayList and you can parse the JSON quite a bit easier.

How to Parse Facebook Data

I am having a few problems getting Facebook data to parse properly.
I am working on implementing part of an application to allow a user to select and use one of their own facebook photos within the app. I have gotten the facebook login/logout code working and I am currently getting the token (once logged in) in order to gather the users Album information. The permission set is also working nicely, however I am now stuck at trying to get the JSON information to parse correctly. Here is a sample snippet of the information I need to parse:
"data": [
{
"id": "3486732467234",
"from": {
"name": "Persons Name",
"id": "Persons ID"
},
"name": "Vacation",
"location": "City",
"link": "https://www.facebook.com/album.php?fbid=434235&id=324343&aid=2430",
"cover_photo": "3489234432",
"privacy": "everyone",
"count": 60,
"type": "normal",
"created_time": "2007-06-03T23:01:16+0000",
"updated_time": "2011-03-18T19:46:43+0000",
"can_upload": true
},
{
"id": "4043544665",
"from": {
"name": "Persons Name",
"id": "Persons ID"
},
"name": "Vacation 2",
"location": "City",
"link": "https://www.facebook.com/album.php?fbid=4043434665&id=508154335&aid=2555",
"cover_photo": "5434543",
"privacy": "everyone",
"count": 60,
"type": "normal",
"created_time": "2007-06-03T22:53:03+0000",
"updated_time": "2011-03-18T19:45:55+0000",
"can_upload": true
}],
...more paging JSON information ...}}
I need to be able to pull the album information in order to display the photo album names in a list (and use the ID in another query). Once I can get the albums to show, I would then use those IDs to perform another query to get the photos from that album. Again I can also get that information back, I am just not sure how to properly parse it.
Any useful tips that someone might have in being able to parse this into a listview would be greatly appreciated.
I need to target pulling the first ID and the Album name ("id": "3486732467234" and "name": "Vacation" from the first listing)
why don't you try with the json classes...
something like this:
jsonObject = new JSONObject(your_data);
jArray = jsonObject.getJSONArray("data");
for(int i =0;i<jArray.length();i++){
String name= jArray.getJSONObject(i).getString("name");
String location= jArray.getJSONObject(i).getString("location");
etc.
The new Android Facebook SDK 3.0 returns a Response object in the Response.Callback() listener when making Graph API calls. This response object can be used to create a GraphObject which can be used to get a JSON...ex:
Request graphRequest = Request.newGraphPathRequest(session, graphRequestString, new Request.Callback() {
#Override
public void onCompleted(Response response) {
//Create the GraphObject from the response
GraphObject responseGraphObject = response.getGraphObject();
//Create the JSON object
JSONObject json = responseGraphObject.getInnerJSONObject();
}
});

Categories

Resources