Tuesday 17 April 2012

Android: Parsing JSON with Generics

Parsing JSON in Android is quite a common task but as project grows this can become quite messy if not done properly at the beginning.
I will create a simple function which parses JSON by passing a expected class type and getting the instance of the same class if request is successful.
We will achieve this by using Java Generics. From what I've seen so far, many people run away from this feature but in this case they are just the right tool for the job.
So here's how the stuff should look like:
/**
 * Converts recieved JSON into passed type
 * @param url - address to which are we posting
 * @param requestObject - post data
 * @param responseType - type of the response we are expecting
 * @return - instance of the class
 * @throws Exception - use more precise exceptions
 */
public < T extends Response > T simplePostExample(String url, 
  Object requestObject, Class responseType) throws Exception {
                
  // standard post request with json content
  HttpPost request = new HttpPost(url);
  request.setHeader("Accept", "application/json");
  request.setHeader("Content-type", "application/json");
                
  // converting post data to json
  String json = new Gson().toJson(requestObject);
  StringEntity requestEntity = new StringEntity(json);
  request.setEntity(requestEntity);
                
  // executing request
  HttpResponse httpResponse = httpClient.execute(request);
  HttpEntity entity = httpResponse.getEntity();

  checkResponse(httpResponse, entity);

  if (entity != null) {
   InputStream content = entity.getContent();
   Reader reader = new InputStreamReader(content);
                        
   // convert response to new instance of the expected class
   T object = new Gson().fromJson(reader, responseType);
   return object;
  } else {
   throw new Exception("Something went wrong…");
  }
 }
        
 // check if everything is as it should be
 private void checkResponse(HttpResponse httpResponse, HttpEntity entity)
   throws Exception {
  int statusCode = httpResponse.getStatusLine().getStatusCode();
  if (statusCode != HttpStatus.SC_OK)
   throw new Exception("Something went wrong…");

  Header contentType = entity.getContentType();
  if (contentType == null
    || !contentType.getValue().startsWith("application/json"))
   throw new Exception("Something went wrong…");
 }

All responses inherit Response class which can also be useful for storing data that all responses have ( status, message...). This is just a quick example, but can later be extended to use more features like other http requests, credentials and etc...