RPC serialization

64 views
Skip to first unread message

sim123

unread,
Aug 12, 2008, 4:32:18 PM8/12/08
to Google Web Toolkit
Hello All,

My Service interface is returning a class which has Arraylist of
Objects (private List<Objects> myList;) this objects could be any java
types like String/Boolean/Integer/Date etc, how can I serialize this
type of List?

Thanks.

Ian Petersen

unread,
Aug 12, 2008, 6:39:06 PM8/12/08
to Google-We...@googlegroups.com

Painfully. One way is to use a custom field serializer. You should
be able to get some details on those by searching the list history for
CustomFieldSerializer.

It looks like your List<Object> is actually a list of value-types
because your examples were String, the wrapper types, and Date. One
potential work-around is to create a hierarchy of wrapper wrappers
that is serializable, like this:

public interface Wrapper extends Serializable {

Object getValue();
}

public class IntegerWrapper implements Wrapper {

private final Integer value;

public IntegerWrapper(Integer value) {
this.value = value;
}

public Object getValue() {
return value;
}
}

// create similar types for all possible subtypes of Object that you
might put in your List

then define your DTO to have a List<Wrapper> instead of a
List<Object>. It's ugly as sin, but it allows the compiler to
eliminate unused serialization code, which is the whole reason for
disallowing List<Object> in the first place.

If you've moved to GWT 1.5, you could possibly use type parameters to
make your code a little cleaner, but there are lots of ways to use
type parameters to get yourself back in trouble so it might not be as
useful as you think.

Ian

gregor

unread,
Aug 13, 2008, 8:36:57 AM8/13/08
to Google Web Toolkit
Unless you have strong reasons for returning arbitrary types from RPC
calls I think you should give up on the idea because it is a
significant undertaking to do it properly that goes beyond just these
serialization issues. Stick with a set of predefined Data Transfer
Objects instead that can be properly typed up in advance.

A strong reason would be if your application generates (say) a large
number of forms or data grids that vary dynamically depending on maybe
the user profile or some application state. If this is your situation
then I think you should first understand the causes of the impediments
you face and secondly have a look at some existing GWT projects that
have implememted a solution for this kind of thing:

The basic impediments are:

1) RPC does not let you pass parameters/return values of type Object
(as you have already found out). This is unlikely to change and there
are good reasons for that as explained by Sumit in this post:

http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/3bb11f01a5004cdc/b2bab8a7ed4c953c#b2bab8a7ed4c953c

2) GWT client side javascript does not support reflection. Reflection
is an important tool in for instance binding arbitrary sets java beans
to tables etc so the tables can interrogate the objects and configure
their cells accordingly. The lack of reflection is therefore a major
headache to achieve something like this in a GWT client. There is a
project that seeks to emulate reflection in GWT which is worth a read:

http://gwtreflection.sourceforge.net/

There are a couple of interesting projects posted to Google Code that
seek to address these problems in one way or another. They are
probably worth you spending some time studying as they might give you
some idea of the difficulties involved, some ideas on how to solve
your issues, and maybe an off the shelf solution.

GWT-PF

http://code.google.com/p/gwt-pf/

Looking at their javadoc they appear to take a very similar approach
to Ian's. There is an interface IDBValue that is implemented by a set
of classes representing standard Java types e.g. DBInteger. The data
in each of these is held as a String (enabling it to be easily
serialized over HTTP) but can be set and retrieved as their original
types on demand. So a List of IDBValue will go through RPC with no
problems as they are treated as just Strings by RPC (which is a direct
solution template for your problem as posted)

They also have interfaces such as IDataBinder and IForm that are
implemented in classes such as DataGridWrapper ( I can't find an
implementation of IForm) that would appear to render sets of IDBValues
as specified in DataBinders or IFormItemGroups. All this seems to give
an impression of the level of complexity involved.

GWT Model

http://code.google.com/p/gwt-model/

There is much less info about this than GWT-PF, but it uses the
aforementioned GWT reflection library to bind a model of arbitrary
types to a form (or presumably a grid table).

Anyway it looks to me like this stuff is not going to save you any
time unless you really do have good reasons to go down this road, in
which case there look to be some good ideas here.

