Flexjson

JavaScript Object Notation (aka JSON) is a very popular alternative to XML for transmitting data to the web browser. Flexjson is a lightweight library for serializing Java objects into JSON. What's different about Flexjson is it's control over what gets serialized allowing both deep and shallow copies of objects. Most JSON serializers mimic object serialization libraries and try to serialize the entire object graph from the object being turned into JSON. This causes problems when you want a connected object model in your server, but you can't send that object model to the client because the serialization library will try to send the entire object graph. This makes it very hard to create object oriented models and serialize pieces of that model to the client without sending everything. Other JSON libraries require you to create a lot of boiler plate code to translate your object representation into a JSON object. In this regard I shouldn't have to explain myself, but to keep it short let's me just say I hate boiler plate translation code! Flexjson tries to solve both of these problems by offering a higher level API or dare I say DSL for specifying your intent.

In order to explore Flexjson we will be using the following model. Let's say we're building a PIM or contact management application. Here are some classes we might see in an application like this along with the relationships between them.

UML Diagram of Person, Address, Zipcode, and Phone classes.

In the above diagram you can see Person has many instances of Phone, and has many Addresses. While this is a trival object model it will help us demostrate the ideas behind Flexjson.

Flexjson takes a different approach allowing you to control the depth to which it will serialize. It's very similiar in concept to lazy loading in Hibernate which allows you to have a connected object model, but control what objects are loaded out of your database for performance. Let's look at a simple example first to get a feel for how the library works. Say we are serializing an instance of Person. We might do the following:

public String doSomething( Object arg1, ... ) { Person p = ...load a person...; JSONSerializer serializer = new JSONSerializer(); return serializer.serialize( p ); }

The above would produce the following output:

{ "class": "Person", "name": "William Shakespeare", "birthday": new Date(-12802392000000), "nickname": "Bill" }

Looks pretty much like you'd expect. However, our Person object contains more fields that name, birthday, and nickname so what happened to phoneNumbers, and addresses? By default Flexjson serializes the immediate fields of that object. It's just a shallow representation of the object. All collections and other object references are not serialized by default. Or said another way any one to one, many to one, one to many, many to many relationships are not serizialized by default. But, let's say we did want to serialize the phoneNumbers then we could do the following:

public String doSomething( Object arg1, ... ) { Person p = ...load a person...; return new JSONSerializer().include("phoneNumbers").serialize(p); }

In this example, we're telling the serializer to include the following fields from the target object. Collections are serialized in full including the shallow copy of the objects they contain. So in our example, Person has a List field called phoneNumbers, and that List contains Phone instances. This means Flexjson will send a shallow copy of Person, the List of phoneNumbers, and a shallow copy of each Phone instance within the List. So the output might look like:

{ "class": "Person", "name": "William Shakespeare", "birthday": new Date( -12802392000000 ), "nickname": "Bill" "phoneNumbers": [ { "class": "Phone", "name": "cell", "number": "555-123-4567" }, { "class": "Phone", "name": "home", "number": "555-987-6543" }, { "class": "Phone", "name": "work", "number": "555-678-3542" } ] }

Getting the hang of it? It's pretty simple. If you wanted to send both phoneNumbers and addresses you can call include method twice, or you can include two parameters to the include method using Java's new vararg feature. Personally I prefer the later since I think it makes it shorter and easier to read. But, it's your choice.

public String doSomething( Object arg1, ... ) { Person p = ...load a person...; return new JSONSerializer().include("phoneNumbers", "addresses").serialize(p); }

So in this case we'll only get the street, city, and state, but not the zipcode because that is an object reference. It's an easy fix using the dot notation. Here is an example to include the zipcode with each Address instance.

public String doSomething( Object arg1, ... ) { Person p = ...load a person...; return new JSONSerializer().include("phoneNumbers", "addresses.zipcode").serialize(p); }

Flexjson is smart enough to know you mean the object contained with this collection and not the collection itself. It's also smart enough to know that the addresses reference has to be included in order to include zipcode so you don't have to specify it twice. You can use the dot notation to trace over your object graph very easily.

There is an alternate form of serialize() method that allows you to specify an outer object for collections. There are some javascript libraries like EXTJS (previously known as YUI-EXT) that require this for their JSON data models. However, I haven't found any JSON libraries that offer this type of serialization. Here is an example:

public String getPeople( Object arg1, ... ) { List people = ...load a person...; return new JSONSerializer().include("phoneNumbers").serialize("people", people); }

The resulting JSON would look like the following:

{ "people" : [ { "class": "Person", "name": "Warren Buffet", "birthday": new Date( -1241467200000 ), "nickname": "Oracle of Omaha", "phonNumbers" : [ ... ], }, { "class": "Person", "name": "Steven Jobs", "birthday": new Date( -468702000000 ), "nickname": "Steve", "phonNumbers" : [ ... ], } ] }

Not only can you include, but you can specify it in terms of exclude as well. The exclude() method allows you to exclude certain fields from serilization. This can come in handy if you have special fields that you don't want sent to the client like passwords, or secret data that should remain on the server.

public String doSomething( Object arg1, ... ) { User u = ...load a user...; return new JSONSerializer().exclude("password").include("hobbies")serialize(p); }

Using dot notation with exludes has a subtle difference in it's use when compared with includes. If you exclude a nested field it implies that the rest of the parent object is included. So if I say exclude("head.rightEye.retinalScan"). The retinalScan member of rightEye field will be excluded, but both rightEye and head field will be included. The reason is in order to exclude retinalScan field you have to include the rightEye member. If you didn't then it doesn't change anything because retinalScan wasn't going to be included in the first place. Said another way it's only the last field that is excluded all other parent fields are included.

Always having to do your excludes in this manner can be cumbersome especially if you always intend something to be excluded or included. Flexjson provides a way to express this using annotations. The JSON annotation can be used to mark a field in the object as included by default. Annotations can be placed on the methods or fields. A good example of this might be the Address object that contains a reference to Zipcode object. Since Zipcode is an integral part of every Address (in the US) then it might make more sense for us to default this with the annotation. So in our Address object we could do the following:

public class Address { private String name; private String street; private String city; private String state; private Zipcode zipcode; @JSON public Zipcode getZipcode() { } }

Annotations can improve your security so that fields that shouldn't be sent over the wire ever can be fixed in one place. That way you keep your code more DRY, and that prevents accidental security flaws. Consider if we store the a hashed version of a password in our User object.

public class User { private String login; private String hashedPassword; private Date lastLogin; @JSON(include=false) public String getHashedPassword() { } }

Finally, JSONSerializer instances can be reused to serialize many objects of the same type. Once you instantiate the object you can reuse it across multiple threads so long as you don't call include or exclude methods. Typically this isn't an issue since you might follow this pattern of instantiation:

public class PersonController { JSONSerializer personSerializer; public PersonController() { personSerializer = new JSONSerializer().include("addresses.zipcdoe"); } public String listPerson() { Person p = ....; return personSerializer.serialize( p ); } public String editPerson() { Person p = ....; return personSerializer.serialize( p ); } }

That's really all you need to know about Flexjson. It's really just that simple and lightweight. Please give me some feedback. I'd love to hear about improvements or new features you would like added. Email me at charlie DOT hubbard ( I don't want spam so this is here to stop harvesters ) AT gmail DOT com.