72

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.

Joe Ludwig
  • 6,756
  • 7
  • 30
  • 29

7 Answers7

84

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
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 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 May 16 '10 at 21:51
  • 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 May 16 '10 at 21:58
  • 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 May 16 '10 at 22:02
  • 4
    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 May 16 '10 at 22:06
  • 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 May 16 '10 at 22:13
  • Awesome. Where is JSONTokener from? I never can find these flippin' jar files. – manafire Feb 28 '14 at 20:00
  • Found JSONArray and JSONTokener jar [here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.codeartisans%22%20AND%20a%3A%22org.json%22) – manafire Feb 28 '14 at 20:15
9

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
  • 74,484
  • 29
  • 137
  • 169
  • 1
    What is the advantage of this over the built-in `org.json` package? – CommonsWare May 16 '10 at 21:52
  • 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 May 16 '10 at 23:51
5

You can use the Gson library for parsing

void getJson() throws IOException {
    HttpClient  httpClient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet("some url of json");
    HttpResponse httpResponse = httpClient.execute(httpGet);
    String response = EntityUtils.toString(httpResponse.getEntity());

    Gson gson = new Gson();
    MyClass myClassObj = gson.fromJson(response, MyClass.class);

}

here is sample json file which is fetchd from server

{
"id":5,
"name":"kitkat",
"version":"4.4"
}

here is my class

class MyClass{
int id;
String name;
String version;
}

refer this

Rajesh Batth
  • 1,672
  • 2
  • 19
  • 23
2

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
  • 986,068
  • 189
  • 2,389
  • 2,491
0

Instead of doing

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() );

You can do:

JSONTokener tokener = new JSONTokener(
                           IOUtils.toString(response.getEntity().getContent()) );

where IOUtils is from the commons IO library.

Jove Kuang
  • 322
  • 2
  • 12
0

For Android, and using Apache's Commons IO Library for IOUtils:

// connection is a HttpURLConnection
InputStream inputStream = connection.getInputStream()
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(inputStream, baos);
JSONObject jsonObject = new JSONObject(baos.toString()); // JSONObject is part of Android library
Jonathan Lin
  • 19,922
  • 7
  • 69
  • 65
-3

There is no need to do the reader loop yourself. The JsonTokener has this built in. E.g.

ttpResponse response; // some response object
BufferedReader reader = new BufferedReader(new    
JSONTokener tokener = new JSONTokener(reader);
JSONArray finalResult = new JSONArray(tokener);
guido
  • 687
  • 4
  • 13
  • 1
    I can't find any constructor of JSONTokener which accepts a BufferedReader, therefore this answer is misleading. – Ian Newson Feb 21 '12 at 22:26
  • There is no constructor which accepts a BufferedReader but a Reader and BufferedReader is a subclass of Reader. --> org.json.JSONTokener(Reader reader) – guido Feb 22 '12 at 09:05
  • This constructor doesn't seem be part of Android: http://developer.android.com/reference/org/json/JSONTokener.html – Ian Newson Feb 22 '12 at 11:38
  • i got mine from from the json.org website which seems to be different to the android version. – guido Mar 14 '12 at 14:07