Android: Is it the right approach to convert JSON to POJO? - android

I'm using Volley Library to get JSON responses on my requests. I created base http Helper classes which process requests and return JSON for next processing.
I would like to ask what is the right approach to process returned JSON data?
I would like to use data for displaying in ListView, View, etc. but I don't know what is the right approach (Convert to POJO or keep data in JSON?)
I tried to find any solution on this topic:
Json to POJO mapping in Android
But it seems that each object should have a single class with definition of the all possible fields of the object.
This approach seems strange to me because I have already created models for the database objects and if JSON object is changed (for example added new attribute or changed his name) it means that code on the API models should be changed too.
Is there any other possibility and the right way how to avoid this and work with returned data only in Activities (Controllers)?

Use GSON it is quite snappy and easy to use. for e.g.
Gson gson = new Gson(); // Or use new GsonBuilder().create();
MyType target = new MyType();
String json = gson.toJson(target); // serializes target to Json
MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2

Read my answer completely, i've explained in easy way.
First of all if you are using Volley no need of http helper class, use Volley's method to get JSON data by objects or array.
Second POJO classes are best use it. yes it is the right approach.
Here is the source code to get json object data from volley and store in POJO.
/**
* Method to make json object request where json response starts wtih {
* */
private void makeJsonObjectRequest() {
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET,
"http://api.example.com", null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
try {
// Parsing json object response
// response will be a json object
String name = response.getString("name");
String email = response.getString("email");
//POJO class to store
Person person = new Person();
person.name=name;
person.email=email;
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
hidepDialog();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_SHORT).show();
// hide the progress dialog
hidepDialog();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq);
}

I would definitely suggest you transform JSON to POJOs and use this. It is much more natural to use objects to represent data in an object oriented language, such as Java.
I would like to ask what is the right approach to processing returned JSON data?
There are two main options:
Use the built - in JSON SDK - it is a very decent tool and is adequate if you don't have complex response structures. It can be quite performant.
Use some kind of a third party JSON processing library - GSON or Jackson. They come stacked with functionality, like automatic deserialisation from JSON to POJO based on annotations, etc. This can save you time, but it is expensive. To get the best performance out of this, you should still parse the things manually, but you can start doing this only if you need to optimise.
No matter what you use, just make sure that JSON processing is done on a worker thread. If you are using Volley, you should consider extending a Request class and overriding parseNetworkResponse() - this is a good place to plug in your deserialisation. The responses will now be POJOs and you can use them to populate lists, etc.
As far as this goes:
This approach seems to me strange because i have already created models for the database objects and if JSON object is changed (for example added new attribute or changed his name) it means that code on the API models should be changed too.
Unfortunately, you are right. But this is a common problem in client - server communication. When using JSON over HTTP there is no way to enforce that the contract between server and client is being followed. The best you could do, IMHO, is detect the possible exceptions and handle them accordingly - showing a message to the user, or something like that. You can always use Maps to hold the deserialised payload as key - value pairs, but this doesn't really solve the issue, but ensures the deserialisation logic wont' fail.

Related

How to handle such a json properly?

The problem is next.
In response I have JSON like
{
object: {
// a lot of different fields
}
}
I use Retrofit with gson parser. What I really need is just this object. I don't want to create class for response with the only one field. All responses server send in a such manner. As far I understand somewhere I need place simple code for fetching that one object and then use default parser for it.
Probably sorry for stupid question. I used Volley and there was quite a different approach.
Instead of creating a special class to handle this (and another special class for every other server response), just use Map<String, YourRealObjectType>. Then use this method to extract the YourRealObjectType instance for each response:
public static <T> T getFirstValue(Map<String, T> map) {
return map.values().iterator().next();
}
you can convert class into JsonObject class. then cal iterate all the elements in it one by one
#Get
ObservablegetData();
Note : use JsonObject not JSONObject

Android: Compute properties after GSON deserialization finished

