Revision: 9417
Author: b...@google.com
Date: Tue Dec 14 07:37:53 2010
Log: Integrate r9414 into GWT 2.1 branch.
Ensure that primitive values can be used as RequestFactory proxy properties.

http://code.google.com/p/google-web-toolkit/source/detail?r=9417

Added:
/releases/2.1/user/test/com/google/gwt/requestfactory/server/BoxesAndPrimitivesJreTest.java /releases/2.1/user/test/com/google/gwt/requestfactory/shared/BoxesAndPrimitivesTest.java
Modified:
/releases/2.1/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java /releases/2.1/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java /releases/2.1/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java /releases/2.1/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
 /releases/2.1/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
/releases/2.1/user/test/com/google/gwt/requestfactory/shared/BaseFooProxy.java

=======================================
--- /dev/null
+++ /releases/2.1/user/test/com/google/gwt/requestfactory/server/BoxesAndPrimitivesJreTest.java Tue Dec 14 07:37:53 2010
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.server;
+
+import com.google.gwt.dev.asm.Type;
+import com.google.gwt.dev.asm.commons.Method;
+import com.google.gwt.requestfactory.server.RequestFactoryInterfaceValidatorTest.VisibleErrorContext;
+import com.google.gwt.requestfactory.shared.BoxesAndPrimitivesTest;
+import com.google.gwt.requestfactory.shared.EntityProxy;
+import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.requestfactory.shared.Request;
+import com.google.gwt.requestfactory.shared.RequestContext;
+import com.google.gwt.requestfactory.shared.Service;
+
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+/**
+ * A JRE version of {...@link BoxesAndPrimitivesTest} with additional validation
+ * tests.
+ */
+public class BoxesAndPrimitivesJreTest extends BoxesAndPrimitivesTest {
+
+  @Service(ServiceImpl.class)
+  interface ContextMismatchedParameterA extends RequestContext {
+    Request<Void> checkBoxed(int value);
+  }
+
+  @Service(ServiceImpl.class)
+  interface ContextMismatchedParameterB extends RequestContext {
+    Request<Void> checkPrimitive(Integer value);
+  }
+
+  @ProxyFor(Entity.class)
+  interface ProxyMismatchedGetterA extends EntityProxy {
+    int getBoxed();
+  }
+
+  @ProxyFor(Entity.class)
+  interface ProxyMismatchedGetterB extends EntityProxy {
+    Integer getPrimitive();
+  }
+
+  private VisibleErrorContext errors;
+  private RequestFactoryInterfaceValidator v;
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+  public void test() {
+ RequestFactoryInterfaceValidator v = new RequestFactoryInterfaceValidator(
+        Logger.getAnonymousLogger(),
+        new RequestFactoryInterfaceValidator.ClassLoaderLoader(
+            getClass().getClassLoader()));
+    v.validateRequestFactory(Factory.class.getName());
+    assertFalse(v.isPoisoned());
+  }
+
+  /**
+   * Tests that mismatched primitive verses boxed getters are correctly
+   * reported.
+   */
+  public void testMismatchedGetters() {
+    v.validateEntityProxy(ProxyMismatchedGetterA.class.getName());
+    v.validateEntityProxy(ProxyMismatchedGetterB.class.getName());
+    assertTrue(v.isPoisoned());
+
+ String getBoxedMessage = RequestFactoryInterfaceValidator.messageCouldNotFindMethod(
+        Type.getType(Entity.class),
+        Arrays.asList(new Method("getBoxed", "()Ljava/lang/Integer;")));
+ String getPrimitiveMessage = RequestFactoryInterfaceValidator.messageCouldNotFindMethod(
+        Type.getType(Entity.class),
+        Arrays.asList(new Method("getPrimitive", "()I")));
+    assertEquals(Arrays.asList(getBoxedMessage, getPrimitiveMessage),
+        errors.logs);
+  }
+
+  /**
+   * Tests that mismatched parameter types are correctly reported.
+   */
+  public void testMismatchedParameters() {
+    v.validateRequestContext(ContextMismatchedParameterA.class.getName());
+    v.validateRequestContext(ContextMismatchedParameterB.class.getName());
+
+ String checkBoxedMessage = RequestFactoryInterfaceValidator.messageCouldNotFindMethod(
+        Type.getType(ServiceImpl.class),
+        Arrays.asList(new Method("checkBoxed", "(Ljava/lang/Integer;)V")));
+ String checkPrimitiveMessage = RequestFactoryInterfaceValidator.messageCouldNotFindMethod(
+        Type.getType(ServiceImpl.class),
+        Arrays.asList(new Method("checkPrimitive", "(I)V")));
+    assertEquals(Arrays.asList(checkBoxedMessage, checkPrimitiveMessage),
+        errors.logs);
+  }
+
+  @Override
+  protected Factory createFactory() {
+    return RequestFactoryJreTest.createInProcess(Factory.class);
+  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    super.gwtSetUp();
+    errors = new VisibleErrorContext(Logger.getAnonymousLogger());
+    v = new RequestFactoryInterfaceValidator(errors,
+        new RequestFactoryInterfaceValidator.ClassLoaderLoader(
+            getClass().getClassLoader()));
+  }
+}
=======================================
--- /dev/null
+++ /releases/2.1/user/test/com/google/gwt/requestfactory/shared/BoxesAndPrimitivesTest.java Tue Dec 14 07:37:53 2010
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.shared;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.SimpleEventBus;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Contains a set of checks of how primitive and boxed method declarations
+ * interact.
+ */
+public class BoxesAndPrimitivesTest extends GWTTestCase {
+
+  /**
+   * The domain type.
+   */
+  protected static class Entity {
+    static final Entity SINGLETON = new Entity();
+
+    public static Entity findEntity(int id) {
+      return SINGLETON;
+    }
+
+    public Integer getBoxed() {
+      return EXPECTED_BOXED;
+    }
+
+    public int getId() {
+      return 0;
+    }
+
+    public int getPrimitive() {
+      return EXPECTED;
+    }
+
+    public int getVersion() {
+      return 0;
+    }
+
+    public void setBoxed(Integer value) {
+      assertEquals(EXPECTED_BOXED, value);
+    }
+
+    public void setPrimitive(int value) {
+      assertEquals(EXPECTED, value);
+    }
+  }
+
+  /**
+   * The RequestFactory.
+   */
+  protected interface Factory extends RequestFactory {
+    Context context();
+  }
+
+  /**
+   * The service method implementations.
+   */
+  protected static class ServiceImpl {
+    public static void checkBoxed(Integer value) {
+      assertEquals(EXPECTED_BOXED, value);
+    }
+
+    public static void checkPrimitive(int value) {
+      assertEquals(EXPECTED, value);
+    }
+
+    public static Integer getBoxed() {
+      return EXPECTED_BOXED;
+    }
+
+    public static Entity getEntity() {
+      return Entity.SINGLETON;
+    }
+
+    public static int getPrimitive() {
+      return EXPECTED;
+    }
+  }
+
+  @Service(ServiceImpl.class)
+  interface Context extends RequestContext {
+    Request<Void> checkBoxed(Integer value);
+
+    Request<Void> checkPrimitive(int value);
+
+    Request<Integer> getBoxed();
+
+    Request<Proxy> getEntity();
+
+    Request<Integer> getPrimitive();
+  }
+
+  @ProxyFor(Entity.class)
+  interface Proxy extends EntityProxy {
+    Integer getBoxed();
+
+    int getPrimitive();
+
+    void setBoxed(Integer value);
+
+    void setPrimitive(int value);
+  }
+
+  static abstract class TestReceiver<T> extends Receiver<T> {
+    @Override
+    public void onFailure(ServerFailure error) {
+      fail(error.getMessage());
+    }
+  }
+
+  private static final int EXPECTED = 42;
+  private static final Integer EXPECTED_BOXED = Integer.valueOf(EXPECTED);
+  private static final int TEST_DELAY = 5000;
+
+  private Factory factory;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.requestfactory.RequestFactorySuite";
+  }
+
+  /**
+ * Tests that domain service methods that return a primitive type are upcast + * to the boxed type that the generic declaration requires. Also checks that
+   * primitive and boxed property types can be retrieved and that boxed and
+   * primitive method arguments work.
+   */
+  public void testReturnAndParamTypes() {
+    delayTestFinish(TEST_DELAY);
+    Context ctx = context();
+    // Boxed service method
+    ctx.getBoxed().to(new TestReceiver<Integer>() {
+      @Override
+      public void onSuccess(Integer response) {
+        assertEquals(EXPECTED_BOXED, response);
+      }
+    });
+    // Primitive service method
+    ctx.getPrimitive().to(new TestReceiver<Integer>() {
+      @Override
+      public void onSuccess(Integer response) {
+        assertEquals(EXPECTED_BOXED, response);
+      }
+    });
+    // Boxed and primitive properties
+    ctx.getEntity().to(new TestReceiver<Proxy>() {
+      @Override
+      public void onSuccess(Proxy response) {
+        assertEquals(EXPECTED_BOXED, response.getBoxed());
+        assertEquals(EXPECTED, response.getPrimitive());
+      }
+    });
+    // Boxed service argument
+    ctx.checkBoxed(EXPECTED_BOXED).to(new TestReceiver<Void>() {
+      @Override
+      public void onSuccess(Void response) {
+        // OK
+      }
+    });
+    // Primitive service argument
+    ctx.checkPrimitive(EXPECTED).to(new TestReceiver<Void>() {
+      @Override
+      public void onSuccess(Void response) {
+        // OK
+      }
+    });
+    ctx.fire(new TestReceiver<Void>() {
+      @Override
+      public void onSuccess(Void response) {
+        finishTest();
+      }
+    });
+  }
+
+  protected Factory createFactory() {
+    Factory toReturn = GWT.create(Factory.class);
+    toReturn.initialize(new SimpleEventBus());
+    return toReturn;
+  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    factory = createFactory();
+  }
+
+  private Context context() {
+    return factory.context();
+  }
+}
=======================================
--- /releases/2.1/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java Tue Dec 7 20:02:07 2010 +++ /releases/2.1/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java Tue Dec 14 07:37:53 2010
@@ -148,7 +148,7 @@
       this.parent = parent;
       this.validator = parent.validator;
     }
