|
Contents
Choosing the right data interchange format is an important design decision when building any network-aware software. This is especially true when designing mobile and embedded applications, where attributes such as lightweight and efficient are important characteristics to consider. Such characteristics are important because they translate to lower computation requirements and use of power, potentially better performance, and lower costs of operation.
In mobile applications, developers typically rely on home-grown data-interchange formats or on the Extensible Markup Language (XML). The advantage of the former is that it can be tailored to particular situations for the purpose of maximizing performance and/or computational resources. The advantage of the latter, when used over HTTP, is that it is a de facto standard for data interchange. In addition, the text-based/human-readable representation used in XML makes it easier to debug.
Yet these two approaches also have disadvantages, one being proprietary in nature, non-standard, and potentially non-interoperable, while the other one could be considered too heavy and verbose for data representation, again this is especially true for mobile and embedded applications.
JSON versus XML
The question of JSON versus XML is a topic left to the reader. I will say that XML purists question whether JSON is reinventing the wheel, and you can find lots of discussions on this topic by searching the web. At the end, the argument of JSON versus XML should be answered based on the run-time environment, parser availability, and integration and application requirements.
|
|
An alternative to consider is the JavaScript Object Notation or JSON, a lightweight data-interchange format. In this article I introduce JSON for data interchange in the Java Platform, Micro Edition (Java ME).
JSON is defined as part of JavaScript (ECMAScript) scripting language. Being native to JavaScript, JSON is ideal for browser-based applications. But JSON is not limited to JavaScript, and its lightweight characteristics make it very attractive for mobile and embedded applications in general.
JSON uses a very straightforward syntax that is based on two main data structures:
- Collection of name/value pairs, and
- Order list of values.
JSON is text-based, making it human-readable and great for debugging. JSON supports notation for all the basic data-types, and provides the methods to parse back and forth to Java native types. The following table summarizes JSON syntax elements:
Table 1 - JSON Syntax Elements
 |
