Package org.cakelab.json
This package contains a JSON API and a JSON/POJO codec.
This package provides two ways to deal with JSON documents. A simple API mapping the JSON document to a JSON object tree in Java and a codec to map a JSON document to plain Java objects using the reflection API.
JSON Object Tree
JSON object tree is a representation of a JSON object in Java. Mapping between JSON objects and their Java representation is depicted in the following table:
JSON type | Java Representation |
---|---|
object | JSONObject |
array | JSONArray |
true/false | Boolean |
number | Double/Long |
string | String |
null | null |
- Instances of JSONObject contain name-value pairs while a value can reference other instances of JSONObject or JSONArray.
- Instances of JSONArray contain a list of values while a value can be a reference to another JSONObject or JSONArray again.
JSON numbers are mapped to either Long or Double to keep accuracy high. JSONObject and JSONArray provide methods to retrieve either counterpart.
Example
The following JSON document:
{ "member1": 1.0, "member2": true, "member3": [ { "m1": "Hello friend!" }, { "m2": null } ] }Can be parsed with an instance of the class Parser of this package:
JSONParser p = new DefaultParser(); JSONObject json = p.parse(jsonString);
Access to the member variables is provided via get
and set
methods.
if (json.getBoolean("member2")) { JSONArray array = json.getArray("member3") JSONObject object = array.getObject(1); object.set("m2", "Hello there!"); }
Both classes (JSONObject and JSONArray) provide a method toString
to
receive the corresponding JSON document with indenting.
String jsonString = jsonObject.toString();
A more compact representation can be achieved by a so-called JSONFormatter named JSONFormatterCompact.
JSONFormatter formatter = new JSONFormatterCompact(); String jsonString = jsonObject.toString(formatter);
Mapping to Java Objects
The JSONCodec allows to map JSON documents to Java objects and vice versa. This of course requires that the class of that object contains member variables corresponding to the entries found in a JSON object of a JSON document.
Rules:
- The data model has to be hierarchical.
static
andtransient
members will be ignored.- Do not use nested classes (not supported yet).
- If you are using polymorphism on classes of member attributes you have to configure the codec specially (see Section on polymorphism below).
Example
To map the JSON document given above to Java objects you would need classes like this:class A { double member1; boolean member2; B[] member3; transient int dont_mind_me; /* <-- hidden from encoding/decoding */ } class B { String m1; }
The JSONCodec is used to decode the given JSON document to Java objects.
A obj = jsonCodec.decodeObject(jsonString, A.class);
Or like this:
A obj = new A(); jsonCodec.decodeObject(jsonString, obj);
The codec is also used to turn Java objects into JSON documents.
String jsonString = codec.encodeObject(a);
Data Model Conversion
The JSONModeller converts between JSON object tree representation and a given Java object Data Model. This is useful, when assembling a JSON object tree in parts manually. The data model must conform to the same rules stated in section Mapping to Java Objects.
Example: Adding an object to given object tree root:
JSONObject root = ...; MyObject myObject = ...; JSONModeller modeller = new JSONModeller(cfg); JSONObject jsonObject = modeller.toJSON(myObject); root.put("myObject", jsonObject);
Example: Receiving an object from a given JSON object tree:
JSONObject root = ...; JSONModeller modeller = new JSONModeller(cfg); JSONObject jsonObject = root.get("myObject"); MyObject myObject = modeller.toJavaObject(jsonObject, MyObject.class);A JSONFormatter and JSONParser can be used to transform between JSON document and JSON object tree representation to complete the cycle.
Rules and Workarounds
Modifiers static
and transient
As a feature, static
and transient
members of an object
will be ignored during the encoding/decoding process. This allows to control which
data will be actually encoded.
Resolving Cyclic Dependencies
The codec traverses through your data model by iterating over all members of the given
root object and following each reference to other objects. Thus, a data model must be
strictly hierarchically (tree-like). Cyclic dependencies have to be resolved by the use
of the transient
modifier.
The following example demonstrates the use of transient
to resolve a cyclic dependency between two classes A
and
B
.
class A { B refB; } class B { transient A refA; }
Polymorphism
Use of Polymorphism requires type information about objects referenced through a super class or interface. A JSONCodec must be configured to add this information (see JSONCodecConfiguration.supportClassAttribute).class MySuperClass {} class A extends MySuperClass {} class B extends MySuperClass {} /* class with a reference on any of those subclasses */ class PolymorphismUser { MySuperClass ref_on_A_or_B; }
When support of the 'class' attribute is enabled, the codec will compare the type of a
reference to the type of the referenced object. A class
attribute
will be added to the corresponding JSON object, if reference type and referenced
object type differ.
The class
attribute will then carry the fully qualified name of the
referenced object type.
When decoding, the JSONCodec (or JSONModeller, see below) will in turn search for
a class
attribute in such cases, to instantiate the proper object.
/* given an object with reference on A, while reference is of type SuperClass */ PolymorphismUser object = new PolymorphismUser(); object.ref_on_A_or_B = new A(); /* configure and instantiate a codec which supports the "class" attribute. */ JSONCodecConfiguration cfg = new JSONCodecConfiguration() .supportClassAttribute(true); JSONCodec codec = new JSONCodec(cfg); /* encode object into a json string */ String json = codec.encodeObject(object); /* and decode it again using a codec with the same configuration */ PolymorphismUser o2 = codec.decodeObject(json, PolymorphismUser.class); /* member o2.ref_on_A_or_B is of type A again. */ assert object.ref_on_A_or_B.getClass().equals(o2.ref_on_A_or_B.getClass());
-
Interface Summary Interface Description JSONCompoundType Common interface of JSONObject and JSONArray -
Class Summary Class Description JSONArray JSONDefaults JSONObject -
Exception Summary Exception Description JSONException