Understanding Creation of GWT Serialization Policy Files (.gwt.rpc)

Today I deep-dived a bit into how GWT creates and reads Serialization Policy files. These are the .gwt.rpc files which are generated beside the JavaScript files for GWT modules.

Chiefly, I learned two things:

  • The .gwt.rpc files are only used by the server. The client never reads them.
  • The .gwt.rpc files are generated in the ProxyCreator class.

I have listed some further classes and links below.

GWT Framework Classes

ProxyCreator: Creates the .gwt.rpc file

RemoteServiceProxy: Manages calls to services

ClientSerializationStreamWriter: Write serialization on client for server

ClientSerializationStreamReader: Read responses from server on client

Serializer: Interface for serialization contract for class

Links

The GWT RPC Wire Protocol

 

Run GWT Generated Code in Nashorn

GWT is a very useful tool to compile Java code into JavaScript.

Nashorn is Oracle’s new JavaScript implementation which runs JavaScript scripts in Java.

In order to run JavaScript server-side code within a Java server I now want to make an extensive GWT library available to this JavaScript code.

For this I need to load code generated in GWT into a Nashorn engine.

This is not very easy since the load process of GWT libraries includes various ‘hacks’ which involve the DOM.

I don’t know yet how I am going to do this exactly. I found the gwt-node project. This project is meant to run GWT code on Node.js.

I think by working with the custom linker developed there (GwtNodeLinker.java) I might be able work something out.

Cross-Domain Requests in GWT with JSONP

GWT RPC is built upon AJAX requests and thus is subject to the Same-Origin Policy. However, it is really easy in GWT (as well as in other JavaScript applications) to circumvent this policy using a method called JSON-with-padding (JSONP).

Unfortunately, there are a couple of issues one needs to consider before utilizing JSON-P:

Amount of Data Send from Client to Server

The biggest limitation of JSONP is that it uses GET and not POST requests. Thus, all data send from the client to the server needs to be encoded as URL query parameters such as:

http://myserver.com/myrpctarget?data_from_client=lotsofdatafromclient

These URL parameters can only hold a limited amount of data. I couldn’t find a conclusive upper limit on this, but most sensible suggestions seem to indicate that parameters should be limited to between 2,000 or 4,000 bytes. Please note that many sources here discuss the limit of characters which can be put into a browsers address bar. This limit is not the same as the limit for GET requests triggered from within JS code.

Reliance on GWT RPC

It is a non-trivial (but not impossible – I’ve done it!) endeavor to channel GWT RPC requests through JSONP. Thus, if your application is deeply dependent on GWT RPC, it will probably involve a lot of work to make it JSONP ready. Good news is that if you use the Request Builder API things will be far easier.

Other than these two issues there is really nothing stopping you from writing GWT client applications, which can communicate with multiple servers. I believe that this decoupling from client and server is far more valuable than the added security derived from restricting requests to one domain. After all, the browser is a client application which is by design meant to communicate with many different servers. If you have a choice, consider the two factors above and architect your GWT applications from the very beginning in a way which enables JSONP requests.

Resources

GWT JavaDoc – JsonpRequestBuilder

Wikipedia – JSONP

GWT 2, JSONP and Javascript Overlays with JsonpRequestBuilder

GWT Exclude Package From Source Path

Problem

The Google Web Toolkit Java to JavaScript transpiler is a powerful tool to convert Java source code into JavaScript files. Unfortunately, not all Java code can be transpiled into JavaScript code by GWT.

Sometimes, a project contains a mix of Java code that can be converted into JavaScript and Java code that doesn’t. In that case, the GWT compiler issues errors such as ‘No source code is available for type …‘.

Solution

GWT module definitions (.gwt.xml) files allow to specify fine-grained rules which files in a project are to be converted and which files should not. The rules are based on Ant patterns, which can be difficult to wrap one’s head around. Below are a few handy examples.

Exclude all files in packages with the name ‘/jre/’

<source path='' >

    <exclude name="**/jre/**" />
</source>

Exclude the file ‘ForJre.java’:

<source path='' >
   <exclude name="**/ForJre.java" />
</source>

GWT Object Serialization with gwt-storage

Problem

The built in Java Serialization and various serialization frameworks available for Java allow to serialize Java objects conveniently into binary or textual representations. Unfortunately, most of these frameworks are not available for Google Web Toolkit client applications.

There is no easily available built in solution for serializing GWT objects into text on the GWT client side. This is surprising since GWT evidently has a mechanism to serialize and deserialize objects to support GWT RPC.

Solution

Seanchenxi has kindly created a convenient wrapper around the GWT RPC serialization mechanism, which makes it very easy to serialize and deserialize objects on a GWT client application into String representations. The project, gwt-storage, is available on github:

https://github.com/seanchenxi/gwt-storage

You can download the source code and import it to your Java project. I’ve also uploaded the project to a public Maven repository. You can add it to your Maven project as follows:


<dependencies>

<dependency>

<groupId>com.seanchenxi.gwt</groupId>

<artifactId>gwt-storage</artifactId>

<version>1.2</version>

</dependency>

</dependencies>

…

<repositories>

<repository>

<id>Appjangle</id>

<url>http://maven.appjangle.com/appjangle/releases/</url>

</repository>

</repositories>

With gwt-storage available for your project, you can do the following in GWT client side code:


StorageSerializer serializerImpl = new com.seanchenxi.gwt.storage.client.serializer.StorageRPCSerializerImpl();

try {

MyClass obj = new MyClass("1234");

String serialized = serializerImpl.serialize(Serializable.class, obj);

GWT.log("Serialized Object: "+serialized);

MyClass deserialized = (MyClass) serializerImpl.deserialize(

Serializable.class, serialized);

} catch (SerializationException e) {

throw new RuntimeException(e);

}

Note:

  • If you download the gwt-storage source code, you might have to change the visibility of the class StorageRPCSerializerImpl() to public (from package).
  • MyClass needs to be serializable by GWT RPC; that is, implement Serializable and have non-transient references that are Serializable as well.
  • If you change the implementation of the class MyClass, deserialization of Strings created with older versions of the class will probably not be possible.

References

Serializing objects in GWT and deserializing them in servlet

GWT Google Groups ‘GWT client side Java object serialization’

GWT RPC Serialization for LocalStorage

GWT RPC is a great technology for sending ‘Java’ objects from a Java sever to a JavaScript client and vice averse. Since GWT RPC provides facilities for serializing and deseralizing Java objects, it seems like a good option, too, for preparing objects to be stored in a browsers LocalStorage.

Unfortunately, the devil lies in the details here, since GWT RPC is implemented in an asymmetrical way:

  • The client can only deseralize objects serialized on the server and
  • Only the server can deseralize objects serialized on the client.

Fortunately, however, with a few modifications the GWT RPC serialization mechanism can be adjusted to support client-client serialization.

The gwt-storage project available on GitHub does exactly that for us. Check out the getting started guide for this project here. Here a simple example:

StorageExt localStorage = StorageExt.getLocalStorage();

localStorage.put(key, gwtObject);


GwtClass gwtObject = localStorage.get(key);

Note that for this code to work, GwtClass must be involved in one of your GWT RPC services.

Further Information

Stackoverflow ‘How to apply SerializationStreamWriter for storage’

GWT Docs class RPC

SerializationStreamWriter (client)

Something other than a Java object was returned from JSNI method

Google Web Toolkit allows building powerful bridges between the world of Java and JavaScript using so called JS overlay objects.

However, these overlay objects can become it bit tricky if it is not certain what the type of objects passed from JavaScript will be.

Wait? Types and JavaScript? Yes, but only the most fundamental ones of `string`, `number` and `Boolean`.

Problem

Variations of the following exceptions are reported in GWT hosted mode, if the wrong type is declared in the JS overlay object.

java.lang.IllegalArgumentException: Something other than a Java object was returned from JSNI method ‘@one.app.js.api.IntParams::getValue()’: JS value of type boolean, expected java.lang.Object

 

In the example above, a method such as the following might have been declared in the JS overlay object:

public final native Object getValue()/*-{ this.value; }-*/;

Howerver, `this.value` happened to be of the type `boolean` in JavaScript.

Solution

An easy solution is to change the declaration of the method in the JavaScript overlay type to:

public final native boolean getValue()/*-{ this.value; }-*/;

However, things are a bit more difficult, if depending on the context, `this.value` can take on values of different type than boolean (for instance `number` or java script object).

In this case, the a little bit more work is required. First, the function in the overlay type must be changed to something like:

public final native Object getValue() /*-{ 
	if ( this.value && 
	     ((typeof this.value == "number") || 
	      (typeof this.value == "boolean")) ) {
		return {
			type: "JsAtomicTypeWrapper",
			value: this.value
		};
	}

	return this.value;
}-*/;

This method replaces the value with a wrapper JS object. For retrieving the value, another JS overlay type can be introduced to extract the value such as:

ublic class JsAtomicTypeWrapper extends JavaScriptObject {

	protected JsAtomicTypeWrapper() {
	}

	public final native boolean isWrapper()/*-{ 
		if ( this.type && this.type == "JsAtomicTypeWrapper") return true;
		return false;
	}-*/;

	public final native boolean isBoolean()/*-{ 
		return typeof this.value == "boolean";
	}-*/;

	public final native boolean isDouble()/*-{ 
		return !isNaN(parseFloat(this.value));
	}-*/;

	public final native boolean isInteger()/*-{ 
		return this.value % 1 === 0;
	}-*/;

	public final Object getValue() {
		if (isBoolean()) {
			return getBooleanValue();
		}

		if (isInteger()) {
			return getIntValue();
		}

		if (isDouble()) {
			return getDoubleValue();
		}

		return getGenericValue();

	}

	public final native Object getGenericValue()/*-{ 
		return this.value; 
	}-*/;

	public final native int getIntValue()/*-{ 
		return this.value; 
	}-*/;

	public final native double getDoubleValue()/*-{ 
		return this.value; 
	}-*/;

	public final native boolean getBooleanValue()/*-{ 
		return this.value; 
	}-*/;

}

When reading the returned value of the first JS overlay type, the JsAtomicType Wrapper overlay type can be used as follows:

JsAtomicTypeWrapper wrapper;
wrapper = ((JavaScriptObject) jso.getValue()).cast();

if (wrapper.isWrapper()) {
	GWT.log("Number value: " + wrapper.getValue());
	GWT.log("Number value class: " + wrapper.getValue().getClass());
}