-
+
     public void poison(String msg, Object... args) {
       poison();
       logger.logp(Level.SEVERE, currentType(), currentMethod(),
@@ -173,7 +173,7 @@
       toReturn.currentType = type;
       return toReturn;
     }
-
+
     public void spam(String msg, Object... args) {
       logger.logp(Level.FINEST, currentType(), currentMethod(),
           String.format(msg, args));
@@ -309,7 +309,7 @@
             } else {
               return;
             }
-
+
             /*
              * The input is a source name, so we need to convert it to an
* internal name. We'll do this by substituting dollar signs for the
@@ -554,6 +554,18 @@
     validator.validateRequestFactory(args[0]);
     System.exit(validator.isPoisoned() ? 1 : 0);
   }
+
+  static String messageCouldNotFindMethod(Type domainType,
+      List<? extends Method> methods) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(String.format(
+        "Could not find matching method in %s.\nPossible matches:\n",
+        print(domainType)));
+    for (Method domainMethod : methods) {
+      sb.append("  ").append(print(domainMethod)).append("\n");
+    }
+    return sb.toString();
+  }

   private static String print(Method method) {
     StringBuilder sb = new StringBuilder();
@@ -632,6 +644,7 @@
    * A map of a type to all types that it could be assigned to.
    */
private final Map<Type, List<Type>> supertypes = new HashMap<Type, List<Type>>();
+
   /**
    * The type {...@link ValueProxy}.
    */
@@ -646,7 +659,7 @@
    * Contains vaue types (e.g. Integer).
    */
   private final Set<Type> valueTypes = new HashSet<Type>();
-
+
   /**
    * Maps a domain object to the type returned from its getId method.
    */
@@ -657,13 +670,13 @@
       valueTypes.add(Type.getType(clazz));
     }
   }