regards
gregor

On Aug 12, 11:39 pm, "Ian Petersen" <ispet...@gmail.com> wrote:

roland

unread,
Aug 13, 2008, 5:12:59 AM8/13/08
to Google Web Toolkit
Hi Sim,

you can use List<Serializable> in your service interface. This allows
you to add String/Boolean/Integer/Date as well as any other
serializable type to your list.

Best,

Roland

sim123

unread,
Aug 13, 2008, 2:48:24 PM8/13/08
to Google Web Toolkit
First of all thank you very much to all of you for the help and your
time, I really appreciate it. The reason I have to use Object as I
have another application for data access and that API is retuning
Object which could be any java type so I can't change this return
type. However I know what all types could be returned. I tried
changing .gwt.rpc file in web mode and I put all expected types in
there like "java.sql.Time, true", "java.lang.BigDecimal, true", the
strange part is I am getting response in firebug console which has all
the types and corresponding values with status OK and my asynchronous
method is hitting onFailure and displaying an error saying "This
application is out of date, please click the refresh button on your
browser". I have no idea why is it so, I would read all the examples
link by gregor (Thanks for that) and would let you know about my
understanding meanwhile if you could please suggest me what could be
the cause of this application out of date error then that would be
great.

Thanks for the help. -sim

Ian Petersen

unread,
Aug 13, 2008, 3:32:36 PM8/13/08
to Google-We...@googlegroups.com
On Wed, Aug 13, 2008 at 2:48 PM, sim123 <sim...@gmail.com> wrote:
> I tried
> changing .gwt.rpc file in web mode and I put all expected types in
> there like "java.sql.Time, true", "java.lang.BigDecimal, true", the
> strange part is I am getting response in firebug console which has all
> the types and corresponding values with status OK and my asynchronous
> method is hitting onFailure and displaying an error saying "This
> application is out of date, please click the refresh button on your
> browser". I have no idea why is it so,

The .gwt.rpc file is a filter for security purposes, but changing it
doesn't control what types the client is actually capable of
serializing or deserializing.

The client-side RPC code is generated. The RPC generator walks over
your service interfaces trying to figure out what types might get
transmitted over the wire. For each type that is encountered, some
purpose-built code is generated that can serialize and deserialize
instances of that type. This process is recursive because class Foo
might have a member of type Bar so, if a Foo can be transmitted, then
a Bar could be, too. The net result includes a map from type name to
a triple of functions. The triple handles serialization and
deserialization for the type it's mapped from. If you change the
.gwt.rpc file to include a type not in the map, then the server might
generate a response that the client doesn't know how to deserialize.
In that case, the client will generate the "This application is out of
date" error.

As a side issue, you mentioned that you added BigDecimal to the
.gwt.rpc file. That's not going to work no matter what you
do--BigDecimal is not supported by GWT.

Ian

gregor

unread,
Aug 13, 2008, 4:36:05 PM8/13/08
to Google Web Toolkit
Hi Sim,

Well it looks to me like you could cast/transform these objects server
side before returning them to the client - in fact you might have to
anyway since I don't think BigDecimal or java.sql.Time are supported
in the JRE emulation library. If you did that and you had a limited
number of possible queries that produced known order result sets, you
could write a separate method in your RPC service for each one
returning a purpose built (and typed) DTO.

However if you have zillions of possible query results and the
objects' number/type is indeterminate then i think you probably are in
territory explored in those links.

regards
gregor

sim123

unread,
Aug 13, 2008, 6:46:55 PM8/13/08
to Google Web Toolkit
Thanks for response, how about writing a custom serializer? Where can
I find some details (I am just starting with baby steps). So if I
write a custom field serializer would it be capable of handling
multiple types in a list (not bigdecimal/Time only supported types)?
Thanks

sim123

unread,
Aug 14, 2008, 2:03:24 AM8/14/08
to Google Web Toolkit
Hello Ian,

I tried implementing this Wrapper approach and getting an error at
compilation time "

