Weird issue while parsing JSONObjects and converting to Java objects - java

This is the first time I am facing a very weird problem. I have a JSONObject mentioned below.:
Link for the JSON body (Cant paste JSON body here because of character limit):
http://kolam.vicz.in:7890/games_gifs/
I am parsing the above set of JSONObjects and converting them to Java objects. Below is my code of parsing this JSON body.
private void getGameList() {
StringRequest request = new StringRequest(Request.Method.GET, gameUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject mainObject = new JSONObject(response);
JSONArray gamesArray = mainObject.getJSONArray("TracingGames");
Log.e(TAG, "gameArray length:" + gamesArray.length());
for (int i = 0; i < gamesArray.length(); i++) {
JSONObject obj = gamesArray.getJSONObject(i);
for (String str : getKeys(obj)) {
Log.e(TAG, str);
if (str.equalsIgnoreCase("kolam")) {
/*Section for Learn and Kolam Tracing games start*/
//TODO: Need to add the game names to the object (Need server side implementation as well)
KolamTracingGames kolamTracingGames = new KolamTracingGames();
kolamTracingGames.setKolamGifPath(obj.getString("path"));
kolamTracingGames.setKolamLevel(Integer.parseInt(str));
kolamTracingGames.setKolamGameName("Kolam Tracing");
kolamTracingGames.setX(getXCoordinates(obj));
kolamTracingGames.setY(getYCoordinates(obj));
kolamObjects.add(kolamTracingGames);
break;
} else if (str.equalsIgnoreCase("level")) {
LearnTracingGames learnTracingGames = new LearnTracingGames();
learnTracingGames.setLearnGameGifPath(obj.getString("path"));
learnTracingGames.setLearnGameLevel(Integer.parseInt(str));
learnTracingGames.setGameName("Learn Game");
learnTracingGames.setX(getXCoordinates(obj));
learnTracingGames.setY(getYCoordinates(obj));
learnGameObjects.add(learnTracingGames);
Log.e(TAG, learnGameObjects.size() + "");
break;
}
}
}
if (gameType.equalsIgnoreCase("Trace the Kolam")) {
kolamTraceAdapter = new KolamTraceAdapter(getActivity());
kolamTraceAdapter.getGameList(kolamObjects);
recyclerView.setAdapter(kolamTraceAdapter);
} else if (gameType.equalsIgnoreCase("Learn")) {
learnGameAdapter = new LearningGameAdapter(getActivity());
learnGameAdapter.getGameList(learnGameObjects);
Log.e(TAG, "learngameobject size:" + learnGameObjects.size());
recyclerView.setAdapter(learnGameAdapter);
Log.e(TAG, "Learn games");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, error.getMessage());
if (getActivity() != null) {
Alerter.create(getActivity())
.setTitle(R.string.warning)
.setText(R.string.network_error)
.setDuration(2000)
.setBackgroundColorRes(R.color.dot_dark_screen1)
.show();
}
}
});
request.setTag(TAG);
request.setRetryPolicy(new DefaultRetryPolicy(30000, 5, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
AppController.getInstance().addToRequestQueue(request);
My problem is there are 8 level type objects and 4 kolam objects (Please refer the JSON body for clarity). I am having two separate POJO classes for them. I am able to parse the JSON body properly but when I am trying to create Java objects of those JSONObjects the inner most for loop is not running completely. Its stopping after 1 loop.
the inner for loop is not getting executed completely (executing only once but should get executed more then 12 times) if I am doing this (Creating Java Objects):
for (int i = 0; i < gamesArray.length(); i++) {
JSONObject obj = gamesArray.getJSONObject(i);
for (String str : getKeys(obj)) {
Log.e(TAG, str);
if (str.equalsIgnoreCase("kolam")) {
/*Section for Learn and Kolam Tracing games start*/
//TODO: Need to add the game names to the object (Need server side implementation as well)
KolamTracingGames kolamTracingGames = new KolamTracingGames();
kolamTracingGames.setKolamGifPath(obj.getString("path"));
kolamTracingGames.setKolamLevel(Integer.parseInt(str));
kolamTracingGames.setKolamGameName("Kolam Tracing");
kolamTracingGames.setX(getXCoordinates(obj));
kolamTracingGames.setY(getYCoordinates(obj));
kolamObjects.add(kolamTracingGames);
break;
} else if (str.equalsIgnoreCase("level")) {
LearnTracingGames learnTracingGames = new LearnTracingGames();
learnTracingGames.setLearnGameGifPath(obj.getString("path"));
learnTracingGames.setLearnGameLevel(Integer.parseInt(str));
learnTracingGames.setGameName("Learn Game");
learnTracingGames.setX(getXCoordinates(obj));
learnTracingGames.setY(getYCoordinates(obj));
learnGameObjects.add(learnTracingGames);
Log.e(TAG, learnGameObjects.size() + "");
break;
}
}
}
the getKeys(JSONObject) method is below:
private static String[] getKeys(JSONObject firstJSONObject) {
Iterator keysToCopyIterator = firstJSONObject.keys();
List<String> keysList = new ArrayList<>();
while (keysToCopyIterator.hasNext()) {
String key = (String) keysToCopyIterator.next();
keysList.add(key);
}
return keysList.toArray(new String[keysList.size()]);
}
But If I avoid creating objects inside the for loop then the inner for loop runs completely.

But If I avoid creating objects inside the for loop then the inner for
loop runs completely.
Integer.parseInt("level") or Integer.parseInt("kolam") which is clearly a crash
Explanation
when your any of if (str.equalsIgnoreCase("kolam")) or else if (str.equalsIgnoreCase("level")) { matches then
you clearly have a crash here , Integer.parseInt(str) because str will either be level or kolam which are clearly not integers
Solution : Don't use str instead fetch the values
if (str.equalsIgnoreCase("kolam")) {
//... code
kolamTracingGames.setKolamLevel(obj.optInt(str));
//... code ^^^^^^^^^^^^^^^
break;
} else if (str.equalsIgnoreCase("level")) {
//... code
learnTracingGames.setLearnGameLevel(obj.optInt(str));
//... code ^^^^^^^^^^^^^^^
break;
}

Related

How to put in array the children of the children

private static JSONArray getListOfChildPagesAsJSON(Page page) {
JSONArray pagesArray = new JSONArray();
try {
Iterator<Page> childPages = page.listChildren();
while (childPages.hasNext()) {
Page childPage = childPages.next();
JSONObject pageObject = new JSONObject();
pageObject.put(childPage.getTitle(), childPage.getPath());
pagesArray.put(pageObject);
}
} catch (JSONException e) {
LOG.error(e.getMessage(), e);
}
return pagesArray;
}
So that not only the children of the transferred page put into array, but also the children of the children.
This is a classical case for recursion, like reading directoy tree on filesystem. My suggestion is as follows:
First step: Change the scope of variable JSONArray pagesArray = new JSONArray(); from function to class scope.
public MyClass {
private JSONArray pagesArray = new JSONArray();
...
}
Step two: Change return value to void and the modifier of your function by removing static.
private void getListOfChildPagesAsJSON(Page page) { }
Step three add the missing recusion to your its body.
//JSONArray pagesArray = new JSONArray();
try {
Iterator<Page> childPages = page.listChildren();
while (childPages.hasNext()) {
Page childPage = childPages.next();
JSONObject pageObject = new JSONObject();
pageObject.put(childPage.getTitle(), childPage.getPath());
//Add the created object to your array which is class variable
this.pagesArray.put(pageObject);
//--Check for each single page for child pages again
Iterator<Page> childPagesOfChildpage = childPage.listChildren();
while (childPagesOfChildpage.hasNext()) {
getListOfChildPagesAsJSON(childPagesOfChildpage.next());
}
//--
}
} catch (JSONException e) {
LOG.error(e.getMessage(), e);
}
Note: The check childPage.hasChild() does not work here, because the node jcr:content is a valid child of passed page.

Volley Response Issue Android

I'm parsing a simple JSON response, and it is working when trying to parse the employer name, but it gets to a point where it will eventually crash and say that my 'review' json object, is empty. Here is the response:
https://raw.githubusercontent.com/vikrama/feed-json-sample/master/feed.json
And here is how I'm reading it:
private void extractName()
{
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest request = new JsonObjectRequest(JSON_URL, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONObject gimme = response.getJSONObject("response");
JSONArray resultsArray = gimme.getJSONArray("results");
for(int i = 0; i < resultsArray.length(); i++)
{
JSONObject info = resultsArray.getJSONObject(i);
JSONObject review = info.getJSONObject("review");
Log.d("COMP NAME", review.getString("employerName"));
companyNames.add(review.getString("employerName"));
}
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
adapter = new CompanyAdapter(MainActivity.this, companyNames);
recyclerView.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage());
}
});
queue.add(request);
}
The debug line prints the correct values, then abruptly stops saying "no value for review". I'm pretty confused by this because it seems i'm reading through the data correctly. (use https://jsonformatter.org/json-viewer to better format this json i listed above)
Also, everything else in my recyclerview is set up properly, and the method extractName() is being called in the onCreate() method of my main activity.
This is happening because in some JSON Object you don't have "review" object, so it's throwing your code directly to catch Exception.
In order to overcome this, Please use:-
if(info.has("review")) {
JSONObject review = info.getJSONObject("review");
companyNames.add(review.getString("employerName"));
}
Instead of:
JSONObject review = info.getJSONObject("review");
Log.d("COMP NAME", review.getString("employerName"));
companyNames.add(review.getString("employerName"));

Execute Async Task Inside another Async Task

I am trying to call another async task inside an OnPostExecute. The 2nd task does not run at all it seems. I am unable to print anything from within to the logs.
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try {
JSONObject json = new JSONObject(result);
JSONArray lignes = json.getJSONArray("lignes");
populatelist(lignes);
}
catch (JSONException e) {
}
}
}
The populatelist function fills an array. Inside this function, I try to call the 2nd async task to get values based on this list.
protected void populatelist(JSONArray lignes){
try {
for(int i=0;i<lignes.length(); i++) {
JSONObject jsonas = lignes.getJSONObject(i);
String fdesignation = jsonas.getString("designation");
String fqtecde = jsonas.getString("qtecde");
String fcode_produit = jsonas.getString("code");
InfoStock(fcode_produit);
items.add(new PickingListProduitItem(fdesignation,"",fqtecde, ""));
}
}
catch(Exception e){
}
}
InfoStock() is the function that is used to return additional from a web service.
protected void InfoStock(String code_produit){
String stockURL = "http://" + mSharedPreferences.getString(Constants.SERVER_IP,"")+"//rest/v2/produit/info/code/"+ code_produit + "?stock=true";
try {
if (mDownloader != null && mDownloader.getStatus() == AsyncTask.Status.RUNNING) {
mDownloader.cancel(true);
mPDialog.dismiss();
}
mPDialog = new ProgressDialog(getApplicationContext());
mDownloader = new XMLDownloader(getApplicationContext(),mPDialog);
byte[][] downloadResults = mDownloader.execute(stockURL).get();
// Read stock info.
String s = new String(downloadResults[0], StandardCharsets.UTF_8);
JSONObject resp = new JSONObject(s);
PrixStockJSONParser psj = new PrixStockJSONParser(resp);
mRepInfoStock = psj.getRepInfoStock();
mRepInfoPrix = psj.getRepInfoPrix();
} catch (Exception ex) {
}
}
I am trying to set a value in the array <> created in the OnPostExecute Method. However there is no error message and the array is not populated at all. Even if I try to print a log from the InfoStock function, it does nothing.
Any suggestions are welcome.

