My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
JsonSerialization  

Featured, Json
Updated Feb 4, 2010 by miroslav...@gmail.com

Motivation

GWT currently provides the very powerful and yet simple RPC mechanism that seemlessly brings rpc with java object serialization to browser based fat clients. This however has a limitation in that the backend must also be a j2ee server. In order to invoke json services developers must manually marshal json values to and from java objects.

The Solution

The rocket.json package includes a simple automate the mapping between java objects and json.

The module supports the following mappings between json to java.

JSON Type Possible Java Type equivalents
objects java instances or a Map composed of key/value pairs
arrays become a List or Set of instances
numbers become any of the numeric primitive byte, short, int, long, float, or double.
strings java.lang.String or chars(which are actually useless but included for completeness)
booleans booleans

Marking a class as serializable

Following in java / gwt tradition a marker interface must be implemented by classes that wish to be serializable. In the case of the rocket library this is rocket.json.client.JsonSerializable.

By design the java.io.Serializable and com.google.gwt.user.client.rpc.IsSerializable are already mapped to a different Generator which produces (de)serializers for the GWT rpc subsystem.

Fields annotations

The rocket json package needs some help in mapping a json stream into a java object. Only non transient, instance fields will be serializable. The visibilty of the field does not affect its ability to be (de)serialized.

The generator (rocket.json.rebind.JsonSerializerGenerator) uses JSNI to set each of the individual fields belonging to the instance being built. Because JSNI code is used field visibility is not an issue, and setters are not required.

Json objects

Each json object which is ultimately made up of key/value pairs maps to a single java type. Each field belonging to the type must use annotations to note which json object property it is mapped to.

	/**
	 * Maps a value referened by the "bar" key to the foo field for the enclosed class.
	 *
	 * @jsonSerialization-javascriptPropertyName bar
	 */
	private String foo;

Json array

An annotation must be included to tell the system the type of each element of the list or set.

	/**
	 * Something about the foo field..
 	 *
	 * The elements of the foo json array will be interpretted as Strings.
	 *
	 * @jsonSerialization-listElementType <java.lang.String>
	 */
	private String foo;

Getting started

The following steps below list what and why is needed to use this facility in your own development efforts.

Importing the rocket module

Add the rocket module to your own project module.

<inherits name="Rocket.User" />

Sample Json

The sample below includes a simple json object graph which includes all json types. It will be used as the basis for the contrived Java classes created below.

	{
		"foo":	true;           // json boolean
		"bar":  123;  	        // json number
		"array": [ 1, 2, 3 ];	// json array
		"object" {
		   "baz":  "apple"; 	// json string
		}
	}

Annotating the bound types

Two separate classes are required, one for each json object present in the convulted example given above. The outter object includes 4 properties.

  • foo
  • bar
  • array
  • object

The code snippet below includes all the fields and required annotations that would be required to map the outter object to a class called OutterClass.

package example;
import rocket.json.client.JsonSerializable;

public class OutterClass implements JsonSerializable{
	/**
	 * @jsonSerialization-javascriptPropertyName foo
	 */
	private boolean foo;

	/**
	 * @jsonSerialization-javascriptPropertyName bar
	 */
	private int number;

	/**
	 * @jsonSerialization-javascriptPropertyName array
	 * @jsonSerialization-listElementType <java.lang.Integer>
	 */
	private java.util.List number;

	/**
	 * @jsonSerialization-javascriptPropertyName object
	 */
	private InnerClass innerClass;
}

The inner object includes 1 property.

  • baz

The code snippet below includes all the fields and required annotations that would be required to map the inner object to a class called InnerClass.

package example;
import rocket.json.client.JsonSerializable;

public class InnerClass implements JsonSerializable{
	/**
	* @jsonSerialization-javascriptPropertyName baz
	*/
	private String baz;
}

Binding json to and from a java object instance

Include required import statements.

import rocket.json.client.JsonSerializer;

To de serialize a json object to java a reference a JsonSerializer must obtained using deferred binding.

JSONObject jsonObject = // already got it from somewhere...
JsonSerializer serializer = (JsonSerializer) GWT.create( SomeClass.class );

Then proceed to ask the serializer to build a java object from the given json object. A rocket.json.client.JsonDeserializationException (its not a checked exception) will be thrown if anything goes wrong.