public abstract java.util.List<com.test.TestList> getTestList(int
formID)
Return type: java.util.List<com.test.TestList>
java.util.List<com.test.TestList>
Checking type argument 0 of type
'java.util.List<E>' because it is directly exposed in this type or in
one of its subtypes
com.test.TestList
Analyzing the fields of type
'com.test.TestList' that qualify for serialization
private
java.util.List<com.test.Wrapper> testList

java.util.List<com.test.Wrapper>
Checking type argument 0
of type 'java.util.List<E>' because it is directly exposed in this
type or in one of its subtypes
com.test.Wrapper
[ERROR] Type
'com.test.Wrapper' was not serializable and has no concrete
serializable subtypes

My Wrapper class implements Serializable (or IsSerializable)
interface. Any suggestions?? I am more interested in writing custom
serializer because that could provide me better scalability (I think
so, please correct me) could you please suggest me how should I start
with that? Thanks for all the help and support.

On Aug 12, 3:39 pm, "Ian Petersen" <ispet...@gmail.com> wrote:

Ian Petersen

unread,
Aug 14, 2008, 10:15:11 AM8/14/08
to Google-We...@googlegroups.com
On Thu, Aug 14, 2008 at 2:03 AM, sim123 <sim...@gmail.com> wrote:
> My Wrapper class implements Serializable (or IsSerializable)
> interface. Any suggestions??

Could you post some of your code? I'm interested in TestList,
Wrapper, and an implementation of Wrapper. The error you're getting
is suspicious--I'm wondering if you've tickled a bug in the RPC
generator.

As a complete shot in the dark, try moving the Serializable
declaration from Wrapper to its implementations. In other words, if
you have this:

public interface Wrapper extends Serializable

public class Foo implements Wrapper

change it to this:

public interface Wrapper

public class Foo implements Wrapper, Serializable

It could be that the RPC generator isn't recognizing the transitive
serializability of implementations of Wrapper. Another, related, shot
in the dark is to change Wrapper from an interface to an abstract
class.

> I am more interested in writing custom
> serializer because that could provide me better scalability (I think
> so, please correct me) could you please suggest me how should I start
> with that? Thanks for all the help and support.

I think the scalability of custom serializers depends on how many you
have to write. If you only have to write a handful of custom
serializers to enable the use a great number of types, then yes, they
are scalable. On the other hand, if you have to write a custom
serializer for (nearly) every type, then I think you'll get tired of
writing custom serializers really fast.

Another issue is that custom serializers won't necessarily solve your
problem because they're "opaque" to the RPC generator. I just took a
look through the issue tracker and noticed that some RPC-related
changes have gone in that I didn't notice, so my understanding of the
RPC code may be out of date, but the following was true until
recently. The RPC generator effectively assumes that types serialized
by a custom serializer are composed of only primitives. You could
write a custom serializer for a type that is composed of a
List<Object> and have it call writeObject(o) for each o in the list,
but, unless the client-side deserialization stub for o's runtime type
is created by some other means, the client won't be able to
deserialize the stream. The typical solution to that problem is to
add some methods to your service interface such that each method's
return type corresponds to a type you need to be able to deserialize
on the client. This hack tricks the RPC generator into generating the
stubs you need, but it's really ugly.

Ian

sim123

unread,
Aug 14, 2008, 12:55:31 PM8/14/08
to Google Web Toolkit
Here is the code: Wrapper Interface
package com.test.client;

import java.io.Serializable;

public interface Wrapper extends Serializable {

public Object getValue();

}

Wapper Implementation:
package com.test.client;

import java.io.Serializable;


public class IntegerWrapper implements Wrapper {

public final Integer value;

public IntegerWrapper(Integer value){
this.value = value;
}
public Object getValue() {
return value;
}

}

TestList
package com.test.client;

import java.io.Serializable;
import java.util.List;

public class TestList implements Serializable{

private Integer id;
private List<Wrapper> testList = new ArrayList<Wrapper>();

public TestList() {}

public Integer getId() {
return this.id;
}

public void setId(Integer id) {
this.id = id;
}

public void setTestList(List<Wrapper> testList) {
this.testList = testList;
}

public List<Wrapper> getTestList() {
return testList;
}

}