Android - Arraylist returning null outside for loop

I'm getting the List<String> resultList response as empty in ResponseFinal log.But inside the loop the response is showing items in resultList
I don't understand why resultlist is returning empty outside the loop.Please help
public List<String> getParseJson(String sName)
{
final List<String> resultList = new ArrayList<String>();
String name=sName.replace(" ", "%20");
StringRequest stringRequest = new StringRequest(Request.Method.GET, Constants.BASE_URL + "/suggest_item/items/"+name +"/"+ Constants.API_KEY,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Result handling
try {
JSONObject jsonObj = new JSONObject(response.toString());
JSONArray predsJsonArray = jsonObj.getJSONArray("Item");
for (int i = 0; i < predsJsonArray.length(); i++) {
System.out.println( predsJsonArray.get(i).toString());
resultList.add(predsJsonArray.get(i).toString());
Log.e("Response",resultList.toString());
}
} catch (JSONException e) {
Log.e("JSOn", "Cannot process JSON results", e);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Error handling
System.out.println(error.toString());
}
});
// Adding request to request queue
Volley.newRequestQueue(context).add(stringRequest);
Log.e("ResponseFinal",resultList.toString());
return resultList;
}
My log :
E/Response: [1660309, 1660410]
E/ResponseFinal: []
declare List before oncreate() (defining the resultList at class level)
List<String> resultList = new ArrayList<String>();
You are returning list before response is coming that's why you are getting empty list. You can do something like below code which can get you list after response.
Step 1: Make a method name it onSuccess(List<String> list) with your getParseJson() method
public void onSuccess(List<String> list){
// do your code here after getting the list
}
//make this method as void
public void getParseJson(String sName){
//your code which you have already implemented
}
Step 2: call the above method from onResponse() method which is declared inside your getParseJson() method as follows:
#Override
public void onResponse(String response) {
// Result handling
try {
JSONObject jsonObj = new JSONObject(response.toString());
JSONArray predsJsonArray = jsonObj.getJSONArray("Item");
for (int i = 0; i < predsJsonArray.length(); i++) {
System.out.println( predsJsonArray.get(i).toString());
resultList.add(predsJsonArray.get(i).toString());
Log.e("Response",resultList.toString());
}
} catch (JSONException e) {
Log.e("JSOn", "Cannot process JSON results", e);
}
//call here
onSuccess(resultList);
}
EDIT:
If you are calling getParseJson() from another class then call it as follows:
//If you are having paramaterized constructor then you can give parameter
new YourClassName(){
#Override
public void success(List<String> list) {
// do your code here after getting the list
}
}.getParseJson(String response);
The list in which you added is a copy and has scope only inside public void onResponse(String response). Hence, the actual list is empty as it was when defined. so, the final log displays empty.
I don't understand why resultList is returning empty outside the loop...
It is empty because your request runs asynchronously. So, you create your request along with response listeners, pass it to the Volley and then getParseJson() returns empty list - because request wasn't performed yet, and the other code will not wait for it to perform. After that, when request is performed (and it's performed asynchronously), your response listener adds the JSON values to the resultList but it's too late.
Rewrite your code so it handles the asynchronous nature of Volley requests.