In one of my apps I have a generic Volley web service which I use to load data from our servers and deserialize them sing GSON like so:
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
T parsedJson = mGson.fromJson(json, mType);
return Response.success(parsedJson, HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
Now one of the objects I'm deserializing is a little bit special since its json model contains of two lists but in code I need a dictionary where ids of the first lists objects are the keys and arrays of the second lists objects are the values.
I also need to sort the two lists after they have been deserialized. (I begged our backend devs to do the sorting and deliver me a proper json model but they refuse to do that, don't ask me why...).
Anyways, now I need a way to do the sorting as well as the calculation of the properties.
In iOS I'm using SwiftyJson which is not really the automatic JSON deserialization you'd get from GSON but there I can calculate and sort the necessary fields in the background thread where I "deserialize" the obejcts.
On Android though, I have this generic function and therefore no clue which object I'm currently deserializing and as far as I'm concerned, GSON uses a default constructor and writes to the fields directly rather than using setters.
So now I'm stuck. I wonder when the best situation would be to calculate my fields. I thought about these ways:
Add a transient boolean to check if I already sorted the lists. When accessing the getter for the lists, the first time it is false so I know I have to sort. I sort the list, store the sorted list back and then return it. For the calculated dictionary, I'd just had to check if its null and if so, calculate it
Implement some sort of PostDeserializable interface with a single method. In the generic web service, I could check if the T parsedJson is an instance of that interface and if so, call the method on it.
The later would had the advantage that it would run in the background but I also had to remember that interface (which might be problematic for new developers who don't know about it). The first however could have an impact since it most likely would run in the UI thread.
I wonder if there is a default way in GSON to execute some post serialization method, maybe via annotations? Hope you can help me find the best way with the least amount of custom code.
Okay so apparently there is no default way of doing it. Though there is a similar interface to the one I suggested in my original post but it is only available in the gson-extras which are not published via maven so one can not simply include it in the gradle file. Instead, one would have to manually download it and keep it up to date.
For me that seems to be unnecessary work and including the whole gson-extras for just this one interface seems to be a little bit over the top. After testing both of my approaches, I think I will stick with the interface solution I suggested.
I changed my JSON volley base request (from which all of my JSON requests inherit) to the following:
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
T parsedJson = mGson.fromJson(json, mType);
if (parsedJson instanceof PostDeserializable) {
PostDeserializable postDeserializable = (PostDeserializable) parsedJson;
postDeserializable.postDeserialization();
}
if (parsedJson instanceof Object[]) {
Object[] array = (Object[]) parsedJson;
for(Object value : array) {
if (value instanceof PostDeserializable) {
PostDeserializable postDeserializable = (PostDeserializable) value;
postDeserializable.postDeserialization();
}
}
}
return Response.success(parsedJson, HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
The PostSerializable interface looks pretty simple as well:
public interface PostDeserializable {
void postDeserialization();
}
And to use it, all I have to do is to implement it on my model POJOs. Notice that I check if the T parsedJson itself is an instance of my interface as well as I check if it is an array and if so, if the objects in the array are of that type.
For me that is enough because I only every have the need for a PostSerializable if the top level object is an instance of it or if the top level object is an array of PostSerializables.
This is not a general solution because it does not cover cases, where the PostSerializable is for example in the 2nd level of another model.
In such a case, I think it would definitely make sense to use gson-extras.

What is the best way to parse JsonObject containing just one enormous JsonObject (Gson)

I have a Json of this type :
{
"4f958ef28ecd651095af6ab6": {
enormous JsonObject
}
}
the "4f958ef28ecd651095af6ab6" is different each time (but I know what it will be as it is a parameter of my api call), it corresponds to the id of the following object. I have a Gson-configured model to parse the enormous JsonObject.
My question is : is it performant to use simply
new JSONObject(jsonresponse).getJSONObject("4f958ef28ecd651095af6ab6")
and parse with Gson from there ?
Is there a better way to do so ?
I guess the real question would be, what does "new JSONObject(String)" realy do ?
Thanks
What you are doing is:
You load all the Json string into the phone memory (memory issue + long time to load entirely)
You create a big JSONObject (same issues) in order to have access to each key.
You write few code but this is not the most performant solution.
To minimized the memory impact and accelerate the operation of objects' creation, you can use Gson in stream mode.
By directly read the input stream, you avoid to load too much data and you can directly start to populate your object piece by piece.
And about the JSONObject, it will mostly check if your json string is correct (or it will throw a JsonException) and it will let you look into the object when you search for a key and its value.
I would recommend use hybrid (native and gson) since i am not sure how to get unknown jsonobject with GSON.
You need to get your response as a JSONArray, then itarete for each JSONObject. You can experiment parsing code as trying. Please check JSONArray.getJSONObject(int index) method. Then we can use GSON to get our data model to get known attributes.
If you can post complete json data, we can give it chance to parse together.

Android and Azure Mobile Services: Using invokeAPI to return recordset

I am trying something very simple. I have a custom API called "missingvehiclesfrominventoryjob" and it simply returns a record set from an standard SQL Query.
I can do this in my WinForms and Windows Phone app easily but I cannot figure out how to do this on the Android App.
Here is my code: (which DOES NOT COMPILE in Android Studio):
msClient.invokeApi("missingvehiclesfrominventoryjob", kd, new
ApiOperationCallback<List<InventoryProspects>>(){
#Override
public void onCompleted(List<InventoryProspects> missingVehicles, Exception e,
ServiceFilterResponse serviceFilterResponse){
for (InventoryProspects item : missingVehicles){
mAdapter.add(item);
}
}
});
The problem is the List in the parameters of the Callback. I am not sure how to indicate that the invoiceAPI call will return multiple rows from the database and I cannot find anywhere in the docs to explain how. Nor can I find an example ANYWHERE on the internet.
I am sure I am not the only on trying to do this.
Thanks in advance
Chuck Giddens
What i did to overcome this problem, is to call a different overload of invokeApi that returns a JsonElement, and then deserialise it into my objects like so:
mClient.invokeApi("MyCustomApi",null, "GET", null, new ApiJsonOperationCallback() {
#Override
public void onCompleted(JsonElement jsonElement, Exception e, ServiceFilterResponse serviceFilterResponse) {
GsonBuilder gsonb = new GsonBuilder();
Gson gson = gsonb.create();
JsonArray array = jsonElement.getAsJsonArray();
List<MyObject> myObjects = new ArrayList<MyObject>()>
for(int i = 0; i < array.size(); i++)
{
myObjects.add(gson.fromJson(array.get(i).getAsJsonObject().toString(), MyObject.class));
}
}
});
I haven't had a chance to test it yet (will try when I have time and edit answer as needed) but my thinking is that the Android SDK won't allow you to do what you're trying to do. The invokeApi methods expect a strongly typed class to be set as the response type (or you can use the raw JSON methods). In this case, you're trying to say you want a list of items back, but I don't think that will work. I think you'll instead need to create a new class (i.e. missingvehiclesfrominventoryjobResponse) which contains a property that is of type List< InventoryProspects>. Note that you'll need to change your method call to actually match one of the available options for invokeApi which I don't believe it's doing right now. You can read more about the different formats of the method here: http://blogs.msdn.com/b/carlosfigueira/archive/2013/06/19/custom-api-in-azure-mobile-services-client-sdks.aspx
Alternatively, you can use the table methods against a table endpoint where the read expects a collection of results back.
Have you tried to remote debug your API call from the app.[http://blogs.msdn.com/b/azuremobile/archive/2014/03/14/debugging-net-backend-in-visual-studio.aspx]. Your app will timed out in doing that but you can see line by line execution of your controller action if it returns the correct result set. If there is no problem with it then the problem should be in parsing result set.
What is the exception you are getting in callback? And have you tried using other method parameters such as passing with different HTTP methods? Use this as a reference as well. http://azure.microsoft.com/en-us/documentation/articles/mobile-services-android-get-started/
Please paste your exception or either controller action, and the object structure of the data transfer object of the result set.

Android parsing JSON vs JSON Overlay

I wondering what folks think about the PROS/CONS of parsing JSON to POJOs vs. using JSON overlay objects.
Use Case: REST call that returns Person JSON documents.
e.g.
[{"name":"name1"}, {"name":"name2}, ...]
Solution 1:
Parse all incoming JSON into POJOs using GSON, Jackson, JSONObject/JSONArray (manual), etc.
Result:
class Person {
String name;
public String getName() {
return name;
}
}
Solution 2:
Create overlay class that uses JSONObject access methods.
Result:
class Person {
JSONObject json;
public String getName() {
json.getString("name");
}
}
In particular, I am interested in terms of limited system ressources on Android. Do I want to incur the parsing cost upfront and use more memory, or do I want to incur the parsing cost during data access such as in a ListView.
Does it matter?
I would usually prefer Solution 1.
Downloading and parsing as a single asynchronous task is pretty simple. Parsing should be quite fast compared to downloading from the web.
The JSON data can be removed from memory after parsing is done and the required memory is lower at that point.
Accessing the data is then faster than in Solution 2 - fast access is essential if you want to use it in the UI thread to e.g. update the items in a ListView.
But there are scenarios where Solution 2 should yield better results. Like when there are thousands of people or the data changes faster than you can parse it. A ListView requests just the data that is currently visible so parsing would be done only on demand and would become more or less independant from the amount of data that exists for invisible items.
And in case parsing a single item takes really long, Solution 2 can also be used with an asynchronous approach like the async image loaders used with ListViews. I would use something like below in that case since that prevents that parsing needs to be repeated for the same object all the time.
class Person {
boolean parsed;
String name;
JSONObject json;
public String getName() {
if (!parsed) {
name = json.getString("name");
json = null;
parsed = true;
}
return name;
}
}

Categories

Resources