Saturday, 15 November 2014

Creating a simple JSON parser for parsing various similar response types.

Background

Many a times it so happens that a particular service or APIs return a set of similar resources. So how do we handle it in a client that uses these APIs or services. One way is that you check the incoming response against all the exhaustive possible list of responses . One would match and you will have your result. But that's very bad programming. So many if-else statements. Plus so much computing time wastage. Surely not a way to go for production code. In this post I will show how can write a simple parser that parses such requests.


Assumption and Understanding of task

Before we go to the code let me explain the problem which we are going to solve with the parser. Assume there is a Service or an API that returns an Animal. For example you want a pet you may ask for Dog or a Cat. If you want to participate in horse racing you may ask for a Horse or a Hen for poultry etc. Point is we have to build a client that can parse the incoming requests. So if someone asks for a Dog we should parse the response for a Dog and prove it is indeed a Dog.

For simplicity of code and understanding I am just going to work with Class Dog and Class Cat. To differentiate between them I am adding bark() method in Dog class and drink() method in Cat class.
Also we have a super class called Animal. Both Dog and Cat class extend Animal Class. We will leverage the concept of polymorphism

Also I am assuming that the response we get has a basic structure 

{
     "type":type of animal
}

It may have additional attributes depending on the type of animal. For Cat and Dog I have added another attribute called isPet. What will be more important is the type which is common to all the responses.

To the Code

As usual I am using Eclipse with Ivy dependency manager. We need GSON library to handle json data. My Ivy file looks like -



<ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
    <info
        organisation="OpenSourceForGeeks"
        module="JsonParser"
        status="integration">
    </info>
    
    <dependencies>
        <dependency org="com.google.code.gson" name="gson" rev="2.2.4"/>
    </dependencies>
</ivy-module>

Next lets create our model classes. We will have three model classes - Animal, Dog and Cat. Overall my project structure looks like follows -



Animal.java

package opensourceForGeeks.models;

public class Animal {
    
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

Dog.java

package opensourceForGeeks.models;

public class Dog extends Animal {
    
    boolean isPet;
    
    public boolean isPet() {
        return isPet;
    }

    public void setPet(boolean isPet) {
        this.isPet = isPet;
    }

    public void bark()
    {
        System.out.println("Dog is barking...");
    }

}

Cat.java

package opensourceForGeeks.models;

public class Cat extends Animal {
    
    boolean isPet;
    
    public boolean isPet() {
        return isPet;
    }

    public void setPet(boolean isPet) {
        this.isPet = isPet;
    }

    public void drink()
    {
        System.out.println("Cat is drinking milk...");
    }
    
    
}

Next lets write our actual parser logic - JsonParser.java

package opensourceForGeeks.parser;

import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;

import opensourceForGeeks.models.Animal;
import opensourceForGeeks.models.Cat;
import opensourceForGeeks.models.Dog;

public class JsonParser {
    
    private static final Map<String, Class> ANIMAL_MAPPING = new HashMap<String, Class>();
    private static final Gson gson = new Gson();
    
    static
    {
        ANIMAL_MAPPING.put("dog", Dog.class);
        ANIMAL_MAPPING.put("cat", Cat.class);
    }
    
    public Animal parseAnimal(String jsonString)
    {
        try
        {
            Animal animal = gson.fromJson(jsonString, Animal.class);
            return gson.fromJson(jsonString, ANIMAL_MAPPING.get(animal.getType()));
        }
        catch (Exception ex)
        {
            System.out.println("Exception occured while parsing Animal json string");
            return null;
        }
        
    }

}

and finally lets test it - JSONParserTest.java

package opensourceForGeeks.test;

import opensourceForGeeks.models.Cat;
import opensourceForGeeks.models.Dog;

public class JSONParserTest {
    
     private static final String DOG_JSON = "{\"type\": dog,\"isPet\": true}";
     private static final String CAT_JSON = "{\"type\": cat,\"isPet\": true}";
    
    public static void main(String args[])
    {
        opensourceForGeeks.parser.JsonParser parser = new opensourceForGeeks.parser.JsonParser();
        ((Dog) parser.parseAnimal(DOG_JSON)).bark();
        ((Cat) parser.parseAnimal(CAT_JSON)).drink();
    }

}


and the output is as expected - 

Dog is barking...
Cat is drinking milk...

Understanding the logic

What we have done in our JsonParser class is as follows -

  • We first create a map of type(exhaustive list of possible types of Animals) and their model classes.
  • All type of Animals extend Class Animal which has the type that will be common to all the JSON responses.
  • So we first convert the json string into Animal object which in turn provides us the information about what type of Animal it is.
  • Then we use this information to get the model class used to describe that type of Animal and again parse the json String to covert it into that specific type of Animal and finally return it.
  • Yes we have used polymorphism here to make our task easier!




No comments:

Post a comment

t> UA-39527780-1 back to top