Search code examples
androidjsonrequestandroid-volley

Responding to Volley JSONException


I have a Volley JSONRequest that is getting stuck because the response from the server is not a valid JSON (it's html).

How is it possible to gracefully handle this error? I have this implementation:

JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            … something …   
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
        // TODO Auto-generated method stub
            Log.i(TAG,"error "+error.toString());
        }
    });
    queue.add(jsObjRequest);

However when i send the request and get a not valid JSON response, the onErrorResponse doesn't get called. Instead i get an exception

08-14 16:26:15.590: D/538 - JsonRequest(27888): exception error Value <!DOCTYPE of type java.lang.String cannot be converted to JSONObject

and the whole app crashes.

I managed to track that error to the following line in the JsonObjectRequest.java class:

 @Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
    try {

        Log.d(TAG,"response headers "+response.headers.toString());
        String jsonString =
            new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        Log.d(TAG,"json string "+jsonString);
        return Response.success(new JSONObject(jsonString),
                HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
        Log.d(TAG,"parse error");
        return Response.error(new ParseError(e));
    } catch (JSONException je) {
        Log.d(TAG,"exception error "+je.getLocalizedMessage());
        return Response.error(new ParseError(je));
    }
}

the line that gets called is : return Response.error(new ParseError(je));

How do i catch that so it doesn't crash the app?

Thanks in advance!


Solution

  • If you are expecting to get JSON, you should check that your URL is valid. HTML is often returned when the request is invalid. Such examples are when a request returns a 404 not found webpage.

    If you are trying to get HTML (or XML), you can use a StringRequest to get a String, then convert it to a XML Document or can use a SAXParser to parse it. For example:

    StringRequest request = new StringRequest(Method.GET, url, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            try {
                Document xml = factory.newDocumentBuilder().parse(response);
                //TODO: handle XML Document parsing
            } catch (Throwable t) {
                return ;
            }
        }
    }, new Response.ErrorListener() {
    
            @Override
            public void onErrorResponse(VolleyError error) {
                // TODO Auto-generated method stub
            
            }
            
    });
    
    queue.add(request);
    

    One thing that you may wish to consider as a simpler alternative is my droidQuery library. To complete this request with droidQuery:

    $.ajax(new AjaxOptions().url(url)
                            .type("GET")
                            .dataType("XML")
                            //optionally, add own SAX parser with SAXContentHandler or customXMLParser methods
                            .success(new Function() {
                                @Override
                                public void invoke($ droidQuery, Object... params) {
                                    Document xml = (Document) params[0];
                                    //TODO: parse Document
                                }
                            })
                            .error(new Function() {
                                @Override
                                public void invoke($ droidQuery, Object... params) {
                                    AjaxError error = (AjaxError) params[0];
                                    Log.e("$", "Error " + error.status + ": " + error.error);
                                }
                            }));