Help! Some confusing problems about gwt rpc with generics!

179 views
Skip to first unread message

Lan Andrew

unread,
Aug 28, 2011, 9:42:53 PM8/28/11
to Google Web Toolkit
I make a test about gwt rpc these days, and meet some confusing
problems.
At first, I created a project named testGwtRpc by the gwt plug-in.
Certainly,this is a
helloworld project,and it works fine.
Second,I made some changes for the project,especially adding the
generics on the rpc service
interface. Just like this below:
public interface GenericsRpcService<T,K> extends RemoteService{

T callServer(List<K> id);

T callServer(K id);
}

@RemoteServiceRelativePath("greet")
public interface RpcService extends GenericsRpcService<String,
String>{

}

Then ,some strange happened.In the client page, it failed when I
called the function T callServer(K id) ,but worked fine when calling T
callServer(List<K> id). The correspongding exception is as follows:
Starting Jetty on port 8888
[WARN] testServlet: An IncompatibleRemoteServiceException was
thrown while processing this call.
com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException:
java.lang.ClassNotFoundException: aaaaaa
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:315)
at
com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:
206)
at
com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:
248)
at
com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:
62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:
487)
at
org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:
362)
at
org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:
216)
at
org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:
181)
at
org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:
729)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:
405)
at
org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:
152)
at
org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:
49)
at
org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:
152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:
505)
at org.mortbay.jetty.HttpConnection
$RequestHandler.content(HttpConnection.java:843)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at
org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:
395)
at org.mortbay.thread.QueuedThreadPool
$PoolThread.run(QueuedThreadPool.java:488)
Caused by: com.google.gwt.user.client.rpc.SerializationException:
java.lang.ClassNotFoundException: aaaaaa
at
com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserialize(ServerSerializationStreamReader.java:
572)
at
com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamReader.readObject(AbstractSerializationStreamReader.java:
119)
at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader
$ValueReader$8.readValue(ServerSerializationStreamReader.java:137)
at
com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserializeValue(ServerSerializationStreamReader.java:
381)
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:303)
... 22 more
Caused by: java.lang.ClassNotFoundException: aaaaaa
at java.lang.ClassLoader.findClass(ClassLoader.java:359)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at
org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:
352)
at
org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:
337)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at
com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserialize(ServerSerializationStreamReader.java:
542)
... 26 more

Actually, I think it is because parameters would be compiled as
Object type when we used generics in the gwt rpc service interface. It
is undoubted that the Object type can't be serialized in the gwt rpc.
So the exception was threw. But after I tried the function T
callServer(List<K> id), I knew the problem was not so simple.
So, my questions are:
How does the gwt compiler work for the java generics in gwt rpc
service interface?
What differences are there between those two functions above?

Attached below is the testGwtRpc project.

Jeff Larsen

unread,
Aug 28, 2011, 10:25:02 PM8/28/11
to google-we...@googlegroups.com
Don't send List over rpc. The serializer has to take every impl of List and create a serialization policy for it. Try it with ArrayList and see what you get. 

Also, K has to be defined as something, preferably something as strongly typed as possible. And all instances of T and K must also be serializable. 

in short, creating a generic rpc service this way is going to be a nightmare. Check out the command pattern for solving this problem. Look into gwt-dispatch or gwtp also has a dispatching framework. . 

Alex Dobjanschi

unread,
Aug 29, 2011, 3:18:45 AM8/29/11
to google-we...@googlegroups.com
Are you sure you need a generic RemoteService? Like Jeff stated, RPC proxyCreator needs to ensure all subtypes of the types specified in your RemoteService need to be serialized (that way, server & client can communicate without problems). This will bloat the size of generated code. Moreover, having T & K can only reduce the code-size by 100 bytes or so, like this:

public interface GenericsRpcService<T,K> extends RemoteService{ 
  T callServer(List<K> id); 
  T callServer(K id); 


public interface UserRpcService extends GenericsRpcService<User, Long> {
  // Other (additional methods).
}

Notice the 2 methods from GenericsRpcService are already present in the subinterface. This is the only advantage you can get. Besides, you need a type literal for GWT.create so there's no way to call GWT.create (GenericRpcService<A, B>.class) (same goes with dependency injection -- you can't bind a generics interface).

Lan Andrew

unread,
Aug 30, 2011, 3:00:39 AM8/30/11
to Google Web Toolkit
Thank you very much,Jeff.