Object |
{ |
} |
Members |
{...}
|
Member |
|
|
Pair, other members |
|
Pair |
Name (string) |
Value |
Name and Value separated by ":" |
"FirstName":"Enrique"
|
Name |
The name of the attribute |
: |
A string |
"username"
|
Value |
: |
The actual value |
String, number, object, array, null, boolean (true, false) |
"C. Enrique Ortiz", true, 01234, [...], {...}
|
Array |
[ |
] |
Elements |
["mobile", "web", "apps"]
|
Element |
|
|
Values, other elements |
|
The following JSON text snippet shows the request and response for JSON-Time, a helpful web-service that returns the current time for a specified time zone. the following example is a request and response for time in the central United States:
Listing 1 - JSON-Time HTTP Request and JSON Text Response
What about Binary Data?
JSON is a text-based data representation format, and as in all text-based formats, binary data need to be encoded as text. One approach is to convert the binary data to base 64 encoding, and another approach is to convert the binary data to other text-encoded formats, such as hex values, for example [\uDEAD, \uBEEF,...].
A better solution is to decouple the binary data via a Uniform Resource Locator (URL), where the binary data is represented or pointed to by the URL. In this approach the binary data wouldn't be embedded into the JSON text but would exist on a server on the web. This approach would allow for a separate mechanism for retrieval that can support caching and asynchronous retrieval and local storage.
|
|
The response is a simple JSON text structure, an unnamed object that contains properly escaped values, Strings, numbers, and boolean.
JSON supports all basic numbers and string data types. Numbers are integer digits, fractions, or exponents, but remember that floating-point/double data types are not supported on CLDC 1.0. Strings are any Unicode character.
The following characters must be properly escaped by using the Backslash character:
- Quotation mark (
\")
- Back-slash (
\\)
- Front-slash (
\/)
- Backspace (
\b)
- Form-feed (
\f)
- New-line (
\n)
- Carriage Return (
\r)
- Tab (
\t)
- Hexadecimal digits (
\u4-hex-digits)
Visit JSON.org for more information about JSON syntax.
As part of the Mobile and Embedded Application Developers Project, Sun Microsystems provides an open-source (Java.net) project version of the JSON for ME Java API. This source code comes properly instrumented for conditional compilation for CLDC 1.0 vs. 1.1 (that is, support for floating point). The JSON ME source code is also available at JSON.org, but without the conditional directives.
As expected, JSON ME is a subset of the full JSON Java API. The following table summarizes the JSON Java API:
Table 2 - JSON ME Java API
 |
org.json.me
|
JSONArray is an ordered sequence of values
JSONException is error detected
JSONObject is an ordered collection of name/value pairs
JSONString is an Interface for JSON serialization
JSONStringer is a subclass of JSONWriter for generating JSON syntax
JSONTokener is a parsing utility class used by JSONObject and JSONArray
JSONWriter is a convenience class to generate JSON syntax
StringWriter is StringBuffer-based implementation of StringWriter. This a Sun Microsystems helper class, not part of the standard JSON Java API
|
org.json.me.util
|
XML is a helper class to generation JSON from XML
XMLTokener extends JSONTokener in support of XML parsing
|
JSON and JSON ME differ internally with respect to some of the data types used (for example, JSON ME's use of Vector and Hashtable) and the compiler directives for conditional compilation for floating point support (CLDC 1.1). The JSON ME JAR file is around 25KB.
The JSON Java API provides some convenience classes, JSONWriter and JSONStringer, to generate JSON text. I personally prefer using the core JSONObject directly together with JSONArray, however, which provide the parsing capabilities needed. Let's cover a couple of simple examples that use these aforementioned core classes to serialize and deserialize a simple DataTypes example class to and from JSON. The following code snippet illustrates the JSON text that we will use as example:
Listing 2 - JSON Text Example
{
"datatypes": {
"aString":"C. Enrique Ortiz",
"anArray":["tech","mobile","web", "apps"],
"aInteger": 15569,
"aLong": 1234567890,
"aBoolean": true,
}
}
|
Looks simple enough, right? With JSON you can nest objects within objects, and define any data structure that you can in XML.
JSONObject is the core JSON Java class to use. The class provides a number of helper methods such as methods to:
accumulate values under a key
append values to the array under a key
- Generate a String from a
double
get a Java Object, a boolean, a double, an int, a JSONArray, a JSONObject, a long, as well as the opposite methods to put values of the same data types
get the field names inside a JSONObject
get the value associated with a specific key
- Find if a specific key exist inside a
JSONObject
- Determine if the value associated with the key is
null or if there is no value
- Get an
Enumeration of the keys of the JSONObject
- Get the number of keys stored in the
JSONObject
- Get a
JSONArray containing the names of the elements of this JSONObject
- Generate a String from a number
- Generate a String in double-quotes with backslash sequences in all the right places
- Remove a name and its value, if present
- Get an
Enumeration of the keys of the JSONObject
- Generate a
JSONArray containing the values of the members of this JSONObject
- Generate a JSON text of this
JSONObject
The Example DataTypes Class
The following code snippet defines the DataTypes example Java class that contains the data types supported by JSON ME. This is the class we are going to use to illustrate how to serialize to and from JSON. Again, remember that floating-point/double is not supported on CLDC 1.0:
Listing 3 - The DataTypes Example Class
/**
* A data types class to use as example
*/
class DataTypes {
public String aString; // a string
public String[] anArray; // an array
public int anInteger; // an integer
//public double aDouble; // double not supported on CLDC 1.0
public long aLong; // a long
public boolean aBoolean; // a boolean
/**
* An example multi-data type Class
*/
public DataTypes(
String aString,
String[] anArray,
int anInteger,
//double aDouble, // Not supported on CLDC 1.0
long aLong,
boolean aBoolean) {
this.aString = aString;
this.anArray = anArray;
this.anInteger = anInteger;
//this.aDouble = aDouble; // Not supported on CLDC 1.0
this.aLong = aLong;
this.aBoolean = aBoolean;
}
:
:
}
|
Supported data types are String, int, long, and boolean, and arrays of these aforementioned basic data types.
Serializing to JSON: Generating JSON Text
Let's now create a JSON text representation of a DataTypes class instance. Note that while the JSON Java API provides some helper classes (JSONWriter and JSONStringer) that allow you to use a JSON-like syntax flow in Java, the following example uses JSONOjbect and JSONArray directly, which are simple and effective APIs. Also, the code flow used in this approach can be easily mapped to a code flow to generate XML. The code snippet below illustrates the toJSON() helper serialization method:
Listing 4 - Generating JSON Text
/**
* Serializes this DataTypes instance
*
* @return the serialized DataTypes as JSON text
*/
public String toJSON() {
// Define an external an a nexted JSONObjects
JSONObject outer = new JSONObject();
JSONObject inner = new JSONObject();
// Now generate the JSON output
try {
outer.put("datatypes", inner); // the outer object name
inner.put("aString", aString); // a name/value pair
JSONArray ja = new JSONArray();
for (int i=0; i<anArray.length; i++) {
ja.put(anArray[i]);
}
inner.put("anArray", ja); a name/value pair
inner.put("anInteger", anInteger); a name/value pair
//inner.put("aDouble", aDouble); // Not supported on CLDC 1.0
inner.put("aLong", aLong); a name/value pair
inner.put("aBoolean", aBoolean); a name/value pair
} catch (JSONException ex) {
// ...process exception
}
return outer.toString(); // return the JSON text
}
|
Note: The use of hard-coded text literals is not a good practice, but I've used them in the example code snippets for illustration purposes.
Deserializing JSON: Initializing the Class from JSON Text
The following code snippet illustrates the helper method fromJSON(), which deserializes an input JSON text string, and initializes the instance of the DataType class:
Listing 5 - Initializing the Object from an Input JSON Text String
/**
* Initializes this instance of UserInfo and de-serializes the
* input JSON string
*
* @param ji is the input JSON string
*/
public void fromJSON(String ji) {
// First, clear the object.
aString = null;
anArray = null;
anInteger = 0;
//aDouble = 0.0; // Double not supported on CLDC 1.0
aLong = 0;
aBoolean = false;
// Now initialize from JSON text.
try {
JSONObject outer = new JSONObject(ji); // the outer objet
if (outer != null) {
// Get the inner object and parse out the data
JSONObject inner = outer.getJSONObject("datatypes");
if (inner != null) {
// Parse the name/value pairs
aString = inner.getString("aString");
JSONArray ja = inner.getJSONArray("anArray");
if (ja != null) {
anArray = new String[ja.length()];
for (int i=0; i<ja.length(); i++) {
anArray[i] = (String) ja.get(i);
}
}
anInteger = inner.getInt("anInteger");
//aDouble = inner.getDouble("aDouble");
aLong = inner.getLong("aLong");
aBoolean = inner.getBoolean("aBoolean");
}
}
} catch (Exception e) {
// ...process exception
}
}
|
Using the Serialization Methods
The following code snippet shows how to use the preceding toJSON() and fromJSON() JSON serialization methods:
Listing 6 - Using the JSON Serialization Methods
// Create an initialize instance of DataTypes
DataTypes dt = new DataTypes(
"C. Enrique Ortiz", // a String
new String[] {"tech","mobile","web", "apps"}, // an Array
15569, // an int
//0.0, // a double, not supported on CLDC 1.0
1234567890, // a long
true); // a boolean
// Covert object to JSON
String j = dt.toJSON();
System.out.println("*** toJSON: " + j);
// Initialize object from JSON
System.out.println("*** fromJSON:");
dt.fromJSON(j);
// Dump to console to see if it worked
dt.dump();
|
Following is the dump() helper method used in the preceding code for debugging:
Listing 7 - The dump() Helper Method for Debugging
/**
* Dump DataTypes for debugging
*/
public void dump() {
System.out.println(" aString: " + aString);
if (anArray != null) {
for (int i =0; i<anArray.length; i++) {
System.out.println(" tag [" + i + "]: " + anArray[i]);
}
}
System.out.println(" anInteger: " + anInteger);
//System.out.println(" aDouble: " + aDouble);
System.out.println(" aLong: " + aLong);
System.out.println(" aBoolean: " + aBoolean);
}
|
In this article, I have introduced JSON for ME as an alternative to XML. JSON has lightweight characteristics that make it attractive for mobile and embedded applications. With the JSON for ME Java API (contributed by Sun Microsystems), parsing JSON text is easy. The API is small enough and provides all the functionality you need for interchanging data within your application.
C. Enrique Ortiz is a long time mobile technologist and blogger. He is a mobility enthusiast, practitioner and professional, with many years of experience in end-to-end mobile computing.
|
|