Sunday, November 28, 2010

Servlet-GSON vs JSONME-JavaME

In this post I’m going to show you a simple example of data transmition between a mobile client using Java Me and a Server using Servlets. The data format to use in the transmition is JSON.

Requirements:

Servlets: On the server side, servlets will wait for requests. More info:
http://www.oracle.com/technetwork/java/index-jsp-135475.html

Java Me: Used to create mobile applications using Java. More info:
http://www.oracle.com/technetwork/java/javame/overview/index.html

JSON: Data interchange format. More info:
http://www.java-n-me.com/2010/10/json-without-fear-of-friday-13th.html

GSON: Google's library to create JSON Strings from and to objetos. More info:
http://www.java-n-me.com/2010/11/gson-json-in-just-two-lines-of-code.html

JSON Me: Library to work with JSON in Java ME. More info:
http://www.java-n-me.com/2010/11/java-me-and-json.html

Following is the Client class that is used on the server side which we will use to create the Objects to pass through the network in JSON format:


package model;

public class Client {

    /** Name of the client*/
    private String name;

    /** Last name of the client*/
    private String lastName;

    /** Identification of the client*/
    private String id;

    //Getters and Setters...
}


As shown, there is nothing strange. Just a simple class with some attributes. This is because on the server side we have GSON. On the mobile client side, this class has a little more lines of code as we shall see later.

The servlet will respond to POST requests, will create 3 Client objects, convert them to JSON Strings (using GSON) and send the response to the client:



package servlets;

import com.google.gson.Gson;
import java.io.*;
import java.util.Vector;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import model.Client;

public class ClientsServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
      
        //sets the type of response and the charset used
        //Be careful, in your mobile client, read the response using the same charset
        response.setContentType("application/json; charset=UTF-8");

        //create some clients and add them to the vector
        Vector vClients = new Vector();

        Client clientOne = new Client();
        clientOne.setName("Alexis");
        clientOne.setLastName("Lopez");
        clientOne.setId("123456");

        vClients.add(clientOne);

        Client clientTwo = new Client();
        clientTwo.setName("Second");
        clientTwo.setLastName("Client");
        clientTwo.setId("987534");

        vClients.add(clientTwo);

        Client clientThree = new Client();
        clientThree.setName("Colombia");
        clientThree.setLastName("JUG");
        clientThree.setId("555555");

        vClients.add(clientThree);

        //convert the clients vector to JSON using GSON, very easy!
        Gson gson = new Gson();
        String jsonOutput = gson.toJson(vClients);

        System.out.println("*****JSON STRING TO RESPONSE*****");
        System.out.println(jsonOutput);
        System.out.println("*********************************");

        //print the response
        PrintWriter out = response.getWriter();
        out.println(jsonOutput);
        out.flush();
        out.close();
    }
}

When the servlet is run and it receives a POST request, the following message is shown on the console:

INFO: *****JSON STRING TO RESPONSE*****


INFO: [{"name":"Alexis","lastName":"Lopez","id":"123456"},{"name":"Second","lastName":"Client","id":"987534"},{"name":"Colombia","lastName":"JUG","id":"555555"}]
INFO: *********************************

As you can see, is the JSON representation of the newly created Vector of Client objects. Note that the servlet defines the type of response as JSON ("application/json") and also uses the "UTF-8" charaset. This is important to remember, because when the mobile client is reading the answer, you must use the same charset or you could get strange characters when reading accents or 'Ñ' letter, etc. You may also notice how easy it is to implement GSON to convert objects to JSON Strings. Only two lines of code.

That's it on the server side. Now we will see the Client class on the mobile side and will notice that it has more lines of code than the Client class on the server side. As mentioned before, this is because in Java ME there is NO Java Reflection API and therefore we can not use GSON but we use JSON ME and we have to manually map the attributes of the classes. For more information about the next class, check this previous post: http://www.java-n-me.com/2010/11/java-me-and-json.html


