Fixes issue 1097; added a unit test for this case. The code will now validate the interface in the aggregate. Minor doc fix for ReachableTypeOracleBuilder.
Patch by: mmendez
Review by: scottb (desk check)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1133 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/rebind/rpc/RemoteServiceAsyncValidator.java b/user/src/com/google/gwt/user/rebind/rpc/RemoteServiceAsyncValidator.java
index 26bc4bc..bb46011 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/RemoteServiceAsyncValidator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/RemoteServiceAsyncValidator.java
@@ -17,18 +17,18 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPackage;
import com.google.gwt.core.ext.typeinfo.JParameter;
-import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
-import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.client.rpc.AsyncCallback;
+import java.util.Map;
+import java.util.TreeMap;
+
/**
* Validates the asynchronous version of
* {@link com.google.gwt.user.client.rpc.RemoteService RemoteService} interface.
@@ -48,7 +48,7 @@
sb.append(serviceIntf.getSimpleSourceName());
sb.append("Async {\n");
- JMethod[] methods = serviceIntf.getMethods();
+ JMethod[] methods = serviceIntf.getOverridableMethods();
for (int index = 0; index < methods.length; ++index) {
JMethod method = methods[index];
assert (method != null);
@@ -82,8 +82,8 @@
return sb.toString();
}
- private final JClassType asyncCallbackClass;
+ private final JClassType asyncCallbackClass;
private final TypeOracle typeOracle;
RemoteServiceAsyncValidator(TypeOracle typeOracle) throws NotFoundException {
@@ -91,49 +91,58 @@
asyncCallbackClass = typeOracle.getType(AsyncCallback.class.getName());
}
+ /**
+ * Checks that for there is an asynchronous
+ * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService}
+ * interface and that it has an asynchronous version of every synchronous
+ * method.
+ *
+ * @throws UnableToCompleteException if the asynchronous
+ * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService}
+ * was not found, or if it does not have an asynchronous method
+ * version of every synchronous one
+ */
public void validateRemoteServiceAsync(TreeLogger logger,
JClassType remoteService) throws UnableToCompleteException {
- logger = logger.branch(TreeLogger.DEBUG,
+ TreeLogger branch = logger.branch(TreeLogger.DEBUG,
"Checking the synchronous interface '"
+ remoteService.getQualifiedSourceName()
+ "' against its asynchronous version '"
+ remoteService.getQualifiedSourceName() + "Async'", null);
-
- JClassType remoteServiceAsync = typeOracle.findType(remoteService.getQualifiedSourceName()
- + "Async");
boolean failed = false;
- if (remoteServiceAsync == null) {
- logger.branch(TreeLogger.ERROR,
+ JClassType serviceAsync = typeOracle.findType(remoteService.getQualifiedSourceName()
+ + "Async");
+ if (serviceAsync == null) {
+ failed = true;
+ branch.branch(TreeLogger.ERROR,
"Could not find an asynchronous version for the service interface "
+ remoteService.getQualifiedSourceName(), null);
- failed = true;
} else {
+ JMethod[] asyncMethods = serviceAsync.getOverridableMethods();
JMethod[] syncMethods = remoteService.getOverridableMethods();
- JMethod[] asyncMethods = remoteServiceAsync.getOverridableMethods();
- if (syncMethods.length != asyncMethods.length) {
- logger.branch(TreeLogger.ERROR, "The asynchronous version of "
+ if (asyncMethods.length != syncMethods.length) {
+ branch.branch(TreeLogger.ERROR, "The asynchronous version of "
+ remoteService.getQualifiedSourceName() + " has "
+ (asyncMethods.length > syncMethods.length ? "more" : "less")
+ " methods than the synchronous version", null);
failed = true;
} else {
+ Map asyncMethodMap = initializeAsyncMethodMap(asyncMethods);
for (int i = 0; i < syncMethods.length; ++i) {
- JMethod method = syncMethods[i];
-
- JMethod asyncMethod = remoteServiceAsync.findMethod(method.getName(),
- getAsyncParamTypes(method));
-
+ JMethod syncMethod = syncMethods[i];
+ String asyncSig = computeAsyncMethodSignature(syncMethod);
+ JMethod asyncMethod = (JMethod) asyncMethodMap.get(asyncSig);
if (asyncMethod == null) {
- logger.branch(TreeLogger.ERROR,
+ branch.branch(TreeLogger.ERROR,
"Missing asynchronous version of the synchronous method '"
- + method.getReadableDeclaration() + "'", null);
+ + syncMethod.getReadableDeclaration() + "'", null);
failed = true;
} else if (asyncMethod.getReturnType() != JPrimitiveType.VOID) {
- logger.branch(TreeLogger.ERROR,
+ branch.branch(TreeLogger.ERROR,
"The asynchronous version of the synchronous method '"
- + method.getReadableDeclaration()
- + "' must have a void return type", null);
+ + syncMethod.getReadableDeclaration()
+ + "' must have a 'void' return type", null);
failed = true;
}
}
@@ -141,44 +150,48 @@
}
if (failed) {
- logValidAsyncInterfaceDeclaration(logger, remoteService);
+ logValidAsyncInterfaceDeclaration(branch, remoteService);
throw new UnableToCompleteException();
}
}
- private JType[] getAsyncParamTypes(JMethod method) {
- JParameter[] params = method.getParameters();
- JType[] asyncParamTypes = new JType[params.length + 1];
-
- for (int index = 0; index < params.length; ++index) {
- asyncParamTypes[index] = getRawType(params[index].getType());
- }
-
- asyncParamTypes[params.length] = asyncCallbackClass;
-
- return asyncParamTypes;
+ private String computeAsyncMethodSignature(JMethod syncMethod) {
+ return computeInternalSignature(syncMethod) + "/"
+ + asyncCallbackClass.getQualifiedSourceName();
}
- private JType getRawType(JType type) {
- JParameterizedType parameterized = type.isParameterized();
- if (parameterized != null) {
- return getRawType(parameterized.getRawType());
+ private String computeInternalSignature(JMethod method) {
+ StringBuffer sb = new StringBuffer();
+ sb.setLength(0);
+ sb.append(method.getName());
+ JParameter[] params = method.getParameters();
+ for (int j = 0; j < params.length; j++) {
+ JParameter param = params[j];
+ sb.append("/");
+ sb.append(param.getType().getQualifiedSourceName());
}
+ return sb.toString();
+ }
- JArrayType arrayType = type.isArray();
- if (arrayType != null) {
- return typeOracle.getArrayType(getRawType(arrayType.getComponentType()));
+ /**
+ * Builds a map of asynchronous method internal signatures to the
+ * corresponding asynchronous {@link JMethod}.
+ */
+ private Map initializeAsyncMethodMap(JMethod[] asyncMethods) {
+ Map /* <String,JClassType> */sigs = new TreeMap();
+ for (int i = 0; i < asyncMethods.length; ++i) {
+ JMethod asyncMethod = asyncMethods[i];
+ sigs.put(computeInternalSignature(asyncMethod), asyncMethod);
}
-
- return type;
+ return sigs;
}
private void logValidAsyncInterfaceDeclaration(TreeLogger logger,
JClassType remoteService) {
- logger = logger.branch(TreeLogger.INFO,
- "A valid definition for an asynchronous version of interface '"
+ TreeLogger branch = logger.branch(TreeLogger.INFO,
+ "A valid definition for the asynchronous version of interface '"
+ remoteService.getQualifiedSourceName() + "' would be:\n", null);
- logger.log(TreeLogger.ERROR,
+ branch.log(TreeLogger.ERROR,
synthesizeAsynchronousInterfaceDefinition(remoteService), null);
}
}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
index d84af23..fa01c3e 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -72,11 +72,6 @@
* <li>Is not default instantiable</li>
* <li>Has a non-static, non-transient, non-final field whose type is not
* serializable</li>
- * <li>Has native methods</li>
- * <li>Has a reachable subtype that is not automatically serializable, this
- * error can be treated as a warning if the
- * gwt.allowUnserializableSubtypesOfAutoSerializableTypes property is set to
- * <code>true</code></li>
* </ul>
*
* <p/> A class qualifies for manual serialization if:
@@ -104,6 +99,10 @@
* <li>Has native methods</li>
* <li>Is assignable to {@link Collection} or {@link Map} but it is not a
* parameterized type</li>
+ * <li>Is automatically serializable and one of its subtypes is not;
+ * this warning can be treated as an error if the
+ * gwt.allowUnserializableSubtypesOfAutoSerializableTypes property is set to
+ * <code>false</code></li>
* </ul>
*/
public class SerializableTypeOracleBuilder {
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
index e3cccf0..d08d122 100644
--- a/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
@@ -191,7 +191,7 @@
private InheritanceTestServiceAsync getServiceAsync() {
if (inheritanceTestService == null) {
- inheritanceTestService = (InheritanceTestServiceAsync) GWT.create(InheritanceTestService.class);
+ inheritanceTestService = (InheritanceTestServiceAsync) GWT.create(InheritanceTestServiceSubtype.class);
((ServiceDefTarget) inheritanceTestService).setServiceEntryPoint(GWT.getModuleBaseURL()
+ "inheritance");
}
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTestServiceSubtype.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTestServiceSubtype.java
new file mode 100644
index 0000000..52fecd2
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTestServiceSubtype.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2007 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.user.client.rpc;
+
+/**
+ */
+public interface InheritanceTestServiceSubtype extends InheritanceTestService {
+ /**
+ */
+ void foo();
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTestServiceSubtypeAsync.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTestServiceSubtypeAsync.java
new file mode 100644
index 0000000..79ff6aa
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTestServiceSubtypeAsync.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2007 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.user.client.rpc;
+
+/**
+ *
+ */
+public interface InheritanceTestServiceSubtypeAsync extends
+ InheritanceTestServiceAsync {
+// public void foo(AsyncCallback callback);
+}
diff --git a/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java
index 32c4d35..bba012e 100644
--- a/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java
@@ -15,9 +15,9 @@
*/
package com.google.gwt.user.server.rpc;
-import com.google.gwt.user.client.rpc.InheritanceTestService;
import com.google.gwt.user.client.rpc.InheritanceTestSetFactory;
import com.google.gwt.user.client.rpc.InheritanceTestSetValidator;
+import com.google.gwt.user.client.rpc.InheritanceTestServiceSubtype;
import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.AnonymousClassInterface;
import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.Circle;
import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.SerializableClass;
@@ -27,7 +27,7 @@
* TODO: document me.
*/
public class InheritanceTestServiceImpl extends RemoteServiceServlet implements
- InheritanceTestService {
+ InheritanceTestServiceSubtype {
public AnonymousClassInterface echo(AnonymousClassInterface serializable) {
return serializable;
@@ -58,6 +58,9 @@
return serializableClass;
}
+ public void foo() {
+ }
+
public SerializableClass getUnserializableClass() {
return InheritanceTestSetFactory.createNonStaticInnerClass();
}