SomeClass instance = (SomeClass) serializer.writeJson( jsonObject );

To serialize from java back to json is quite simple as demonstrated by the example below.

JSONValue json = serializer.writeJson( instance );

Further samples

For further examples refer to the unit test

  • rocket.json.test.client.JsonGwtTestCase

Comment by reallyme...@gmail.com, Nov 20, 2007

BIG FAT WARNING:

use @jsonSerialization-listElementType java.lang.Integer not @jsonSerialization-listElementType <java.lang.Integer>

Adding the enclosing "<>" breaks it..

Comment by jon.r.cr...@gmail.com, Nov 30, 2007

One minor tweak for the docs here, "Rocker.User" should be "rocket.User" in the "inherits" statement above.

Comment by szoc...@gmail.com, Jan 29, 2009

This is Great!

Any plans for a variant that would use JAXB annotation instead of the current custom annotations? It would be nice to be able to use the same JAXB annotated DTO I already have for the server side.

Comment by chris.hi...@gmail.com, Feb 26, 2009

Just a quick note because I spent some time searching. Make a field static or transient if you do not want to serialize it. There is not an ignore annotation to ignore a field. The transient modifier should most commonly be used.

Thanks Miroslav for a great tool.

Comment by nyst...@gmail.com, May 4, 2009

Rocket does not compile any longer with gwt 1.6 For using json, I've extracted the modules: "generator json text util" from rocket.jar, and then it builds (hosted mode) and compiles ok.

Is anyone making rocket gwt16 compliant ?

Comment by kazakev...@devexperts.com, May 7, 2009

Another fat warning:

Annotation has been chaged for gwt 1.6.

instead of @jsonSerialization-listElementType

use @jsonSerialization-type

Hope it helps

Comment by mar...@gmail.com, Jun 13, 2009

Is this supported for GWT 1.6.x?

Comment by pascal.d...@gmail.com, Nov 15, 2009

FYI, it almost works with 1.7.1: the JSON part I mean. I did the same as nystony: I've extracted the modules: "generator json text util" and then it builds. I could also use it in compiled mode. I just compiled my gwt.xml. ONLY it, not all the related "generator json text util" since they do not have any EntryPoint?. Check this port for explanation about this point: http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/d6777b8d62ebe818

About the OutterClass?, I had to remove

/
  • @jsonSerialization-javascriptPropertyName array
  • @jsonSerialization-type <java.lang.Integer>
private java.util.List number;
since List is an interface and no default constructor is available on it (of course) I give it another try by replacing List by ArrayList?. not more sucessfull: I guess there i s a kind of 'I search for a default constructor on the given class, but also on its ancestors', which makes no sense.

Note: as you could read it, it's @jsonSerialization-type and not @jsonSerialization-listElementType. kazakev...@devexperts.com is right about that.

If someone can solve the List bug, that would be great.

Regards

Comment by pascal.d...@gmail.com, Nov 15, 2009

ok.. About that List stuff: in GWT 1.7.1, the com.google.gwt.core.ext.typeinfo.JRealClassType.isDefaultInstantiable() method begin with this code:

if (isInterface() != null || isAbstract()) {
return false;
}
so it return false for List and ArrayList? (inherits of AbstractList?). But it should work with ArrayList? since it has protected AbstractList?() protected AbstractList?() constructor. Well, it is protected, but it is there. So the rocket.generator.rebind.gwt.JRealClassOrJRawClassTypeTypeAdapter public boolean hasNoArgumentsConstructor() {
return this.getJClassType().isDefaultInstantiable();
}
should be implemented in some other way. Can the Rocket team fix this?

Comment by kfun...@gmail.com, Mar 30, 2010

You can forget it in GWT 2.0+

SomeClass? instance = (SomeClass?) serializer.writeJson( jsonObject );

causes error: "Cannot cast from JSONValue to SomeClass?"

Comment by lvx...@gmail.com, Apr 6, 2010

Is there any security problem when converting jason to java object?

Comment by harald.pehl, Jun 21, 2010

In case anybody is interested: I wrote a JSON/XML mapper for GWT. Feel free to take a look at it under http://code.google.com/p/piriti/


Sign in to add a comment
Powered by Google Project Hosting