Android - Cannot refer to a non-final variable test inside an inner class defined in a different method

I'm currently creating an app utilizing Facebook's Android SDK. Below is the attached code:
private void checkIfPostLiked(final String post_id) {
String isLiked = null;
new Request(Session.getActiveSession(), post_id + "/likes/", null,
HttpMethod.GET, new Request.Callback() {
#Override
public void onCompleted(Response response) {
try {
JSONObject json;
json = new JSONObject(response.getRawResponse());
JSONArray jArray = json.getJSONArray("data");
for (int i = 0; i < jArray.length(); i++) {
user_like_name = jArray.getJSONObject(i)
.get("name").toString();
if (user_like_name.equals(user_me.getName())) {
isLiked= "true";
}
else{
isLiked = "false";
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Get message data
}
}).executeAsync();
}
I would like to return the string isLiked, and return it, but the issue is that I keep on getting Cannot refer to a non-final variable isLiked inside an inner class defined in a different method. I have to use this method (checkifPostLiked) as a function in another iteration within a loop, therefore putting the variable isLiked as member variable would not work as well. I really hope that anyone could help me on this!
You need to initialize isLiked and finalize it:
final String isLiked = new String();
/* Rest of the code remains the same. */
new Request(Session.getActiveSession(), post_id + "/likes/", null,
HttpMethod.GET, new Request.Callback() {
....
....
}

Categories