Using JSON for mobile object exchange – Tutorial
Posted March 6th, 2009 by NazmulIntroduction
I’ve been working with various object encoding schemes to get information transferred over the network between services and mobile apps running on Android and BlackBerry. On Android, I figured I would try using Java object serialization, and that works some of the time, and not for anything complex. I wish the object serialization and deserialization mechanism in GWT would be ported over to all these mobile environments, but I digress.So I evaluated the following strategies:
- I tried using binary formats, these are too complicated and the overhead of writing marshalling/unmarshalling code is too high. Also this code has to be portable across a variety of platforms, and so it gets complicated. For me, it has to work on BlackBerry and Android, and BlackBerry is clearly the lesser platform, only supporting JavaME, while Android has pseudo Java5 support with generics.
- I tried using Google Protocol Buffers. While this sounded like the perfect solution at first, it isn’t. It relies on the use of generics and so that rules it out as an option for JavaME, although it’s a good option to have for Android and even desktop environments, and other service to service interactions. But this is one more thing to learn, and it won’t even work for BlackBerry. So that ruled it out.
- I looked at XML serialization. There is plenty of tooling around this option. They have XMLRPC servers and clients (even for JavaME) so that makes it a little easier to deal with. But all transport mechanism aside, the marshalling and unmarshalling code still has to be generated painfully. Although the use of Betwixt & Digester or XML Beans might make it easier. Again, more APIs to use and learn and all that… so that ruled it out.
What is JSON?
You can also pass arrays, which can have objects of any type in them using JSONArray. This class is great when you don’t have keys for the objects you are trying to pass over the wire. Things like method params are really easy to encode using this scheme. You can also put JSONArray as a value for a key in a JSONObject object.
Here are some diagrams that depict this:
There are a couple of things to keep in mind:
- When passing null as a value, be sure to pass JSONObject.NULL instead. This just avoids JSONExceptions being raised all over the place, and it makes it so that null values are actually passed in a JSONObject (which by default will not include a key if the value is null). JSONObject.NULL.equals(null) is true, so you can test for your value being null in this way.
- When passing objects, be sure that what’s contained in them can be serialized. Alternatively, provide serialization routines to Base64 encoded string for bytes that are not provided by default.
- When using JSON, you can use the underlying Hashtable has the foundation data structure of your object model, if it fits. Otherwise, just design your object model in a way that is natural for it, and just write serialization method to convert it to a Hashtable/JSONObject/JSONArray. My code generator is meant as a starting point to do this… you can modify it’s output by hand to meet your needs.
Source code example
This example shows using JSONArray, JSONObject, and Vectors. There’s also a visualization of the state of the JSONObject at the end of the code.public class JSONDemo { // main method public static void main(String[] args) throws JSONException { JSONArray list1 = new JSONArray(); Vector v = new Vector(); v.addElement("1"); v.addElement("2"); v.addElement("3"); list1.put(v); Vector v1 = new Vector(); v1.addElement("A"); v1.addElement("B"); v1.addElement("C"); JSONArray list2 = new JSONArray(v1); JSONObject jObj = new JSONObject(); jObj.put("key", "value"); jObj.put("list1", list1); jObj.put("list2", list2); System.out.println("JObject: " + jObj.toString(5)); } }
My JSON Code Generator
Here are some code examples to get you started: http://code.google.com/p/json-simple/wiki/EncodingExamplesNeed more help? developerlife.com offers training courses to empower you, and consulting services to enable you.
To automate the process, I’ve actually created a class that generates JSON code for you . It’s a very useful code generator that is a good starting point for you to use in your projects. If you improve on it, and are willing to share the improvements, please email them to me and I will provide it on developerlife.com. Just run this class and provide the field names you want it to generate code for as command line arguments. The code is output to the console and automatically copied to the clipboard so you can paste it into your IDE using Ctrl + V.
package rpc.json; import rpc.json.me.*; import java.awt.*; import java.awt.datatransfer.*; /** * JSONCodegen is a simple code generator that takes care of creating getter/setter/ser/deser code for you. * You just provide the fields you want, and the code is generated & copied to the clipboard. * <p/> * The getter/setter code deal with "null" objects by using {@link JSONObject#NULL} instead. * * @author Nazmul Idris * @version 1.0 * @since Feb 11, 2009, 8:55:51 AM */ public class JSONCodegen { public static final String DefaultPackage = "datamodels"; public static final String DefaultClass = "MyDataModel"; public static final String DefaultType = "Object"; /** provide the properties/fields that you want your json object to have, separated by spaces. */ public static void main(String[] args) { StringBuffer buf = new StringBuffer(); // package and import buf.append("package ").append(DefaultPackage); _endLine(buf); buf.append("import rpc.json.me.*"); _endLine(buf); // class buf.append("/** code generated by JSONCodegen */n"); buf.append("public class ").append(DefaultClass).append(" {n"); _data(args, buf); _constructors(args, buf); _gettersetter(args, buf); _serdeser(args, buf); _listutils(args, buf); _tostr(args, buf); // end class buf.append("} //end class ").append(DefaultClass); // dump to console & copy to clipboard System.out.println(buf); _saveToClipboard(buf); } private static void _tostr(String[] args, StringBuffer buf) { buf.append("n/* toString */n"); buf.append("public String toString() {n" + " try {n" + " return BBUtils.compactPrintJSONObject(toJSON()).toString();n" + " }n" + " catch (JSONException e) {n" + " return "" + DefaultClass + " - can not get toString():" + e.toString();n" + " }n" + "}"); } private static void _listutils(String[] args, StringBuffer buf) { buf.append("n/* list utils */n"); // toarray buf.append("public static JSONArray toJSONArray("); buf.append(DefaultClass); buf.append("[] ray) {n"); buf.append("JSONArray jray = new JSONArray();n") .append("for (int i = 0; i < ray.length; i++) jray.put(ray[i]);n") .append("return jray;n") .append("}n"); // fromarray buf.append("public static "); buf.append(DefaultClass); buf.append("[] fromJSONArray(JSONArray jray) throws JSONException {n"); buf.append("int size = jray.length();n"); buf.append(DefaultClass); buf.append("[] ray = new "); buf.append(DefaultClass); buf.append("[size];n"); buf.append("for (int i = 0; i < size; i++) ray[i] = ("); buf.append(DefaultClass); buf.append(") jray.get(i);n"); buf.append("return ray;n}n"); } private static void _serdeser(String[] args, StringBuffer buf) { buf.append("n/* ser, deser */n"); // tojson buf.append("public JSONObject toJSON() throws JSONException {n"); buf.append("JSONObject retval = new JSONObject()"); _endLine(buf); for (int i = 0; i < args.length; i++) { String arg = args[i]; buf.append("retval.put(").append(_quotesAround(arg)).append(", ").append(arg).append(")"); _endLine(buf); } buf.append("return retval"); _endLine(buf); buf.append("}n"); // fromjson buf.append("public static ").append(DefaultClass).append(" fromJSON(JSONObject json) throws JSONException {n"); buf.append(DefaultClass).append(" retval = new ").append(DefaultClass).append("()"); _endLine(buf); for (int i = 0; i < args.length; i++) { String arg = args[i]; buf.append("retval.set_").append(arg).append("(json.get(").append(_quotesAround(arg)).append("))"); _endLine(buf); } buf.append("return retval"); _endLine(buf); buf.append("}n"); } private static void _gettersetter(String[] args, StringBuffer buf) { buf.append("n/* getter, setter */n"); for (int i = 0; i < args.length; i++) { String arg = args[i]; buf.append("/** @param val if this is null, JSONObject.NULL will be inserted.*/n"); buf.append("public void ").append("set_").append(arg).append("(").append(DefaultType).append(" val){n"); buf.append("if (val == null) val = JSONObject.NULL;n"); buf.append(arg).append(" = val;n}n"); } for (int i = 0; i < args.length; i++) { String arg = args[i]; buf.append("/** @return JSONObject.NULL will be returned if null was inserted to begin with.*/n"); buf.append("public ").append(DefaultType).append(" get_").append(arg).append("(){"); buf.append("return ").append(arg).append(";}n"); } } private static void _constructors(String[] args, StringBuffer buf) { buf.append("n/* constructors */n"); buf.append("public ").append(DefaultClass).append("(){}n"); buf.append("public ").append(DefaultClass).append("("); for (int i = 0; i < args.length; i++) { String arg = args[i]; boolean isLastElement = i == (args.length - 1); buf.append(DefaultType).append(" ").append(arg).append("_"); if (!isLastElement) buf.append(", "); } buf.append("){n"); for (int i = 0; i < args.length; i++) { String arg = args[i]; buf.append("set_").append(arg).append("(").append(arg).append("_)"); _endLine(buf); } buf.append("}n"); } private static void _data(String[] args, StringBuffer buf) { buf.append("n/* data */n"); for (int i = 0; i < args.length; i++) { String arg = args[i]; buf.append(DefaultType).append(" ").append(arg).append(" = JSONObject.NULL"); _endLine(buf); } } private static void _endLine(StringBuffer buf) { buf.append(";n"); } private static String _quotesAround(String msg) { return """ + msg + """; } private static void _saveToClipboard(StringBuffer buf) { StringSelection stringSelection = new StringSelection(buf.toString()); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(stringSelection, new ClipboardOwner() { public void lostOwnership(Clipboard clipboard, Transferable contents) { } }); } }//end class JSONCodegen
Thanks
akm
www.cdacians.com
No comments:
Post a Comment