A simple Java JSON API which supports encoding and decoding of POJOs too.
(free and open source)
Version 0.3.0
06-Jun-2021
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 hierarchical set of name value pairs and a codec to map between JSON and sets of plain Java objects using the reflection API. Both methods will be explained in the following sections.
Using this method, you get access to the JSON content via the classes JSONObject and JSONArray. The Parser creates a hierarchy of instances of these classes according to the given JSON document.
In both cases, values are decoded from the given string and stored in scalar types such as Integer, Double, Boolean etc.
The following JSON document:
{ "member1": 1.0, "member2": true, "member3": [ { "m1": "Hello my friend!" }, { "m1": null } ] }Can be parsed with an instance of the class Parser of this package:
Parser p = ParserFactory.getDefault().create(); JSONObject json = p.parse(jsonString);
The given example above would result in an object hierarchy like this:
Access to the member variables is provided via get
and set
methods.
if ((boolean)json.get("member2")) { JSONArray array = (JSONArray)json.get("member3") JSONObject object = (JSONObject)array.get(1); object.set("m1", "You'r not my friend, dude!"); }
Both classes (JSONObject and JSONArray) provide a method toString
to receive the JSON document.
String jsonString = jsonObject.toString();
Using this method is based on the use of the JSONCodec in this package. It allows you to map JSON documents directly to Java objects and vice versa. This of course requires that the class of the object contains the member variables which exist in the JSON document.
Important Rules:
static
and transient
members will be ignored.Note: The codec internally uses the Parser class to turn the JSON document in instances of JSONObject and JSONArray before it maps it to your Java object. A better solution (possibly coming in future) is to parse it directly to the object.
class A { double member1; boolean member2; B[] member3; /* hide this from the JSON codec */ transient int dont_mind_me; } class B { String m1; }
The JSONCodec is used to decode the given JSON document to your Java object.
JSONCodec codec = new JSONCodec(); A obj = new A(); codec.decodeObject(jsonString, obj);
Access is much simpler this way, as the next code fragment demonstrates, which realises the same functionality as in the example above.
if (obj.member2) { obj.member3[1].m1 = "Now we'r talking!"; }
The codec is also used to turn any Java object into a JSON document.
String jsonString = codec.encodeObject(a);
static
or transient
As a feature, static
and transient
members of an object will be ignored by the codec. The transient
modifier allows you to control which members will be ignored by the codec which (for example) comes in handy if you have to resolve cyclic dependencies in your data model or you have runtime variables as members which you don't want to be persistent. The static
members have been excluded because they are actually not a member of the object but of the class. That means, there is no point in storing them in every object.
transient
as shown in the example below.
class A { B refB; } class B { transient A refA; }
class
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; }
JSON does not know anything about classes and is not type save. Thus, the parser requires additional information to determine the actual type of an object if it does not match with the type of the variable which will receive the reference.
Since Java has built-in runtime type information on each object stored in a global variable for each class which is called "class
", this attribute name is implicitly reserved and can be used for this purpose if required.
For this purpose, you can configure the JSONCodec to use the class
attribute. Refer to class JSONCodecConfiguration
to do so.
When enabled, the codec will compare the type of a reference and the type of a referenced object and in case of differences (inheritance) it will automatically add an attribute class
which holds the name of the class, when encoding. When decoding, the codec will in turn search for an attribute class
and use the type information 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(); cfg.considerClassAttribute = 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 = (PolymorphismUser) 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());