When I implement Serializable on IntegerWrapper Exception is:
Caused by: com.google.gwt.user.client.rpc.SerializationException: Type
'com.test.client.IntegerWrapper' was not included in the set of types
which can be serialized by this SerializationPolicy or its Class
object could not be loaded. For security purposes, this type will not
be serialized.
at
com.google.gwt.user.server.rpc.impl.StandardSerializationPolicy.validateSerialize(StandardSerializationPolicy.java:
83)

>if you have to write a custom
>serializer for (nearly) every type, then I think you'll get tired of
>writing custom serializers really fast.

I am little confused here, as my problem is creating a generic
collection (for now basic java types would also do). why RPC can not
identify that my collection has java.lang.Boolean type as RPC supports
serialization and deserialization of Boolean values? So if I am
putting a custom type in my collection (like ArrayList) then I should
provide custom serializer (even in that case implementing
serialization should work) for that type and for java primitives or
for all implementation present in rpc.core.java package I would expect
RPC to do serialization for me, please suggest as I am no good than a
newbie. Thanks for your help and time.



On Aug 14, 7:15 am, "Ian Petersen" <ispet...@gmail.com> wrote:

Ian Petersen

unread,
Aug 14, 2008, 2:29:40 PM8/14/08
to Google-We...@googlegroups.com
On Thu, Aug 14, 2008 at 12:55 PM, sim123 <sim...@gmail.com> wrote:
> When I implement Serializable on IntegerWrapper Exception is:
> Caused by: com.google.gwt.user.client.rpc.SerializationException: Type
> 'com.test.client.IntegerWrapper' was not included in the set of types
> which can be serialized by this SerializationPolicy or its Class
> object could not be loaded. For security purposes, this type will not
> be serialized.
> at
> com.google.gwt.user.server.rpc.impl.StandardSerializationPolicy.validateSerialize(StandardSerializationPolicy.java:
> 83)

OK, I have the following, and it worked for me:

public interface Wrapper {

Object getValue();
}

public final class IntegerWrapper implements Wrapper, Serializable {

private Integer value;

private IntegerWrapper() {
}

public IntegerWrapper(Integer value) {
this.value = value;
}

public Object getValue() {
return value;
}
}

public interface Service extends RemoteService {

List<Wrapper> getListOfWrapper();
}

public interface ServiceAsync {

void getListOfWrapper(AsyncCallback<List<Wrapper>> callback);
}

public class ServiceImpl extends RemoteServiceServlet implements Service {

public List<Wrapper> getListOfWrapper() {
return new ArrayList(Arrays.asList(new IntegerWrapper(42)));
}
}


Maybe you need to add default constructors to your serializable
classes? I think that's the only major difference between your
non-working code and my working code.

>>if you have to write a custom
>>serializer for (nearly) every type, then I think you'll get tired of
>>writing custom serializers really fast.
>
> I am little confused here, as my problem is creating a generic
> collection (for now basic java types would also do). why RPC can not
> identify that my collection has java.lang.Boolean type as RPC supports
> serialization and deserialization of Boolean values?

There are two issues here.

Perhaps most importantly, you should understand that while RPC _may_
support serializing and deserializing java.lang.Boolean (or any other
arbitrary serializable reference type), it will only do so if the RPC
generator can statically determine that it _must_ support serializing
and deserializing java.lang.Boolean instances. The reason is
multi-faceted, but mostly it comes down to the fact that client-side
GWT doesn't support reflection so the ability to (de)serialize a type
must be encoded in purpose-written code that is included in the
download. Since code size is directly correlated with at least
download speed and sometimes also runtime speed, the RPC generator
does what it can to eliminate the (de)serialization stubs for types
that it determines will not be transmitted between client and
server--why pay for the ability to (de)serialize a java.lang.Boolean
if you never transmit java.lang.Boolean instances?

The second issue to understand is that the RPC generator runs at
compile time, not runtime, so it can only look at the information
present in your source code--it can't inspect any runtime type
information. In other words, it can't look at a List<Object> and see
that it does contain java.lang.Boolean instances but doesn't contain
java.lang.Double instances. The only information present in
List<Object> is that the List could be any known serializable
implementation of the List interface and the <Object> _could_ be _any_
serializable subtype of Object. You really don't want
(de)serialization stubs for _every_ serializable subtype of Object in
your client-side code, which is why a bare List<Object> causes a
compile-time problem. You can trick the generator, though, using the
technique I suggested in my previous post--you can force the RPC
generator to generate the stubs for any arbitrary type by including a
method declaration in the service interface that returns that
arbitrary type.