import java.util.Vector;
import org.json.me.JSONArray;
import org.json.me.JSONException;
import org.json.me.JSONObject;
public class Client {

    /** Name of the client*/
    private String name;

    /** Constant name of the attribute name*/
    private static final String ATT_NAME = "name";

    /** Last name of the client*/
    private String lastName;

    /** Constant name of the attribute last name*/
    private static final String ATT_LAST_NAME = "lastName";

    /** Identification of the client*/
    private String id;

    /** Constant name of the attribute id*/
    private static final String ATT_ID = "id";

    /**
     * Allows to get the JSON String from the Client passed as parameter
     * @param client Client object to convert to JSON
     * @return JSON String of the Client passed as parameter
     */
    public static String toJSON(Client client)
    {
        return toJSONObject(client).toString();
    }

    /**
     * This method should be used by this class only, that's why it is private.
     * Allows to get a JSONObject from the Client passed as parameter
     * @param client Client Object to convert to JSONObject
     * @return JSONObject representation of the Client passed as parameter
     */
    private static JSONObject toJSONObject(Client client) {
        JSONObject json = new JSONObject();
        try {
            json.put(ATT_NAME, client.getName());
            json.put(ATT_LAST_NAME, client.getLastName());
            json.put(ATT_ID, client.getId());
        } catch (JSONException ex) {
            ex.printStackTrace();
        }
        return json;
    }

    /**
     * Allows to get JSON String from a Vector of Clients
     * @param clients Vector of clients to convert to JSON
     * @return JSON String of the Vector of clients
     */
    public static String toJSONs(Vector clients) {
        JSONArray clientsArray = new JSONArray();
        for (int i = 0; i < clients.size(); i++) {
            Client client = (Client)clients.elementAt(i);

            JSONObject jsonObject = toJSONObject(client);
            clientsArray.put(jsonObject);
        }
        return clientsArray.toString();
    }

    /**
     * Allows to get a Client Object from a JSON String
     * @param jsonText JSON String to convert to a Client Object
     * @return Client Object created from the String passed as parameter
     */
    public static Client fromJSON(String jsonText) {
        Client client = new Client();
        try {
            JSONObject json = new JSONObject(jsonText);

            //check if the JSON text comes with the attribue Name
            if (json.has(ATT_NAME)) {
                //asign the String value of the attribute name to the client
                client.setName(json.getString(ATT_NAME));
            }

            //check if the JSON text comes with the attribue last name
            if (json.has(ATT_LAST_NAME)) {
                client.setLastName(json.getString(ATT_LAST_NAME));
            }

            //check if the JSON text comes with the attribue id
            if (json.has(ATT_ID)) {
                client.setId(json.getString(ATT_ID));
            }
        } catch (JSONException ex) {
            ex.printStackTrace();
        }
        return client;
    }

    /**
     * Allows to get a Vector of Clients from a JSON String
     * @param jsonArray String that contains Clients JSON Text
     * @return Vector of Clients from the String passed as parameter
     */
    public static Vector fromJSONs(String jsonArray) {
        Vector clients = new Vector();
        try {
            JSONArray jsonArr = new JSONArray(jsonArray);
            for (int i = 0; i < jsonArr.length(); i++) {
                //get a single client JSON Object
                JSONObject json = jsonArr.getJSONObject(i);

                //pass the JSON String to the method in order
                //to get the Client Object
                Client client = fromJSON(json.toString());

                clients.addElement(client);
            }
        } catch (JSONException ex) {
            ex.printStackTrace();
        }
        return clients;
    }

    //Getters and Setters...
}


Finally we'll see the MIDlet that runs and creates an HTTP connection to access the servlet. The connection is established using POST method and we read the data using the same charset that was used when creating the http response to avoid getting strange characters. Then the console displays the values of the attributes of the clients received:



