How to let this Map be transferred by GWT-RPC correctly?

2,422 views
Skip to first unread message

gong min

unread,
Aug 14, 2012, 11:07:28 AM8/14/12
to google-we...@googlegroups.com
I want to return a Map with 2 members to web client: One member is a list of Post, and the other is a Map of User. Of course, I can define a class with these 2 members, and it realy works. But I want to try a more general solution for GWT-RPC parameters/results transferring.
So far, I tried this solution on 2.5rc1. It works but with warning like below,anybody knows how to resolve it, or I really should forget this way to transfer objects between client and server if you know the reason.  Thanks.

[DEBUG] [ gwtLearning ] - Rebinding com.learn.client.GreetingService
 [DEBUG] [ gwtLearning ] - Invoking generator com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator
  [DEBUG] [ gwtLearning ] - Generating client proxy for remote service interface 'com.learn.client.GreetingService'
   [DEBUG] [ gwtLearning ] - Analyzing 'com.learn.client.GreetingService' for serializable types
    [DEBUG] [ gwtLearning ] - Analyzing methods:
     [DEBUG] [ gwtLearning ] - public abstract java.util.Map postWithUserServer() throws java.lang.IllegalArgumentException
      [DEBUG] [ gwtLearning ] - Return type: java.util.Map
       [DEBUG] [ gwtLearning ] - java.util.Map
        [DEBUG] [ gwtLearning ] - Verifying instantiability
         [DEBUG] [ gwtLearning ] - java.util.HashMap<? extends java.lang.Object, ? extends java.lang.Object>
          [WARN] [ gwtLearning ] - Checking all subtypes of Object which qualify for serialization
           [DEBUG] [ gwtLearning ] - com.google.gwt.validation.client.impl.PathImpl
            [DEBUG] [ gwtLearning ] - Verifying instantiability
             [DEBUG] [ gwtLearning ] - com.google.gwt.validation.client.impl.PathImpl
              [DEBUG] [ gwtLearning ] - Analyzing the fields of type 'com.google.gwt.validation.client.impl.PathImpl' that qualify for serialization
               [WARN] [ gwtLearning ] - Field 'private final java.util.List<javax.validation.Path.Node> nodes' will not be serialized because it is final
=============================================

public interface GreetingService extends RemoteService {
Map postWithUserServer() throws IllegalArgumentException;
}

public interface GreetingServiceAsync {
void postWithUserServer(AsyncCallback<Map> callback) 
throws IllegalArgumentException;
}

public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {
@Override
public Map postWithUserServer() throws IllegalArgumentException {
List<Post> lPost=Arrays.asList(new Post(2),new Post(3),new Post(4),new Post(5),new Post(6),new Post(7)
,new Post(8),new Post(9),new Post(10),new Post(11),new Post(12),new Post(13));
Map<Integer,User> mUser=new TreeMap<Integer,User>();
mUser.put(1, new User(1));
mUser.put(2, new User(2));
mUser.put(3, new User(3));
Map mResult = new TreeMap();
mResult.put("posts", lPost);
mResult.put("users", mUser);
return mResult;
}
}

public class GwtImage implements EntryPoint {

private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);

public void onModuleLoad() {

final CellList<String> clPostWithUser = new CellList<String>(new TextCell());
Button btnShowPostWithUser = new Button("Show Post With User",new ClickHandler(){
@Override
public void onClick(ClickEvent event) {
greetingService.postWithUserServer(new AsyncCallback<Map>(){
@Override
public void onFailure(Throwable caught) {
Window.alert("get result failed!");
}

@Override
public void onSuccess(Map mResult) {
List<Post> lShowPosts =(List<Post>) mResult.get("posts");
Map<Integer,User> mShowUsers = (TreeMap<Integer,User>) mResult.get("users");
List<String> lShowResult = new ArrayList<String>();
User uShow;
for(Post pShow:lShowPosts){
uShow=mShowUsers.get(pShow.pid%3+1);
lShowResult.add(pShow.pid+":"+pShow.title+":"+pShow.body+" from " + uShow.uid +"/" + uShow.name + "/" + uShow.nickName);
}
clPostWithUser.setRowData(lShowResult);
}
});
}
});
RootPanel.get().add(btnShowPostWithUser);
RootPanel.get().add(clPostWithUser);
}
}

public class User implements Serializable{
private static final long serialVersionUID = 1L;
public int uid;
public String name;
public String nickName;
public User(){}
public User(int i){
uid=i;
name="name "+String.valueOf(i);
nickName="nickName "+String.valueOf(i);
}
}

public class Post implements Serializable{
private static final long serialVersionUID = 1L;
public int pid;
public String title;
public String body;
public Post() {}
public Post(int i) {
pid=i;
title="title "+String.valueOf(i);
body="body "+String.valueOf(i);
}
}

--
Gong Min

Jens

unread,
Aug 14, 2012, 12:15:10 PM8/14/12
to google-we...@googlegroups.com
I guess the reason is that you return a raw Map. A raw Map means Map<? extends Object, ? extends Object> and GWT now has to check all possible sub classes of Object (= all classes) to see if they can be safely serialized. GWT then finds the serializable class PathImpl on the classpath and complaints about a final List variable inside that class (GWT-RPC can't serialize final fields yet I think). 
Also because you have used Map/List GWT has to generate JavaScript code to support serializing all implementation classes of Map/List even if you never use them.

When you use GWT-RPC there is a rule very different from what you know from Java: Be as explicit as possible (as long as it makes sense) while defining your GWT-RPC methods. So instead of a raw Map use a parametrized HashMap or TreeMap. In your example its probably best to create a DTO class, e.g.

class MyResult implements Serializable {
  ArrayList<Post> posts;
  TreeMap<Integer, User> users;
}

Now GWT will only validate MyResult, ArrayList, TreeMap, Integer, Post and User instead of every class on the classpath and the warning should disappear. Also only JS serialization code for ArrayList and TreeMap will be generated instead of code for all List and Map implementations. Being explicit only counts on GWT-RPC, so for everything else in your app you should use Map/List/Set.

If your app grows and you plan to have RPC methods with all kinds of List/Map/Set implementations then you can of course use the Map/List/Set interface (because then you need serialization code for every implementation anyways) but you should still parametrize them.

-- J.

gong min

unread,
Aug 14, 2012, 6:59:21 PM8/14/12
to google-we...@googlegroups.com
Thanks. I will follow the DTO way. It seems more safe for coding.

2012/8/15 Jens <jens.ne...@gmail.com>

-- J.

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



--
Gong Min
Reply all
Reply to author
Forward
0 new messages