tags:

views:

733

answers:

3

I have an HttpResponse object for a web request I just made. The response is in the JSON format, so I need to parse it. I can do it in an absurdly complex way, but it seems like there must be a better way.

Is this really the best I can do?

    HttpResponse response; // some response object
    Reader in = new BufferedReader(
        new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
    StringBuilder builder= new StringBuilder();
    char[] buf = new char[1000];
    int l = 0;
    while (l >= 0) {
        builder.append(buf, 0, l);
        l = in.read(buf);
    }
    JSONTokener tokener = new JSONTokener( builder.toString() );
    JSONArray finalResult = new JSONArray( tokener );

I'm on Android if that makes any difference.

A: 

Use JSON Simple,

http://code.google.com/p/json-simple/

Which has a small foot-print, no dependencies so it's perfect for Android.

You can do something like this,

Object obj=JSONValue.parse(buffer.tString());
JSONArray finalResult=(JSONArray)obj;
ZZ Coder
What is the advantage of this over the built-in `org.json` package?
CommonsWare
If you are familiar with org.json and your app is for Android only, it probably has no advantage. Otherwise, json-simple is much simpler to use and the JAR is much smaller (14k vs 43k). We use it everywhere, even on Android.
ZZ Coder
+1  A: 

Two things which can be done more efficiently:

  1. Use StringBuilder instead of StringBuffer since it's the faster and younger brother.
  2. Use BufferedReader#readLine() to read it line by line instead of reading it char by char.

HttpResponse response; // some response object
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
    builder.append(line).append("\n");
}
JSONTokener tokener = new JSONTokener(builder.toString());
JSONArray finalResult = new JSONArray(tokener);

If the JSON is actually a single line, then you can also remove the loop and builder.

HttpResponse response; // some response object
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
JSONTokener tokener = new JSONTokener(json);
JSONArray finalResult = new JSONArray(tokener);
BalusC
Won't the code in the question read it off the stream 1000 bytes at a time? Obviously it depends on the average line size of the output, but that could very well be fewer batches than one per line.
Joe Ludwig
No, as the method name already hints, the `BufferedReader#readLine()` reads the stream line by line. I.e. it splits the stream on newlines. Give it a try and experience yourself.
BalusC
Right. That's my point. If a line is less than 1000 characters on average using BufferedReader#readLine() will involve more times through the loop than BufferedReader#read(). (Not that the difference is likely to matter unless the output has a lot of short lines.)
Joe Ludwig
The `BufferedReader` internally already buffers on 8KB. After all, this is likely microoptimization, either way is good enough, I would prefer more readable code above that. The idiom you're using is typical for byte streams, not for character streams. PS: why did you edit the question to replace the `StringBuffer` with `StringBuilder`? Now my suggestion about that makes less sense for ones reading the question for first time :)
BalusC
I just changed the variable name. It was a StringBuilder in the original version of the question, but I can see where using the name "buffer" might have confused things. :)
Joe Ludwig
Oh, I see. You're welcome.
BalusC
A: 

Jackson appears to support some amount of JSON parsing straight from an InputStream. My understanding is that it runs on Android and is fairly quick. On the other hand, it is an extra JAR to include with your app, increasing download and on-flash size.

CommonsWare