import java.io.*;
import java.util.Vector;
import javax.microedition.io.*;
import javax.microedition.midlet.*;

public class JSONMIDlet extends MIDlet {

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
        notifyDestroyed();
    }

    public void startApp() {
        try {

            //ask for the clients
            Vector clients = getClients();

            //show information of the clients
            System.out.println("*****CLIENT INFORMATION*****");
            for (int i = 0; i < clients.size(); i++) {
                Client cl = (Client) clients.elementAt(i);

                System.out.println("Client " + (i + 1) + " name = " + cl.getName());
                System.out.println("Client " + (i + 1) + " last name = " + cl.getLastName());
                System.out.println("Client " + (i + 1) + " ID = " + cl.getId());
                 System.out.println("");
            }
        } catch (IOException ex) {
            //manage the exception
        }
        //close the application
        destroyApp(true);
    }

    /**
     * Connects to server in order to obtain information of the clients
     * @return Vector of <code>Client</code> objects
     * @throws IOException if errors with the connections
     */
    public Vector getClients() throws IOException {
        //This is my servlet’s URL
        String URL = "http://localhost:8080/GSON_Servlet/ClientsServlet";
        Vector vClients = new Vector();

        HttpConnection http = null;
        DataInputStream din = null;
        try {
            //Open HttpConnection using POST
            http = (HttpConnection) Connector.open(URL);
            http.setRequestMethod(HttpConnection.POST);
            //Content-Type is must to pass parameters in POST Request
         http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            //Open InputStream to read the response
            din = new DataInputStream(http.openInputStream());
            int i = 0;
            StringBuffer str = new StringBuffer();
            while ((i = din.read()) != -1) {
                str.append((char) i);
            }

            //IMPORTANT: Read the response in the same charset that it was written
            String jSonString = new String(str.toString().getBytes(), "UTF-8");

            System.out.println("*****JSON STRING RECEIVED*****");
            System.out.println(jSonString);
            System.out.println("******************************");


            //Parse the JSON String to obtain a Vector of clients
            vClients = Client.fromJSONs(jSonString);

        } //whatever happens, close the streams
        finally {
            if (din != null) {
                din.close();
            }

            if (http != null) {
                http.close();
            }
        }

        return vClients;
    }
}


When we run the MIDlet the console prints the following lines:

*****JSON STRING RECEIVED*****
[{"name":"Alexis","lastName":"Lopez","id":"123456"},{"name":"Second","lastName":"Client","id":"987534"},{"name":"Colombia","lastName":"JUG","id":"555555"}]
****************************** *****CLIENT INFORMATION***** Client 1 name = Alexis Client 1 last name = Lopez Client 1 ID = 123456 Client 2 name = Second Client 2 last name = Client Client 2 ID = 987534 Client 3 name = Colombia Client 3 last name = JUG Client 3 ID = 555555


Obviously, in a business application the servlet would connect to a database in order to get the clients information, then the servlet would send that information to the mobile client using JSON. The mobile client would have a graphical interface that would allow the user to view the information received from the server... and so many other improvements. But this simple example, shows you the possibilities offered by JSON for communication between server and mobile client in a standard way without having to invent new formats for data exchange.

This concludes the communication Servlets/GSON vs JSON Me/Java Me. I know there have been a lot of code, it may be difficult to read. For the following posts I will emphasize on the really important parts of the code and let the entire source code to be downloaded.

see you soon!


References:

Using JavaScript Object Notation (JSON) in Java ME for Data Interchange. Agosto 2008. Oracle [online].
Available on Internet: http://java.sun.com/developer/technicalArticles/javame/json-me/
[accessed on October the 26th 2010].

meapplicationdevelopers: Subversion. 2007. Oracle [online].
Available on Internet: https://meapplicationdevelopers.dev.java.net/source/browse/meapplicationdevelopers/demobox/mobileajax/lib/json/
[accessed on October the 27th 2010].