-
+
   public RequestFactoryInterfaceValidator(Logger logger, Loader loader) {
     this.parentLogger = new ErrorContext(logger);
     parentLogger.setValidator(this);
     this.loader = loader;
   }
-
+
   /**
    * Visible for testing.
    */
@@ -790,7 +803,8 @@

for (RFMethod method : getMethodsInHierarchy(logger, requestContextType)) {
       // Ignore methods in RequestContext itself
- if (findCompatibleMethod(logger, requestContextIntf, method, false, true) != null) { + if (findCompatibleMethod(logger, requestContextIntf, method, false, true,
+          true) != null) {
         continue;
       }

@@ -961,7 +975,8 @@
Method searchFor = createDomainMethod(logger, new Method(method.getName(),
         returnType, method.getArgumentTypes()));

- RFMethod found = findCompatibleMethod(logger, domainServiceType, searchFor);
+    RFMethod found = findCompatibleServiceMethod(logger, domainServiceType,
+        searchFor);

     if (found != null) {
       boolean isInstance = isAssignable(logger, instanceRequestIntf,
@@ -1048,7 +1063,7 @@
       Method clientPropertyMethod, Type domainType) {
     logger = logger.setMethod(clientPropertyMethod);

-    findCompatibleMethod(logger, domainType,
+    findCompatiblePropertyMethod(logger, domainType,
         createDomainMethod(logger, clientPropertyMethod));
   }

@@ -1102,15 +1117,6 @@
     }
     return false;
   }
-
-  /**
-   * Finds a compatible method declaration in <code>domainType</code>'s
-   * hierarchy that is assignment-compatible with the given Method.
-   */
-  private RFMethod findCompatibleMethod(final ErrorContext logger,
-      Type domainType, Method searchFor) {
- return findCompatibleMethod(logger, domainType, searchFor, true, false);
-  }

   /**
    * Finds a compatible method declaration in <code>domainType</code>'s
@@ -1118,10 +1124,13 @@
    */
   private RFMethod findCompatibleMethod(final ErrorContext logger,
       Type domainType, Method searchFor, boolean mustFind,
-      boolean allowOverloads) {
+      boolean allowOverloads, boolean boxReturnTypes) {
     String methodName = searchFor.getName();
     Type[] clientArgs = searchFor.getArgumentTypes();
     Type clientReturnType = searchFor.getReturnType();
+    if (boxReturnTypes) {
+      clientReturnType = maybeBoxType(clientReturnType);
+    }
     // Pull all methods out of the domain type
Map<String, List<RFMethod>> domainLookup = new LinkedHashMap<String, List<RFMethod>>();
     for (RFMethod method : getMethodsInHierarchy(logger, domainType)) {
@@ -1155,12 +1164,16 @@

     // Check each overloaded name
     for (RFMethod domainMethod : methods) {
-      // Box any primitive types to simplify compotibility check
       Type[] domainArgs = domainMethod.getArgumentTypes();
-      for (int i = 0, j = domainArgs.length; i < j; i++) {
-        domainArgs[i] = maybeBoxType(domainArgs[i]);
-      }
-      Type domainReturnType = maybeBoxType(domainMethod.getReturnType());
+      Type domainReturnType = domainMethod.getReturnType();
+      if (boxReturnTypes) {
+        /*
+ * When looking for the implementation of a Request<Integer>, we want to + * match either int or Integer, so we'll box the domain method's return
+         * type.
+         */
+        domainReturnType = maybeBoxType(domainReturnType);
+      }

       /*
* Make sure the client args can be passed into the domain args and the
@@ -1175,17 +1188,30 @@
       }
     }
     if (mustFind) {
-      StringBuilder sb = new StringBuilder();
-      sb.append(String.format(
-          "Could not find matching method in %s:\nPossible matches:\n",
-          print(domainType)));
-      for (RFMethod domainMethod : methods) {
-        sb.append("  ").append(print(domainMethod)).append("\n");
-      }
-      logger.poison(sb.toString());
+      logger.poison(messageCouldNotFindMethod(domainType, methods));
     }
     return null;
   }
+
+  /**
+   * Finds a compatible method declaration in <code>domainType</code>'s
+   * hierarchy that is assignment-compatible with the given Method.
+   */
+  private RFMethod findCompatiblePropertyMethod(final ErrorContext logger,
+      Type domainType, Method searchFor) {
+    return findCompatibleMethod(logger, domainType, searchFor, true, false,
+        false);
+  }
+
+  /**
+   * Finds a compatible method declaration in <code>domainType</code>'s
+   * hierarchy that is assignment-compatible with the given Method.
+   */
+  private RFMethod findCompatibleServiceMethod(final ErrorContext logger,
+      Type domainType, Method searchFor) {
+    return findCompatibleMethod(logger, domainType, searchFor, true, false,
+        true);
+  }

   /**
* This looks like it should be a utility method somewhere else, but I can't
@@ -1340,14 +1366,6 @@
     if (possibleSupertype.equals(possibleSubtype)) {
       return true;
     }
-
-    // Box primitive types to make this simple
-    if (possibleSupertype.getSort() != Type.OBJECT) {
-      possibleSupertype = getBoxedType(possibleSupertype);
-    }
-    if (possibleSubtype.getSort() != Type.OBJECT) {
-      possibleSubtype = getBoxedType(possibleSubtype);
-    }

     // Supertype calculation is cached
     List<Type> allSupertypes = getSupertypes(logger, possibleSubtype);
@@ -1368,7 +1386,8 @@
     return true;
   }

- private boolean isCollectionType(@SuppressWarnings("unused") ErrorContext logger, Type type) {
+  private boolean isCollectionType(
+      @SuppressWarnings("unused") ErrorContext logger, Type type) {
// keeping the logger arg just for internal consistency for our small minds
     return "java/util/List".equals(type.getInternalName())
         || "java/util/Set".equals(type.getInternalName());
=======================================
--- /releases/2.1/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java Wed Dec 8 12:52:04 2010 +++ /releases/2.1/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java Tue Dec 14 07:37:53 2010
@@ -186,7 +186,7 @@
     processOperationMessages(state, message);
     List<Object> decoded = decodeInvocationArguments(state,
         message.getInvocations().get(0).getParameters(),
-        new Class<?>[]{proxyType}, new Type[]{domainClass});
+        new Class<?>[] {proxyType}, new Type[] {domainClass});

     @SuppressWarnings("unchecked")
     List<T> toReturn = (List<T>) decoded;
@@ -234,7 +234,8 @@

   private AutoBean<ServerFailureMessage> createFailureMessage(
       ReportableException e) {
- ServerFailure failure = exceptionHandler.createServerFailure(e.getCause()); + ServerFailure failure = exceptionHandler.createServerFailure(e.getCause() == null
+        ? e : e.getCause());
     AutoBean<ServerFailureMessage> bean = FACTORY.failure();
     ServerFailureMessage msg = bean.as();
     msg.setExceptionType(failure.getExceptionType());
=======================================
--- /releases/2.1/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java Tue Nov 30 10:36:06 2010 +++ /releases/2.1/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java Tue Dec 14 07:37:53 2010
@@ -16,6 +16,7 @@
 package com.google.gwt.requestfactory;

 import com.google.gwt.requestfactory.rebind.model.RequestFactoryModelTest;
+import com.google.gwt.requestfactory.server.BoxesAndPrimitivesJreTest;
 import com.google.gwt.requestfactory.server.ComplexKeysJreTest;
 import com.google.gwt.requestfactory.server.FindServiceJreTest;
 import com.google.gwt.requestfactory.server.LocatorJreTest;
@@ -34,6 +35,7 @@
   public static Test suite() {
     TestSuite suite = new TestSuite(
         "requestfactory package tests that require the JRE");
+    suite.addTestSuite(BoxesAndPrimitivesJreTest.class);
     suite.addTestSuite(ComplexKeysJreTest.class);
     suite.addTestSuite(FindServiceJreTest.class);
     suite.addTestSuite(LocatorJreTest.class);
=======================================
--- /releases/2.1/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java Tue Nov 30 10:36:06 2010 +++ /releases/2.1/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java Tue Dec 14 07:37:53 2010
@@ -22,6 +22,7 @@
 import com.google.gwt.requestfactory.client.RequestFactoryTest;
import com.google.gwt.requestfactory.client.RequestFactoryUnicodeEscapingTest;
 import com.google.gwt.requestfactory.client.ui.EditorTest;
+import com.google.gwt.requestfactory.shared.BoxesAndPrimitivesTest;
 import com.google.gwt.requestfactory.shared.ComplexKeysTest;
 import com.google.gwt.requestfactory.shared.LocatorTest;

@@ -34,6 +35,7 @@
   public static Test suite() {
     GWTTestSuite suite = new GWTTestSuite(
         "Test suite for requestfactory gwt code.");
+    suite.addTestSuite(BoxesAndPrimitivesTest.class);
     suite.addTestSuite(ComplexKeysTest.class);
     suite.addTestSuite(EditorTest.class);
     suite.addTestSuite(FindServiceTest.class);
=======================================
--- /releases/2.1/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java Wed Dec 8 12:52:04 2010 +++ /releases/2.1/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java Tue Dec 14 07:37:53 2010
@@ -783,7 +783,7 @@
     this.simpleValueField = simpleValueField.get(0);
   }

-  public void setUnpersisted(Boolean unpersisted) {
+  public void setUnpersisted(boolean unpersisted) {
     this.unpersisted = unpersisted;
   }

=======================================
--- /releases/2.1/user/test/com/google/gwt/requestfactory/shared/BaseFooProxy.java Tue Nov 30 11:49:09 2010 +++ /releases/2.1/user/test/com/google/gwt/requestfactory/shared/BaseFooProxy.java Tue Dec 14 07:37:53 2010
@@ -75,7 +75,7 @@

   List<SimpleValueProxy> getSimpleValues();

-  Boolean getUnpersisted();
+  boolean getUnpersisted();

   String getUserName();

@@ -127,7 +127,7 @@

   void setSimpleValues(List<SimpleValueProxy> value);

-  void setUnpersisted(Boolean unpersisted);
+  void setUnpersisted(boolean unpersisted);

   void setUserName(String userName);
 }

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to