Wednesday, April 6, 2011

GWT SerializationException on RPC call when providing List from a ListDataProvider

The Issue: When attempting to send a List<T> object as a parameter of an RPC method call from client to server, the RPC call failed reporting a com.google.gwt.user.client.rpc.SerializationException had been thrown. Our first response then was to assume that our list objects, T, did not properly adhere to the GWT serialization requirements as outlined here Serializable Types. However once we confirmed this was not the case we were left wondering what could cause this issue.

Up until now we had generally assumed that sending a List<T> across the wire would not cause any serialization issues so long as T could be serialized. However this is not strictly true, the List implementation itself must also be serializable for the RPC call to succeed. Since most of the time your List implementations will likely be an ArrayList or a LinkedList, both of which implement the Java Serializable interface, it could be easy to forget to check this.

However this issue may begin to crop up more often with the introduction of the ListDataProvider in GWT 2.1. The ListDataProvider class wraps a List object in order to provide data binding to the new GWT cell widgets. What may surprise you is that the wrapped List is not implemented as an ArrayList or LinkedList but as a ListWrapper. The ListWrapper is an inner class of the ListDataProvider which implements List<T> but does not implement any Serializable interface.

Therefore the following code will throw the aforementioned com.google.gwt.user.client.rpc.SerializationException

       rpcService.anRpcCall(listDataProvider.getList(), new AsyncCallback<Void>) {... //tries to send a ListWrapper

The solution: Do not attempt to directly pass the result of listDataProvider.getList() to the server. Instead you need to construct a List implementation you know is Serializable and pass in the contents of the ListWrapper.

      List<MySerializableType> serializableList = new ArrayList<MySerializableType>();
      serializableList.addAll(listDataProvider.getList());
      rpcService.anRpcCall(serializableList, new AsyncCallback<Void>) {...

More generally, always check that your Collection implementations are serializable before transmitting them across the wire. You may even consider declaring the parameter types of your RPC calls to be a concrete type that you know to be serializable instead of an interface - for example declare ArrayList<T> instead of List<T>.

No comments:

Post a Comment