parsing json result with generics - android

I have an app which sends a REST request to a server and receives a JSON response back. However, my REST client service on the app may send out several different types of REST request which will result in different responses causing different types of objects being created on the client android app. Each response will always be an array of some type of object.
Here is what I have so far:
#Override
protected List<?> doInBackground(String... urls) {
requestType = urls[0];
InputStream source = retrieveStream(Constants.REST_SERVER_URL + requestType);
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
List<?> result = gson.fromJson(reader, List.class);
return result;
}
protected void onPostExecute(List<?> result) {
if(requestType.equals(Constants.GET_OSM_POI_NODES)) {
Log.v(TAG, String.valueOf(result.size()));
ArrayList<Node> nodes = new ArrayList<Node>();
for(Object o : result) {
// create a node object from the result
}
}
}
In the onPostExecute method I want to create the correct object based on what REST url was used. So for example, if the url corresponding to GET_OSM_POI_NODES was used then it would construct an ArrayList of node objects which consists of a latitude and a longitude along with an id. Here is a sample JSON response for such an object:
[
{
"id": 353941,
"lat": 754030751,
"lon": -39701762
},
...
The problem is that the result passed into onPostExecute is always a List of generic objects because I want it to be generic. I am not sure how to create Node objects from these generic types. Even if I don't use generics the objects passed into onPostExecute are list of StringMap and I don't know how to create different types of object from these.
Any ideas?
Anyone have any idea?
Thanks

Related

Using Volley without Gson

Today I got to know that Retrofit uses gson(or any other convertor) to serialize or deserialize the json response (response that was got using okhttp or any related library).
Now, when I was naive(in some sense still am) and I used to use Volley and at that time I never used Gson or any related library and same for okhttp.But i used to get my response and inflate it successfully on my views.
1. Now does Volley internally do what Retrofit does using Gson and Okhttp?
If not? 2. Then how did i able to get values parsed without using anything?
Below is the sample Codes that i used to write:-
JsonObjectRequest jsonObjectRequest=new JsonObjectRequest(
Request.Method.POST, URL_THUMB, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray=response.getJSONArray("server_response");
for(int i=0;i<jsonArray.length();i++)
{
JSONObject jsonObject=(JSONObject)jsonArray.get(i);
String id=jsonObject.getString("id");
String artist_name=jsonObject.getString("artist_name");
String img_id=jsonObject.getString("img_id");
listId.add(id);
listArtistName.add(artist_name);
listImgID.add(img_id);
}
recyclerView.setAdapter(comedy_adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}
);
and now just inflate these list values to my views.
Where did I go wrong? (I don't think I was wrong as things went well and code always run fine)
In your example you're parsing the response into JSON arrays and objects manually. Converters such as Gson let you parse the response into a variable of a custom object in a single line.
For example, if I have the following model:
public class Model {
private int id;
private String name;
}
I can parse a string response using the following code:
Model model = gson.fromJson(str, Model.class);
Otherwise, you have to do it manually, like what you're doing at the moment:
JSONObject jsonObject = response.getJSONObject("str");
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
Model model = new Model(id, name);
In Retrofit 2 you don't even have to call fromJson - you simple receive the object you expect as an input parameter in onResponse. It's very useful when dealing with more complex models.

Response Code 400 Bad Request when use Json String param in Query tag Retrofit 2 Android

I'm using Retrofit 2 to call API in Android App. I have a API, using POST, which have a String param in Query Tag. I do everything like doc suppose and I test this API successfully in Test Page. I can run another API correctly so the problem is not the way I use Retrofit 2.
Here is my interface:
#POST("/users/{userId}/get_list_friends")
Call<GetListFriendDataResponse> getListFriend(#Path("userId") int userId, #Query("list") String list, #Query("page") int page, #Query("size") int size, #Header("hash") String hash);
Here is my implementation:
ArrayList<String> id = new ArrayList<>();
id.add("4782947293");
JSONArray jsonArray = new JSONArray(id);
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("list", jsonArray);
} catch (JSONException e) {
e.printStackTrace();
}
String list = jsonObject.toString();
Log.e(TAG, "list: " + list);
apiInterface.getListFriend(21, list, 1,1,"AHHIGHTJGI").enqueue(new Callback<GetListFriendDataResponse>() {
#Override
public void onResponse(Call<GetListFriendDataResponse> call, Response<GetListFriendDataResponse> response) {
Log.e(TAG, " response code: "+ response.code());
}
#Override
public void onFailure(Call<GetListFriendDataResponse> call, Throwable t) {
}
});
I always get response code: 400 when use this API.
I'm focusing the "list" var. "list" is a JSON text but I wonder if method "jSon.toString()" is right to get a String from a JSONObject, which can using in Retrofit 2. List param form is:{"list":["12332"]} .
Please help me!
Questions
1) Why you are creating JSONObject and JSONArray on your own?
2) You are creating string using whatever you are creating json.
Eg: {list:["123","456"]}
you are trying pass whole json, I think, instead you need to pass just the array of string to the list key.
Request Sending
{
list:["123","456"]
}
suppose the above json is the request you want to send to server
Now, create model class goto http://jsonschema2pojo.org and paste your json and select json and gson at right side and click on preview.
It will show the classes to map you json to model. Use this model class to set the list to the key in your json
I found my problem. The JSON text contains some special character so I need to convert them to URL encode.
Correct request URL like this:
http://54.169.215.161:8080/users/29/add_friend?list=%7B%22list%22%3A%5B%2215536%22%5D%7D&platform=google
By using Retrofit 2, it uses the URL:
http://54.169.215.161:8080/users/29/add_friend?list={%22list%22:[%2215536%22]}&platform=google
So I get Bad Request Response code.
Retrofit 2 also provides method to convert char sequence to URL encode but it 's not enough. So I don't use Retrofit 's convert method by using this code: encode= true.
so my interface is:
#POST("/users/{userId}/get_list_friends")
Call<GetListFriendDataResponse> getListFriend(#Path("userId") int userId, #Query(value = "list",encoded = true) String list, #Query("page") int page, #Query("size") int size, #Header("hash") String hash);
And I manually convert JSON text to URL encode by code:
list = list.replace("{", "%7B");
list=list.replace("]", "%5D");
list=list.replace("[", "%5B");
list=list.replace(":", "%3A");
list=list.replace("}","%7D");
list = list.replace("\"", "%22");
That's all. Now I can get data by using API.
Suggestion: If u have the same problem, check the URL retrofit return in response and compare to correct URL to see special character, which is not converted to URL encode.

how to split data of two object from one JSON response?

from server i'm getting json response...but it contais data of two objects..one is of ArrayList Type and 2nd is one POJO(HomeVO) class. i want to split data and store into different objects. i am usnig GSON api.
Servlet:
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(new Gson().toJson(questions));
response.getWriter().write(new Gson().toJson(homeVo));
Json Response:
[{"questionId":2,"question":"Quality","typeOfQuestion":2}, {"questionId":3,"question":"Satisfaction","typeOfQuestion":1},{"questionId":4,"question":"overall","typeOfQuestion":2}]{"feedbackName":"IMS","expiryDate":"2014-12-12","createdDate":"2014-10-24","feedbackId":2}
Android Parsing:
HttpClient httpClient = WebServiceUtils.getHttpClient();
try {
HttpResponse response = httpClient.execute(new HttpGet(url));
HttpEntity entity = response.getEntity();
Reader reader = new InputStreamReader(entity.getContent());
data = gson.fromJson(reader, arrayListType);
} catch (Exception e) {
e.printStackTrace();
Log.i("json array",
"While getting server response server generate error. ");
}
You have two choices:
1. Manually parse the strings (What is not recommended)
2. Convert the JSon objects into objects using Gson and then convert it back into one json object also using Gson.
Let me know, if you need more detailed info
More expl.:
Lets say u have two different JSon string, called JsonA and JSonB.
in order to join them, you have to download the Gson library
class AClass{
int idA;
String nameA;
} // Note that the variable's names must be the same as the identifiers in JSON
class BClass{
int idB;
String nameB;
}
class JoinedClass{
BClass bClass;
AClass aClass; //don't forget getters and setters
}
public String joinJson(String JsonA , String JsonB){
Gson gson = new Gson();
AClass aClass = new AClass();
BClass bClass = new BClass();
aClass = gson.fromJson(JsonA, AClass.class);
bClass = gson.fromJson(JsonB, BClass.class);
JoinedClass joinedClass = new JoinedClass();
joinedClass.setAClass(aClass );
joinedClass.setBClass(bClass);
return gson.toJson(joinedClass);
}
// but you know, just after writing this code, i found that there might be an easier way to do this.
// Thanks for attention!
I believe you have two POJO classes for Questions and HomeVO. Then follow these steps:
You can create another DTO with two lists (questions and homeVo).
public class ResultDTO {
private List < HomeVO > homeVoList;
private List < Question > questionList;
//use your getters and setters here:
}
now, use those setters to set your values like you have already done.
then pass that object (ResultDTO) to your gson:
//assuming the ResultDTO object name is resultDto...
response.getWriter().write(new Gson().toJson(resultDto));
now if you check the result in client side, you may have a json response like below:
[questionList: [{
"questionId": 2,
"question": "Quality",
"typeOfQuestion": 2
}, {...}, ],
homeVoList: [{
"feedbackName": "IMS",
"expiryDate": "2014-12-12",
"createdDate": "2014-10-24",
"feedbackId": 2
}, {..}]
so you can get your json objects in response divided like this (this is for web, I dont know how you access it):
//assuming the json reponse is 'data':
var homeVoList = data.homeVoList;
var questionList = data.questionList;
try and see... just a guidance...haven't try actually..

how to parse complicated json in android

I have been following a tutorial and finally have understand to a decent degree using AsyncTask and how to send an http get request to get the json returned. I can get the json, I think successfully but am having trouble parsing it.
The tutorial I was looking at uses a pretty simple weather api which sends back pretty easy json to parse.
Mine is a search result with info on each item. My json looks like this:
http://pastebin.com/f65hNx0z
I realize the difference between json objects and the arrays of info. Just a bit confused on how to parse over to get information on each beer and the brewery info.
My code below:
String jsonUrl = url + query;
Toast.makeText(this, jsonUrl, Toast.LENGTH_SHORT).show();
//todo: get json
new ReadJSONResult().execute(jsonUrl);
return false;
}
private class ReadJSONResult extends AsyncTask
<String, Void, String> {
protected String doInBackground(String... urls) {
return readJSONFeed(urls[0]);
}
protected void onPostExecute(String result) {
try {
///code below is what I kow I need to reconstruct and change to parse
JSONObject jsonObject = new JSONObject(result);
JSONObject weatherObservationItems =
new JSONObject(jsonObject.getString("weatherObservation"));
Toast.makeText(getBaseContext(),
weatherObservationItems.getString("clouds") +
" - " + weatherObservationItems.getString("stationName"),
Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.d("ReadWeatherJSONFeedTask", e.getLocalizedMessage());
}
}
}
You should use a JSON deserializer library to object which supports nested objects, also. I recommend Gson https://code.google.com/p/google-gson/
There is a Java class generator from JSON response. jsongen.byingtondesign.com will parse your json response and give you Java Bean class. which will help you to understand the need.

Android, create differents kind of jsonObject

I would like to create a generic class which create my jsonObject.
Is it possible to create a class which can create differents kind of objects like
{"chunkSize":10,"filters"
[{"field":"segmentOwners.id","operator":"EQUAL","value":"11578","valueType":"java.lang.Integer"},
{"field":"language","operator":"EQUAL","value":"FR","valueType":"java.lang.String"},
{"field":"customerId","operator":"EQUAL","value":"77","valueType":"java.lang.Integer"}]
,"orderBy":[{"field":"creationTime","order":"DESC"}],"page":0}
OR just a simple request:
{login:"mylogin",pwd:"mypwd"}
I tried something like:
#Override
protected JSONObject doInBackground(String... params) {
byte[] result = null;
Iterator iter = mData.entrySet().iterator();
JSONObject jsonObj = new JSONObject();
Iterator it = mData.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
try {
jsonObj.put((String) pairs.getKey(), (String) pairs.getValue());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
it.remove(); // avoids a ConcurrentModificationException
}
But i'm not sure that is the same kind of hashmap (string, jsonObjet...?)
If you want to create instances of JSONObject from JSON strings, just do the following:
JSONObject jsonObj = new JSONObject("<your json string>");
I'd create generic container class (i.e. DataContainer) which would expose unified API no matter of what data it holds (i.e. setFromJson(), getData()). Then create separate object for each data structure (i.e. DataLogin, DataSomething). Then when you fetch your json data from remote source, you could i.e. create DataLogin object and hand it to your DataContainer (or pass json to DataContainer so it could detect DataLogin should be used and create it itself, but that require some logic which may not be best approach). Then all methods that are expected to work on your json data can be handed DataContainer object and method could do getType() on it (you need to set type yourself of course), which would return what data is stored and then getData() to get the data iself to work on.

Categories

Resources