Best practice for JSON when result is JUST an array?

356 views
Skip to first unread message

S. Dale Morrey

unread,
Mar 29, 2014, 5:16:08 AM3/29/14
to codenameone...@googlegroups.com
I can't seem to locate the proper way to use the JSON parser when the result is a pure array with no top level tagging.

Here is an example.  I have a REST API.
The API defines a method GET /getrecentactivity

The result is a pure javascript array that looks exactly like this...
[
  {
    "account": "user1",
    "category": "broadcast",
    "msgid": "some unique id",
    "time": 1395920488,
    "timereceived": 1395920488,
"message": "Hey everyone this a broadcast!"
  },
{ "account": "user1", "category": "direct",
"destination": "user2",
 "msgid": "some other unique id", "time": 1395920492, "timereceived": 1395920493,
"message": "Hello user2! How is life?"
  }
]

The content type is application/json

To access this RESTful API I'm using a ConnectionRequest with a ResponseListener (extends ActionListener) that looks like this.
public void actionPerformed(ActionEvent evt) {
Result result;
try{
result = Result.fromContent(new String(request.getResponseData()), Result.JSON);
Application.setActivityList(result);
}catch(IllegalArgumentException ex){
Display.getInstance().callSerially(new Runnable(){

public void run() {
Dialog.show("Error!", "The server returned an invalid result.\nPlease try again later.", "OK", null);
}
});
}
}

Application.setActivityList(result)  looks like

    public static void setActivityList(Result result) {
        recentActivityList = result.getAsArray("/");
    }

Unfortunately that line "recentActivity = result.getAsArray("/");" throws the following exception

java.lang.StringIndexOutOfBoundsException: String index out of range: 1
    at java.lang.String.charAt(String.java:658)
    at com.codename1.processing.ResultTokenizer.next(ResultTokenizer.java:146)
    at com.codename1.processing.ResultTokenizer.tokenize(ResultTokenizer.java:77)
    at com.codename1.processing.Result._internalGetAsArray(Result.java:861)
    at com.codename1.processing.Result.getAsArray(Result.java:844)
    at com.cannibay.potwallet.Application.setActivityList(Application.java:123)
 
I've checked the Network Monitor and the result is exactly what I pasted above.  I've ran it through a JSON validator and it validates fine.  Furthermore I have a webpage with a javascript element that does a JSON.parse on this same REST call and it gives me an array every time.
 
So at this point I'm pretty well stumped.  It seems that / should be the root of the JSON response but clearly the JSON parse doesn't like it.
Any ideas?

Shai Almog

unread,
Mar 29, 2014, 12:32:59 PM3/29/14
to codenameone...@googlegroups.com
This might be an omission in that API. We usually use the vector directly rather than the processing API.

S. Dale Morrey

unread,
Mar 29, 2014, 2:37:52 PM3/29/14
to codenameone...@googlegroups.com
Ok fine, so what would be the current best way of dealing with this? 
Assume I can't change what's coming out of the webserver since I'm not on that team. 

I want the array, but I'm willing to take any array like object.  Can you give me a code sample (or point me to one) of how you're recommending someone deal with this type of situation?
Thanks!

Steve Hannah

unread,
Mar 29, 2014, 2:45:05 PM3/29/14
to codenameone...@googlegroups.com
In the worst case you can use this cn1lib

It uses a completely different API and it does support arrays as the root object.

Steve


--
You received this message because you are subscribed to the Google Groups "CodenameOne Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to codenameone-discu...@googlegroups.com.
Visit this group at http://groups.google.com/group/codenameone-discussions.
To view this discussion on the web visit https://groups.google.com/d/msgid/codenameone-discussions/e17f5edb-24ae-4e1b-81b7-e2020ed65711%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Steve Hannah
Web Lite Solutions Corp.

Sadart Abukari

unread,
Mar 29, 2014, 5:21:07 PM3/29/14
to codenameone...@googlegroups.com

It has been a long time since I used this approach. I use the JSONParser instead. Check out if this code will be friendly for your purpose
// Note the root. With JSON array responses starting with [ the parser automatically fixes "root" as the root element for them
// [{"name":"myname"},{"name":"anothername"}]  becomes {"root":[{"name":"myname"},{"name":"anothername"}]}
// Array = Vector / ArrayList eg {"student":[{"name":"student1", "class":"4"},{"name":"student2", "class":"8"}]}
[{"name":"student1", "class":"4"},{"name":"student2", "class":"8"}] will be changed to {"root":[{"name":"student1", "class":"4"},{"name":"student2", "class":"8"}]}
// Object = Hashtable/ HashMap eg {"name":"student1", "class":"4"}

    private void fetchFixturesAndResultsList() {
        ConnectionRequest connectionRequest;
        connectionRequest = new ConnectionRequest() {
            // New school
            ArrayList arFixturesResults = new ArrayList();// Array will be ArrayList
            // Old school
            Vector vFixturesResults = new Vector();// Array will be Vector
           
            @Override
            protected void readResponse(InputStream input) throws IOException {
                JSONParser json = new JSONParser();
                // New school
                Map<String, Object> map = json.parseJSON(new InputStreamReader(input));
                arFixturesResults = (ArrayList) map.get("root");
                // Old school
                Hashtable h = json.parseJSON(new InputStreamReader(input));
                vFixturesResults = (Vector) h.get("root");
            }

            @Override
            protected void postResponse() {
                // do anything you want with arFixturesResults or vFixturesResults
                // New school
                for (int i = 0; i < arFixturesForRenderer.size(); i++) {
                    HashMap hListItem = (HashMap) arFixturesForRenderer.get(i);
                    String homeTeamScore = (String) hListItem.get("home team score");
                    String homeTeam = (String) hListItem.get("home team");
                }
                // Old school
                for (int i = 0; i < vFixturesForRenderer.size(); i++) {
                    Hashtable hListItem = (Hashtable) arFixturesForRenderer.elementAt(i);
                    String homeTeamScore = (String) hListItem.get("home team score");
                    String homeTeam = (String) hListItem.get("home team");
                }
               
            }

 
        };
        connectionRequest.setUrl(API_URL + "/views/fixtures_and_results");
        connectionRequest.setPost(false);
        connectionRequest.removeAllArguments();
        NetworkManager.getInstance().addToQueueAndWait(connectionRequest);

    }

Shai Almog

unread,
Mar 30, 2014, 1:20:52 AM3/30/14
to codenameone...@googlegroups.com
Sadrat's code is good although I would cast to java.util.List rather than ArrayList so the code can be more generic.

Sadart Abukari

unread,
Mar 30, 2014, 10:12:27 AM3/30/14
to codenameone...@googlegroups.com
@Shai. Thanks for the recommendation.
@S. Dale Morrey
I made a mistake in the line

Hashtable h = json.parseJSON(new InputStreamReader(input));
correction is
Hashtable h = json.parse(new InputStreamReader(input));
in case you want to use it
Reply all
Reply to author
Forward
0 new messages