Parse Nested JSON Array from Notification Data using Gson in Android - android
I am getting data in JSON format from FCM notification. It has different format based on notification types as below:
Format 1: accept_request:
{
"alert": "Accept Request By driver",
"title": "Accept Request By driver",
"booking_id": "247",
"notification_type": "accept_request"
}
Format 2: end_request:
{
"alert": "End trip By driver",
"title": "End trip By driver",
"booking_id": "247",
"notification_type": "end_request",
"servicesList": [
{
"service_id": "1",
"service_name": "Services1",
"status": "true",
"sub_category": [
{
"sub_cat_id": "1",
"sub_cat_name": "Doctors on call",
"service_cost": "15.00",
"service_cat_id": "1",
"cost": 0
}
],
"is_multiple_choose": "0",
"total_cost": 15
}
}
I have create CommonNotificationBean.java as POJO class. I have successfully parsed data for accept_request.
Its working because all key has String values and remoteMessage.getData() also returning Map<String, String> type values.
Code:
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData().get("notification_type"));
Map<String, String> params = remoteMessage.getData();
JSONObject object = new JSONObject(params);
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(object.toString()));
reader.setLenient(true);
CommonNotificationBean bean = gson.fromJson(reader, CommonNotificationBean.class);
sendNotification(bean);
}
PROBLEM:
Now I am stuck with problem while parsing end_request data because it has Nested JSON Array.
Read it carefully:
What can I do for dynamic data instead of Map<String, String> because it will not convert data into Map<String, String> type as it has some List type values.
Anyone can help?
And finally I got solution by adding some drops of concepts. :)
I got many problems to converting in JSON with proper format like:
Unterminated object at character
MalformedJsonException
and Finally following code get worked for me.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "remoteMessage.getData() : " + remoteMessage.getData());
// Map<String, String> stringStringMap = remoteMessage.getData();
JSONObject object = new JSONObject(remoteMessage.getData());
Log.d(TAG, "new JSONObject(remoteMessage.getData()) : " + object.toString());
String finalJSON = object.toString().replaceAll("\\\\", "").replace("\"[", "[").replace("]\"", "]");
Log.d(TAG, "Replace all back slash and invalid double quotes : " + finalJSON);
CommonNotificationBean bean = new Gson().fromJson(finalJSON, CommonNotificationBean.class);
sendNotification(bean);
}
Logcat:
remoteMessage.getData(): Getting data without double quotes.
remoteMessage.getData() : {content-available=1, notification_type=end_request, booking_id=247, priority=high, base_price=35, totalMinutePrice=1.5, alert=End trip By driver, sound=default, title=End trip By driver, total_amount=397, address_from=A/ 4 forum bungalow Nr. Hicort, Sola, Ahmedabad, Gujarat 380015, India, service_cost=360, servicesList=[{"total_cost":15,"sub_category":[{"cost":0,"sub_cat_name":"Doctors on call","sub_cat_id":"1","service_cost":"15.00","service_cat_id":"1"}],"service_name":"Services1","service_id":"1","is_multiple_choose":"0","status":"true"},{"total_cost":95,"sub_category":[{"cost":0,"sub_cat_name":"Hand","sub_cat_id":"3","service_cost":"20.00","service_cat_id":"2"},{"cost":0,"sub_cat_name":"Body","sub_cat_id":"4","service_cost":"75.00","service_cat_id":"2"}],"service_name":"Dressing","service_id":"2","is_multiple_choose":"1","status":"true"},{"total_cost":0,"sub_category":[{"cost":0,"sub_cat_name":"No","sub_cat_id":"7","service_cost":"0.00","service_cat_id":"3"}],"service_name":"Do you need oxygen?","service_id":"3","is_multiple_choose":"0","status":"true"},{"total_cost":30,"sub_category":[{"cost":0,"sub_cat_name":"Level 3","sub_cat_id":"10","service_cost":"30.00","service_cat_id":"4"}],"service_name":"Lift\/Stairs Accessibility","service_id":"4","is_multiple_choose":"0","status":"true"},{"total_cost":220,"sub_category":[{"cost":0,"sub_cat_name":"Ventilator","sub_cat_id":"12","service_cost":"100.00","service_cat_id":"5"},{"cost":0,"sub_cat_name":"Intracenous (IV) drip","sub_cat_id":"13","service_cost":"120.00","service_cat_id":"5"}],"service_name":"Other Medical","service_id":"5","is_multiple_choose":"1","status":"true"},{}], tripdatetime=2019-03-27 10:57:51, address_to=19/20, Chanakyapuri, Ahmedabad, Gujarat 382481, India, notification_date_time=28-03-2019 17:24:09}
new JSONObject(remoteMessage.getData()) : Converted to JSONObject but getting unwanted back slash and double quotes
new JSONObject(remoteMessage.getData()) : {"content-available":"1","notification_type":"end_request","booking_id":"247","priority":"high","base_price":"35","totalMinutePrice":"1.5","alert":"End trip By driver","sound":"default","title":"End trip By driver","total_amount":"397","address_from":"A\/ 4 forum bungalow Nr. Hicort, Sola, Ahmedabad, Gujarat 380015, India","service_cost":"360","servicesList":"[{\"total_cost\":15,\"sub_category\":[{\"cost\":0,\"sub_cat_name\":\"Doctors on call\",\"sub_cat_id\":\"1\",\"service_cost\":\"15.00\",\"service_cat_id\":\"1\"}],\"service_name\":\"Services1\",\"service_id\":\"1\",\"is_multiple_choose\":\"0\",\"status\":\"true\"},{\"total_cost\":95,\"sub_category\":[{\"cost\":0,\"sub_cat_name\":\"Hand\",\"sub_cat_id\":\"3\",\"service_cost\":\"20.00\",\"service_cat_id\":\"2\"},{\"cost\":0,\"sub_cat_name\":\"Body\",\"sub_cat_id\":\"4\",\"service_cost\":\"75.00\",\"service_cat_id\":\"2\"}],\"service_name\":\"Dressing\",\"service_id\":\"2\",\"is_multiple_choose\":\"1\",\"status\":\"true\"},{\"total_cost\":0,\"sub_category\":[{\"cost\":0,\"sub_cat_name\":\"No\",\"sub_cat_id\":\"7\",\"service_cost\":\"0.00\",\"service_cat_id\":\"3\"}],\"service_name\":\"Do you need oxygen?\",\"service_id\":\"3\",\"is_multiple_choose\":\"0\",\"status\":\"true\"},{\"total_cost\":30,\"sub_category\":[{\"cost\":0,\"sub_cat_name\":\"Level 3\",\"sub_cat_id\":\"10\",\"service_cost\":\"30.00\",\"service_cat_id\":\"4\"}],\"service_name\":\"Lift\\\/Stairs Accessibility\",\"service_id\":\"4\",\"is_multiple_choose\":\"0\",\"status\":\"true\"},{\"total_cost\":220,\"sub_category\":[{\"cost\":0,\"sub_cat_name\":\"Ventilator\",\"sub_cat_id\":\"12\",\"service_cost\":\"100.00\",\"service_cat_id\":\"5\"},{\"cost\":0,\"sub_cat_name\":\"Intracenous (IV) drip\",\"sub_cat_id\":\"13\",\"service_cost\":\"120.00\",\"service_cat_id\":\"5\"}],\"service_name\":\"Other Medical\",\"service_id\":\"5\",\"is_multiple_choose\":\"1\",\"status\":\"true\"},{}]","tripdatetime":"2019-03-27 10:57:51","address_to":"19\/20, Chanakyapuri, Ahmedabad, Gujarat 382481, India","notification_date_time":"28-03-2019 17:24:09"}
Final JSON :
Replace all back slash and invalid double quotes : {"content-available":"1","notification_type":"end_request","booking_id":"247","priority":"high","base_price":"35","totalMinutePrice":"1.5","alert":"End trip By driver","sound":"default","title":"End trip By driver","total_amount":"397","address_from":"A/ 4 forum bungalow Nr. Hicort, Sola, Ahmedabad, Gujarat 380015, India","service_cost":"360","servicesList":[{"total_cost":15,"sub_category":[{"cost":0,"sub_cat_name":"Doctors on call","sub_cat_id":"1","service_cost":"15.00","service_cat_id":"1"}],"service_name":"Services1","service_id":"1","is_multiple_choose":"0","status":"true"},{"total_cost":95,"sub_category":[{"cost":0,"sub_cat_name":"Hand","sub_cat_id":"3","service_cost":"20.00","service_cat_id":"2"},{"cost":0,"sub_cat_name":"Body","sub_cat_id":"4","service_cost":"75.00","service_cat_id":"2"}],"service_name":"Dressing","service_id":"2","is_multiple_choose":"1","status":"true"},{"total_cost":0,"sub_category":[{"cost":0,"sub_cat_name":"No","sub_cat_id":"7","service_cost":"0.00","service_cat_id":"3"}],"service_name":"Do you need oxygen?","service_id":"3","is_multiple_choose":"0","status":"true"},{"total_cost":30,"sub_category":[{"cost":0,"sub_cat_name":"Level 3","sub_cat_id":"10","service_cost":"30.00","service_cat_id":"4"}],"service_name":"Lift/Stairs Accessibility","service_id":"4","is_multiple_choose":"0","status":"true"},{"total_cost":220,"sub_category":[{"cost":0,"sub_cat_name":"Ventilator","sub_cat_id":"12","service_cost":"100.00","service_cat_id":"5"},{"cost":0,"sub_cat_name":"Intracenous (IV) drip","sub_cat_id":"13","service_cost":"120.00","service_cat_id":"5"}],"service_name":"Other Medical","service_id":"5","is_multiple_choose":"1","status":"true"},{}],"tripdatetime":"2019-03-27 10:57:51","address_to":"19/20, Chanakyapuri, Ahmedabad, Gujarat 382481, India","notification_date_time":"28-03-2019 17:24:09"}
Full code : MyFirebaseMessagingService.java
Hope it will be help to others.
It is simple, you should just have an abstract Notification object with the attributes alert, title and notification_type. And then, have specific implementations based on your possible types, so far:
AcceptRequestNotification extends Notification with just an int booking_id (this is the one you already have, the one you called CommonNotificationBean)
EndRequestNotification extends Notification which contains for example, an ArrayList called servicesList, this ArrayList should be of type Service and then, service would have the attributes: service_id, service_name, status, sub_category which is again another ArrayList of a custom type.
And then you just change your code to be:
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData().get("notification_type"));
Map<String, String> params = remoteMessage.getData();
JSONObject object = new JSONObject(params);
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(object.toString()));
reader.setLenient(true);
Class typeOf;
switch(remoteMessage.getData().get("notification_type")) {
case "accept_request":
typeOf = AcceptRequestNotification.class;
break;
case "end_request":
typeOf = EndRequestNotification.class;
break;
}
//you can cast this object later on (to the corresponding custom subclass of Notification), based on the notif.getNotificationType() value.
Notification notif = gson.fromJson(reader, typeOf);
sendNotification(notif);
}
Related
Missing keys in JSON format
I am trying to parse a JSON string in Android which is dynamical. It is a very simple JSON structure. Similar to the following: { "a": 1, "b": 2, "c": 3, "d": 4, "e": 5 } But sometimes I don't get some keys. For example, the key "b" could be missing. Then my code generates a JSONParser Exception. And the further JSON string could not parsed. So is there any way to ignore missing keys? I tried optString(); but that only works in String case, what about JSONObject and JSONArray? optJSONArray() and optJSONObject() don't work. Any idea or solution?
I think the easiest way is to use GSON! You simply create a plain old java object (POJO) representing the data you want and let GSON do the rest. If the value doesn't exist in the json string, it'll be set to the "default" for that type (usally null, but is 0 for ints, false for booleans etc...) To include in your Android Studio project: compile 'com.google.code.gson:gson:2.2.4' Also take a look at this page, with particular attention to the "Object Examples" heading for how to use GSON.
You can find dynamic key using belo String jsonString = "{ \"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4, \"e\": 5 }"; try { JSONObject jsonObject = new JSONObject(jsonString); JSONObject issueObj = new JSONObject(jsonString); Iterator iterator = issueObj.keys(); while(iterator.hasNext()){ String key = (String)iterator.next(); Integer value = (Integer) issueObj.get(key); Log.d(TAG,"value: "+value); } } catch (JSONException e) { e.printStackTrace(); } Or you can use GSON.
You can try convert that JSONObject to a Map using GSON, like the following: String json1 = "{\n" + " \"a\": 1,\n" + " \"b\": 2,\n" + " \"c\": 3,\n" + " \"d\": 4,\n" + " \"e\": 5\n" + "}"; Gson gson1 = new Gson(); Type type1 = new TypeToken<Map<String, Integer>>(){}.getType(); Map<String, Integer> myMap1 = gson1.fromJson(json1, type1); In your build.gradle file: compile 'com.google.code.gson:gson:2.3.1'
Get json array length and looping
So I have a json response from web service like this { error: false types: [2] -0: { card_type_id: 5 category: "Food & Beverages" } -1: { card_type_id: 8 category: "Entertaiment" } } what I want to do is to get the number inside json array "types" and use it to looping to set the value of arraylist that will be use in listview, but my code seems and cannot get the json array length, this is my code JSONObject obj = new JSONObject(response); if(!obj.getBoolean("error")){ JSONArray types = obj.getJSONArray("types"); for(int i=0; i<types.length();i++) { JSONObject a = types.getJSONObject(i); int ct_id = a.getInt("card_type_id"); String category = a.getString("category"); CardType ct = new CardType(); ct.setTypeId(_ct_id); ct.setTypeCategory(_category); categoryArray.add(ct); } } Can anyone help me? Thanks before
This is what your JSON response probably should look like (note also that keys and string values should be sorrounded by double-quotes): { "error": false, "types": [ { "card_type_id": 5, "category": "Food & Beverages" }, { "card_type_id": 8, "category": "Entertaiment" } ] } The JSONArray "types" in this example has a length (types.length()) of 2. Now you can implement your for-loop and should get the expected results.
actually it's just my fault to see the json from advanced rest client, i use the json menu and the app automatically correct the json and become invalid, after i change to raw menu i can see the actual json and correct the code
Android GCM: Can we get data as a complete JSON structure?
I am sending a message (POST) to Google GCM server https://android.googleapis.com/gcm/send for sending a push notification to a registered android device. The POST body looks something like this: { "registration_ids" : [android_registration_id], "data" : { "message" : "Hello World!", "update" : "You've got a new update", "info" : "You've got new information updates too!" } } Suppose that I don't know what all key-value pairs are being sent to me (gcm registered android app) in the "data" field and I want to enumerate and print them, can I extract the fields in "data" as a JSON structure? For e.g. In the above example, I need the following as a JSON object: { "message" : "Hello World!", "update" : "You've got a new update", "info" : "You've got new information updates too!" }
Bundle data = intent.getExtras(); Iterator<String> it = data.keySet().iterator(); String key; String value; while(it.hasNext()) { key = it.next(); value = data.getString(key); } Try this. Using key and value you can construct initial json.
JSONArray array = new JSONArray(jsonBodyOfTheResponse); for (int i = 0; i < array.length(); i++) { JSONObject row = array.getJSONObject(i); . . . }
json android: parsing json
I have a json : [ {user:"John",s:"Ldh",e:"usa"},{user:"Paul",s:"bukit panjang ",e:"FedExForum - Memphis"},{user:"ross",s:"bukit panjang ",e:"FedExForum - Memphis "}] I am parsing this with the following code to retrieve all the values of "user" .. public class ListViewAndroidActivity extends ListActivity { private String newString, user; ArrayList<String> results = new ArrayList<String>(); #Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TestServiceActivity test = new TestServiceActivity(); //This returns json from the server newString = test.readPooledFeed(); // returned json in string format JSONArray rootArray = new JSONArray(newString); int len = rootArray.length(); for(int i = 0; i < len; ++i) { JSONObject obj = rootArray.getJSONObject(i); user = obj.optString("user"); results.add(user); } } This gives me no error.. but nothing is shown on the screen .. kindly help!
optString : Get an optional string associated with a key. I don't see the key u in your JSON object, shouldn't it be user = obj.optString("user");
JSON formatting Your JSON data is not valid, it's valid as javascript, but not as JSON. All properties should be quoted in JSON: [ { "user": "John", "s": "Ldh", "e": "usa"}, { "user":"Paul", "s":"bukit panjang ", "e": "FedExForum - Memphis" }, { "user": "ross", "s":"bukit panjang ", "e":"FedExForum - Memphis "} ] Indentation is not needed, I just did it to make it clearer. Missing field Your parser seems to ignore that your input data is invalid. Other problem could be as others mentioned you're requesting the u property at user = obj.optString("u"); which does not exists.
Could someone help me with parsing this JSON file?
I have this JSON file: { "ics_desire":{ "version":"Beta 0.1.1", "description":"description here", "build-fingerprint":"fingerprint" } Now I want to put the version part in a txtVersion textview and the description part in the txtDescription textview. Would someone help me?
So first off to state what was said above you JSON code is incorrectly formatted. You can validate you have correctly formated JSON code by going to http://json.parser.online.fr/. Your correct JSON would be as follows (you were missing a closing }) { "ics_desire": { "version": "Beta 0.1.1", "description": "description here", "build-fingerprint": "fingerprint" } } Next, here is an example of a working JSON code that I have used to test with in the past. { "HealthySubstituteData": [ { "Assoc_ID": "1", "uFood": "White Flour", "hFood": "Wheat Flour", "Category": "Baking", "Description": "You can substitute blah blah blah...", "Count": "5", "submittedBy": "Administrator" } ] } And here is the code I use to get that data. ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>(); JSONObject json = JSONfunctions.getJSONfromURL("http://your.url.com/whaterver"); try { JSONArray healthySubstituteData = json.getJSONArray("HealthySubstituteData"); for(int i=0;i<healthySubstituteData.length();i++) { HashMap<String, String> map = new HashMap<String, String>(); JSONObject e = healthySubstituteData.getJSONObject(i); map.put("Assoc_ID", (String) e.get("Assoc_ID")); map.put("uFood", (String) e.get("uFood")); map.put("hFood", (String) e.get("hFood")); map.put("category", (String) e.get("Category")); map.put("description", (String) e.get("Description")); map.put("count", (String) e.get("Count")); map.put("submittedBy", (String) e.get("submittedBy")); mylist.add(map); } } So now I end up with an array list of type HashMap and I can do whatever I want with it at that point.
You can create a simple class like public class Myclass{ String version; String description; String build-fingerprint; }; and then use Gson to convert json to your object and vice versa: Gson gson = new Gson(); Myclass obj = gson.fromJson(json_string, Myclass.class); json_string should contain your jason string. Now you can get your class objects values using getters. Note: Gson is an external library you need to import, download it from google.
Ignoring about the missing brackets in JSON, this code would help you through JSONObject json = JSONfunctions.getJSONfromURL("http://your.url.com/whaterver"); //the site where you get your JSON JSONObject daata = json.getJSONObject("ics_desire"); //grabbing the inner object String version = daata.getString("version"); //grabbing values String description = daata.getString("description"); txtVersion.setText(version); //Hope you have initialized the Views. txtDescription.setText(description);