Did that do anything to help your confusion?

> So if I am
> putting a custom type in my collection (like ArrayList) then I should
> provide custom serializer (even in that case implementing
> serialization should work) for that type and for java primitives or
> for all implementation present in rpc.core.java package I would expect
> RPC to do serialization for me

I'm not 100% clear on your question here, but I think you wondering
why you have to implement a custom serializer for "standard" types.
You don't. You just have to worry about the generator discovering
that, say, java.lang.Boolean is a type that will be transmitted.

Suppose you have the following code:

public class TestList {

private List<Object> list;

// constructors, accessors, etc. not important, so long as there's a
default ctor
}

At first glance, this class is not serializable because the RPC
generator will complain about the List<Object>. You can shut the
generator up by writing a custom field serializer, like so:

public class TestList_CustomFieldSerializer {

public static void serialize(SerializationStreamWriter writer,
TestList instance) throws SerializationException {
writer.writeInt(instance.getList().size());

for (Obect o : instance.getList()) {
writer.writeObject(o);
}
}

public static void deserialize(SerializationStreamReader reader,
TestList instance) throws SerializationException {
int count = reader.readInt();

for (int i = 0; i < count; ++i) {
instance.getList().add(reader.readObject());
}
}
}

The problem now is that no one knows what kinds of objects are going
to be serialized by writeObject() or deserialized by readObject(). If
it so happens that the rest of your service method declarations cause
the RPC generator to generate client-side (de)serialization stubs for
all the types that might be in a TestList's list member, then the
above code will work fine. If, on the other hand, you have exactly
one service method, defined like this:

public interface Service extends RemoteService {

TestList getTestList();
}

then you're going to run into problems. I was about to explain how to
solve this problem by writing more code in the custom field
serializer, but a posting on the contributors forum taught me
something I didn't know. You could try this:

public class TestList {

private Integer exposeIntegerType;

private String exposeStringType;

// declare other, similar fields for all the types you need, but you
don't need to reference them anywhere

private transient List<Object> list;
}

If you use the above, extended definition of TestList, I'm told you
should be able to get away with the fairly simple
TestList_CustomFieldSerializer that I outlined above.

Sorry if this email seems a little disjointed--a GWT contributor
proved me wrong part way through writing it, so I had to edit it to
better reflect reality. I'll try to answer any further questions you
might have.

Ian

gregor

unread,
Aug 14, 2008, 2:54:19 PM8/14/08
to Google Web Toolkit
Yes, I've just found that out Ian.

I tried adding a spurious field of type IntegerWrapper to TestList and
it worked fine (once no-arg constructor added). I guess with the
wrappers you don't need a custom serializer, just one spurious field
for each type you need to pass across.

gregor

On Aug 14, 7:29 pm, "Ian Petersen" <ispet...@gmail.com> wrote:

sim123

unread,
Aug 14, 2008, 3:29:51 PM8/14/08
to Google Web Toolkit
Thank you so much for your reply Ian, and sorry for missing that no-
args constructor :(

I tried both approaches and its working. I am getting a warning
message from compiler that Object is not suitable type for GWT to
serialize etc.
I was insisting on writing custom serializer because if I create
Wrapper and its implementation I would traverse through the list of
Object (which I am getting from Server List<Object>) and construct a
new List<Wrapper> from it and I think that would be too expensive to
traverse the list two times (Once during fetching the data and once
before returning it to client) and I can't change the one which data
access layer is returning to me. second approach solved this problem
for now (could you please post the link of that post) except "private
transient List<Object> list" didn't work for me, I removed transient
and code is working. However I can not identify any cons of this
approach so if you could think of some please let me know. I am trying
to understand RPC and this post is really helpful, thanks for all your
help.

Ian Petersen

unread,
Aug 14, 2008, 5:10:27 PM8/14/08
to Google-We...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages