I have an RPC service in GWT that needs to return a List. The List can be filled with various types of objects, all of which are serializable and all of are referenced elsewhere in my service so they should be available to GWT RPC. However, unless I put on a generic type parameter (e.g. ArrayList<String>
), GWT gives me the warning:
Return type: java.util.ArrayList java.util.ArrayList Verifying instantiability java.util.ArrayList [WARN] Checking all subtypes of Object which qualify for serialization` Adding '465' new generated units
Essentially, I just want a way to declare List or ArrayList without GWT trying to generate code for every serializable object on the class path. Isn't there some way to tell GWT that I know what I'm doing and not to go crazy?
You will have to help GWT by being very precise in what you return. A typical solution is to use a root class or marker interface and declare that the RPC method returns an ArrayList, then GWT can trim down the possible types.
Let me expand on what David Nouls said. The GWT compiler can't read your mind, so when you fail to specify what the return types can be, GWT assumes that it can be anything, and has to do extra work to make sure that can happen on the Javascript client side.
You really should specify what types are able to be returned. There is only upside to doing this--as the compiler will produce more optimized code, rather than generating code to handle '465 genreated units', so your downloads will be faster.
I would suggest creating an empty interface called "BaseResult" and then having the objects you return all implement that that interface.
Then you specify that the return type of your rpc method is ArrayList:
Then make sure your return objects all implement that interface.
Now the GWT compiler will have a much easier time optimizing for your code.
If you add an
ArrayList
or similarly anObject
field to a serializable object, the GWT compiler has no choice but to include all possible variants in its compilation. You are essentially declaring I can send anything using this field , so the compiler makes sure that you are able to send anything.The solution is to declare , using generic parameters, the specific types you are sending. That might require splitting into multiple parameters or classes, but it does keep the code size and compile time down.
It is less than desirable to have the GWT compiler build type serializers for everything under the sun; in the worst case, it fails entirely because, for example, there can be a class (from let's say a third-party GWT library that you are using) that declares a type in the "client" package that implements java.io.Serializable. Should you attempt to use that type in your code, it becomes part of the classpath that the GWT compiler analyzes to build a type serializer for; however, at runtime the class isn't part of the classpath on the server because the type was defined in the "client" package and therefore not compiled for the server! RPC calls, whether they attempt to use that specific type or not, fail with a ClassNotFound exception. Perfect!
It is also, as the poster articulated, impossible to make existing primitive types implement some marker interface whether it be IsSerializable or a custom marker interface (such as BaseResult as suggested above).
Nonetheless, a solution is needed! So here is what I came up with: 1) Use IsSerializable (or some subclass of it) rather than using java.io.Serializable on all your custom transfer objects.
2) Use the following implementation of RpcObject in those instances where you need a generic object type to hold a value that you know will be GWT-RPC serializable (whether it be one of your custom transfer objects that implements IsSerializable or a more "primitive" type such as java.lang.String [see the comments in the RpcObject implementation below for those types that have been whitelisted] that GWT already knows how to serialize!)
This solution is working for me...it both keeps GWT from building type-serializers for every java.io.Serializable class under the sun while at the same time allows me as the developer to transfer values around using a single/uniform type for primitives (that I can't add the IsSerializable marker interface to) as well as my own custom IsSerializable transfer objects. Here is an example of using RpcObject (although using it is so simple, I feel a bit strange about including such examples):
Thanks to the java-generics trickery of the getValue() method, casting can be kept to a minimum, so to retrieve the value (whether it be on the client or the server), you can just do the following without any need for a cast:
You can just as easily transfer one of your custom IsSerializable type:
And again, later on the client or server, the value can be fetched easily (without casting):
You can just as easily wrap something such as java.util.ArrayList:
And once again, later in either the client or server code, you can get the List back with:
After looking at the "white-listing" in RpcObject, you may be inclined to think that only
List<String>
would have been white-listed; you would be wrong ;-) As long as all the values added to theList
are IsSerializable or objects of types from the JRE that GWT-RPC just knows how to serialize, then you'll be all set. However, if you do need to white-list additional types, for example a type from a third-party library that used java.io.Serializable instead of IsSerializable may need to be individually white-listed (see the implementation of RpcObject for details), they can be added as new fields directly in RpcObject, or to keep the overhead lower in the common cases, add them to a subclass of RpcObject and use the subclass only when needed (since it is a subclass, none of your client or server method signatures would need to change from using the generic RpcObject type).I am using this strategy to solve problems nearly identical to those described by the original poster. I hope that other may find it a useful technique as well, but as always, your mileage may vary... If the school of GWT thought has advanced beyond this technique, please comment and let me know!
-Jeff