Yes,as you say, I shouldn't send List over rpc.
Another problem, what do you think about the exception above?
The generic parameter K would be still erased in the generated Proxy
implementing that interface,even though I bind the parameter type,such
as String, in the subinterface, which will be used in the app client
page. Right?
As the exception is threw when I call the second function T
callServer(K id), I am not sure whether it means the gwt rpc doesn't
support the generics? Or it is just a gwt rpc bug?

Lan Andrew

unread,
Aug 30, 2011, 3:10:30 AM8/30/11
to Google Web Toolkit
Thank you very much,Alex.

Yes,maybe I shouldn't send List over rpc and use generics in gwt rpc
like this way.
But I also have some problems about the exception above.
The generic parameter K would be still erased in the generated Proxy
implementing that interface,even though I bind the parameter type,such
as String, in the subinterface, which will be used in the app client
page. Right?
As it happens when I call the second function T callServer(K id), I am
not sure whether it means the gwt rpc doesn't support the generics?
Or it is just a bug?

Thanks again.

On 8月29日, 下午3时18分, Alex Dobjanschi <alex.dobjans...@gmail.com> wrote:
> Are you sure you need a generic RemoteService? Like Jeff stated, RPC
> proxyCreator needs to ensure all subtypes of the types specified in your
> RemoteService need to be serialized (that way, server & client can
> communicate without problems). This will bloat the size of generated code.
> Moreover, having T & K can only reduce the code-size by 100 bytes or so,
> like this:
>
> public interface GenericsRpcService<T,K> extends RemoteService{
>   T callServer(List<K> id);
>   T callServer(K id);
>
> }
>
> *public interface UserRpcService extends GenericsRpcService<User, Long> {*
> *  // Other (additional methods).*
> *}*
> *
> *
> Notice the 2 methods from GenericsRpcService are already present in the
> subinterface. This is the only advantage you can get. Besides, you need a
> type literal for *GWT.create *so there's no way to call *GWT.create
> (GenericRpcService<A, B>.class) *(same goes with dependency injection -- you

Paul Robinson

unread,
Aug 30, 2011, 7:00:12 AM8/30/11
to google-we...@googlegroups.com
http://code.google.com/p/google-web-toolkit/issues/detail?id=2374


On 30/08/11 08:10, Lan Andrew wrote:
> Thank you very much,Alex.
>
> Yes,maybe I shouldn't send List over rpc and use generics in gwt rpc
> like this way.
> But I also have some problems about the exception above.
> The generic parameter K would be still erased in the generated Proxy
> implementing that interface,even though I bind the parameter type,such
> as String, in the subinterface, which will be used in the app client
> page. Right?
> As it happens when I call the second function T callServer(K id), I am
> not sure whether it means the gwt rpc doesn't support the generics?
> Or it is just a bug?
>
> Thanks again.
>
> On 8月29日, 下午3时18分, Alex Dobjanschi<alex.dobjans...@gmail.com> wrote:
>> Are you sure you need a generic RemoteService? Like Jeff stated, RPC
>> proxyCreator needs to ensure all subtypes of the types specified in your

>> RemoteService need to be serialized (that way, server& client can


>> communicate without problems). This will bloat the size of generated code.

>> Moreover, having T& K can only reduce the code-size by 100 bytes or so,

Ali Jalal

unread,
Sep 7, 2011, 6:52:29 AM9/7/11
to google-we...@googlegroups.com
Hi Lan,

I encounter this problem in my services, for more info see: http://groups.google.com/group/google-web-toolkit/browse_thread/thread/64560785342d2dfd?hl=en

Test this:

If id type (K generic parameter) be a primitive-wrapper type (like Long or Integer) you will not get exception, but if K is an non-primitive-wrapper type (like String or Date) you will get that ClassNotFoundException; because gwt uses custom serialization mechanism for primitive (or their wrapper) types.

If K extends java.io.Serializable, problem exists because gwt do not know what is the real type of K to serialize/deserialize that (This is a bug in gwt compiler that will not throw an exception in compiling of such K). Gwt compile application and generates wrong *.gwt.rpc file for this service. When application is
running, in deserialization it reads wrong *.gwt.rpc file and reads id value (for example 'aaaaaa') instead of id type (for example 'java.lang.String') and throws ClassNotFoundException (because compiler does not know K real type and type of K has not been written in *.gwt.rpc file).

Solution:
For solving this problem you should re-write this generic method in 'RpcServiceAsync' and 'RpcService' interfaces and ovewrite this method in 'RpcServiceImpl' and call its super.

Note that, this method-overwriting should be done only for none-primitive-wrapper types (like String, Date, ...) and there is no need to be for primitive-wrapper types (not needed for Long, Integer, Short, ...).

Gook Luck.


--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsub...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.


Reply all
Reply to author
Forward
0 new messages