Big refactor of SerializableTypeOracleBuilder that natively differentiates between "field serializable" and "instantiable". Also handles covariant arrays correctly.
Patch by: scottb, mmendez
Review by: mmendez, scottb (pair program)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1325 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 4c64c36..c16edc9 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -22,6 +22,7 @@
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JConstructor;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPackage;
@@ -140,38 +141,8 @@
* </ul>
*/
public class SerializableTypeOracleBuilder {
- /**
- * Represents additional information about a type with regards to its
- * serializability.
- */
- private class MetaTypeInfo {
- /**
- * An issue that prevents a type from being serializable.
- */
- private class SerializationIssue implements Comparable {
- final String issueMessage;
- final TreeLogger.Type issueType;
-
- SerializationIssue(Type issueType, String issueMessage) {
- this.issueType = issueType;
- this.issueMessage = issueMessage;
- }
-
- public int compareTo(Object obj) {
- SerializationIssue other = (SerializationIssue) obj;
- if (issueType == other.issueType) {
- return issueMessage.compareTo(other.issueMessage);
- }
-
- if (issueType.isLowerPriorityThan(other.issueType)) {
- return -1;
- }
-
- return 1;
- }
- }
-
+ private class TypeInfo {
/**
* <code>true</code> if the type is assignable to {@link IsSerializable}
* or {@link java.io.Serializable Serializable}.
@@ -182,28 +153,112 @@
* <code>true</code> if the this type directly implements one of the
* marker interfaces.
*/
- private Boolean directlyImplementsMarker;
+ private final boolean directlyImplementsMarker;
/**
* Custom field serializer or <code>null</code> if there isn't one.
*/
private final JClassType manualSerializer;
+ TypeInfo(JClassType type) {
+ autoSerializable = type.isAssignableTo(isSerializableClass)
+ || type.isAssignableTo(serializableClass);
+ manualSerializer = findCustomFieldSerializer(typeOracle, type);
+ directlyImplementsMarker = directlyImplementsInterface(type,
+ isSerializableClass)
+ || directlyImplementsInterface(type, serializableClass);
+ }
+
+ public JClassType getManualSerializer() {
+ return manualSerializer;
+ }
+
+ public boolean isAutoSerializable() {
+ return autoSerializable;
+ }
+
+ public boolean isDeclaredSerializable() {
+ return autoSerializable || isManuallySerializable();
+ }
+
+ public boolean isDirectlySerializable() {
+ return directlyImplementsMarker || isManuallySerializable();
+ }
+
+ public boolean isManuallySerializable() {
+ return manualSerializer != null;
+ }
+ }
+
+ private static class TypeInfoComputed {
/**
- * <code>true</code> if this type might be instantiated.
+ * An issue that prevents a type from being serializable.
*/
- private boolean maybeInstantiated;
+ private class SerializationIssue implements Comparable {
+ public final boolean isSpeculative;
+ public final String issueMessage;
+
+ SerializationIssue(boolean isSpeculative, String issueMessage) {
+ this.isSpeculative = isSpeculative;
+ this.issueMessage = issueMessage;
+ }
+
+ public int compareTo(Object obj) {
+ SerializationIssue other = (SerializationIssue) obj;
+ if (isSpeculative == other.isSpeculative) {
+ return issueMessage.compareTo(other.issueMessage);
+ }
+
+ if (isSpeculative && !other.isSpeculative) {
+ return -1;
+ }
+
+ return 1;
+ }
+ }
+
+ /**
+ * Represents the state of a type while we are determining the set of
+ * serializable types.
+ */
+ private static final class TypeState {
+ private final String state;
+
+ protected TypeState(String state) {
+ this.state = state;
+ }
+
+ public String toString() {
+ return state;
+ }
+ }
+
+ /**
+ * The instantiability of a type has been determined.
+ */
+ static final TypeState CHECK_DONE = new TypeState("Check succeeded");
+
+ /**
+ * The instantiability of a type is being checked.
+ */
+ static final TypeState CHECK_IN_PROGRESS = new TypeState(
+ "Check in progress");
+
+ /**
+ * The instantiability of a type has not been checked.
+ */
+ static final TypeState NOT_CHECKED = new TypeState("Not checked");
/**
* <code>true</code> if the type is automatically or manually serializable
* and the corresponding checks succeed.
*/
- private boolean serializable;
+ private boolean fieldSerializable = false;
/**
- * List of serializable types that are assignable to this one.
+ * <code>true</code> if this type might be instantiated.
*/
- private List serializableTypesAssignableToMe;
+ private boolean instantiable = false;
/**
* List of serialization warnings or errors that prevent this type from
@@ -214,218 +269,69 @@
/**
* The state that this type is currently in.
*/
- private TypeState state = SerializableTypeOracleBuilder.NOT_CHECKED;
+ private TypeState state = NOT_CHECKED;
/**
* {@link JType} associated with this metadata.
*/
private final JType type;
- /**
- * <code>true</code> if the subtypes of this type were also checked.
- */
- private boolean typeRoot;
-
- MetaTypeInfo(JType type, boolean autoSerializable,
- JClassType manualSerializer) {
+ public TypeInfoComputed(JType type) {
this.type = type;
- this.autoSerializable = autoSerializable;
- this.manualSerializer = manualSerializer;
}
- public void addSerializationIssue(TreeLogger.Type issueType,
- String issueMessage) {
- serializationIssues.add(new SerializationIssue(issueType, issueMessage));
- }
-
- /**
- * Returns <code>true</code> if this type directly implements one of the
- * marker interfaces.
- *
- * @return <code>true</code> if this type directly implements one of the
- * marker interfaces.
- */
- public boolean directlyImplementsMarkerInterface() {
- JClassType isClassOrInterface = type.isClassOrInterface();
- if (isClassOrInterface == null) {
- return false;
- }
-
- if (directlyImplementsMarker == null) {
- if (directlyImplementsInterface(isClassOrInterface, isSerializableClass)
- || directlyImplementsInterface(isClassOrInterface,
- serializableClass)) {
- directlyImplementsMarker = Boolean.TRUE;
- } else {
- directlyImplementsMarker = Boolean.FALSE;
- }
- }
-
- return directlyImplementsMarker.booleanValue();
- }
-
- public JClassType getManualSerializer() {
- return manualSerializer;
- }
-
- public List getSerializableTypesAssignableToMe() {
- return serializableTypesAssignableToMe;
- }
-
- public Set /* <SerializationIssue> */getSerializationIssues() {
- return serializationIssues;
- }
-
- public TypeState getState() {
- return state;
+ public void addSerializationIssue(boolean isSpeculative, String issueMessage) {
+ serializationIssues.add(new SerializationIssue(isSpeculative,
+ issueMessage));
}
public JType getType() {
return type;
}
- public boolean isSerializable() {
- if (state == SerializableTypeOracleBuilder.CHECK_IN_PROGRESS) {
- // Assume that we are serializable if we are currently checking the
- // type
- return true;
+ public boolean isDone() {
+ return state == CHECK_DONE;
+ }
+
+ public boolean isFieldSerializable() {
+ return fieldSerializable;
+ }
+
+ public boolean isInstantiable() {
+ return instantiable;
+ }
+
+ public boolean isPendingInstantiable() {
+ return state == CHECK_IN_PROGRESS;
+ }
+
+ public void logReasonsForUnserializability(TreeLogger logger) {
+ Iterator iter = serializationIssues.iterator();
+ while (iter.hasNext()) {
+ SerializationIssue serializationIssue = (SerializationIssue) iter.next();
+ logger.branch(getLogLevel(serializationIssue.isSpeculative),
+ serializationIssue.issueMessage, null);
}
-
- return serializable;
}
- /**
- * Returns <code>true</code> if this type was seen as part of a method
- * signature or as a field type.
- */
- public boolean isTypeRoot() {
- return typeRoot;
+ public void setFieldSerializable() {
+ fieldSerializable = true;
}
- /**
- * Returns <code>true</code> if this type might be instantiated.
- *
- * @return <code>true</code> if this type might be instantiated
- */
- public boolean maybeInstantiated() {
- return maybeInstantiated;
+ public void setInstantiable(boolean instantiable) {
+ this.instantiable = instantiable;
+ if (instantiable) {
+ fieldSerializable = true;
+ }
+ state = CHECK_DONE;
}
- /**
- * Returns <code>true</code> if this type needs to be rechecked. Only type
- * roots types have their subtypes analyzed. However it is possible that
- * this type was previously checked as the super type of a root type in
- * which case not all of its subtypes were analyzed.
- *
- * @param asTypeRoot <code>true</code> if we are being asked to check this
- * type as a type root
- * @return <code>true</code> if this type needs to be rechecked
- */
- public boolean needToRecheck(boolean asTypeRoot) {
- assert (state == SerializableTypeOracleBuilder.CHECK_SUCCEEDED);
-
- return asTypeRoot && !isTypeRoot();
- }
-
- /**
- * Returns <code>true</code> if the type is assignable to
- * {@link IsSerializable} or {@link java.io.Serializable Serializable}.
- *
- * @return <code>true</code> if the type is assignable to
- * {@link IsSerializable} or
- * {@link java.io.Serializable Serializable}
- */
- public boolean qualifiesForAutoSerialization() {
- return autoSerializable && manualSerializer == null;
- }
-
- /**
- * Returns <code>true</code> if the type has a custom field serializer.
- *
- * @return <code>true</code> if the type has a custom field serializer
- */
- public boolean qualifiesForManualSerialization() {
- return manualSerializer != null;
- }
-
- public boolean qualifiesForSerialization() {
- return qualifiesForAutoSerialization()
- || qualifiesForManualSerialization();
- }
-
- /**
- * Reset any state cached by this type.
- */
- public void reset() {
- serializationIssues.clear();
-
- serializableTypesAssignableToMe = null;
-
- state = NOT_CHECKED;
-
- serializable = false;
-
- directlyImplementsMarker = null;
- }
-
- public void setMaybeInstantiated(boolean maybeInstantiated) {
- this.maybeInstantiated = maybeInstantiated;
- }
-
- public void setSerializable(boolean serializable) {
- this.serializable = serializable;
- }
-
- public void setSerializableTypesAssignableToMe(List serializableTypes) {
- serializableTypesAssignableToMe = serializableTypes;
- }
-
- public void setState(TypeState newState) {
- state = newState;
- }
-
- public void setTypeRoot(boolean checkedSubtypes) {
- this.typeRoot = checkedSubtypes;
+ public void setPendingInstantiable() {
+ state = CHECK_IN_PROGRESS;
}
}
/**
- * Represents the state of a type while we are determining the set of
- * serializable types.
- */
- private static final class TypeState {
- private final String state;
-
- protected TypeState(String state) {
- this.state = state;
- }
-
- public String toString() {
- return state;
- }
- }
-
- /**
- * A serializability problem was discovered with the type.
- */
- static final TypeState CHECK_FAILED = new TypeState("Check failed");
-
- /**
- * The serializability of a type is being checked.
- */
- static final TypeState CHECK_IN_PROGRESS = new TypeState("Check in progress");
-
- /**
- * The serializability of a type has been determined and there were no errors.
- */
- static final TypeState CHECK_SUCCEEDED = new TypeState("Check succeeded");
-
- /**
- * The serializability of a type has not been checked.
- */
- static final TypeState NOT_CHECKED = new TypeState("Not checked");
-
- /**
* Finds the custom field serializer for a given type.
*
* @param typeOracle
@@ -462,28 +368,6 @@
edges.add(clazz);
}
- /**
- * Returns <code>true</code> if the list of serializable types contains at
- * least one concrete serializable type.
- */
- private static boolean containsConcreteSerializableTypes(
- List serializableTypes) {
- Iterator it = serializableTypes.iterator();
- while (it.hasNext()) {
- JType type = (JType) it.next();
- JType leafType = type.getLeafType();
-
- JClassType clazz = leafType.isClass();
- if (clazz != null && !clazz.isAbstract()) {
- return true;
- } else if (leafType.isPrimitive() != null) {
- return true;
- }
- }
-
- return false;
- }
-
private static void depthFirstSearch(Set seen, Map adjList, JClassType type) {
if (seen.contains(type)) {
return;
@@ -549,8 +433,8 @@
* @param leaves the set of serializable leaf types
* @return all types on the path from the root type to the serializable leaves
*/
- private static List getAllTypesBetweenRootTypeAndSerializableLeaves(
- JClassType root, List leaves) {
+ private static List getAllTypesBetweenRootTypeAndLeaves(JClassType root,
+ List leaves) {
Map adjList = getInvertedTypeHierarchy(root);
Set types = new HashSet();
@@ -616,6 +500,10 @@
return adjList;
}
+ private static Type getLogLevel(boolean isSpeculative) {
+ return isSpeculative ? TreeLogger.WARN : TreeLogger.ERROR;
+ }
+
private static void logSerializableTypes(TreeLogger logger, JType[] types) {
TreeLogger localLogger = logger.branch(TreeLogger.DEBUG, "Identified "
+ types.length + " serializable type"
@@ -627,6 +515,8 @@
}
}
+ private boolean alreadyCheckedObject;
+
/**
* Cache of the {@link JClassType} for {@link Collection}.
*/
@@ -666,11 +556,6 @@
private final JClassType streamWriterClass;
/**
- * Cache of the {@link JClassType} for {@link String}.
- */
- private final JClassType stringClass;
-
- /**
* If <code>true</code> we will not warn if a serializable type contains a
* non-static final field. We warn because these fields are not serialized.
*/
@@ -679,20 +564,14 @@
private final TypeOracle typeOracle;
/**
- * A stack of types whose fields we are currently checking.
+ * Map of {@link JClassType} to {@link TypeInfo}.
*/
- private final Stack /* <JType> */typesBeingAnalyzed = new Stack();
+ private final Map /* <JClassType, TypeInfo> */typeToTypeInfo = new HashMap();
/**
- * Map of {@link JType} to {@link MetaTypeInfo}.
+ * Map of {@link JType} to {@link TypeInfoComputed}.
*/
- private final Map /* <JType, MetaTypeInfo> */typeToMetaTypeInfo = new HashMap();
-
- /**
- * <code>true</code> if we encountered a violation of either automatic or
- * manual serialization which should result in an error.
- */
- private boolean validationFailed;
+ private final Map /* <JType, TypeInfoComputed> */typeToTypeInfoComputed = new HashMap();
/**
* Constructs a builder.
@@ -713,19 +592,8 @@
isSerializableClass = typeOracle.getType(IsSerializable.class.getName());
mapClass = typeOracle.getType(Map.class.getName());
serializableClass = typeOracle.getType(Serializable.class.getName());
- stringClass = typeOracle.getType(String.class.getName());
streamReaderClass = typeOracle.getType(SerializationStreamReader.class.getName());
streamWriterClass = typeOracle.getType(SerializationStreamWriter.class.getName());
-
- // String is always serializable
- MetaTypeInfo stringMti = getMetaTypeInfo(stringClass);
- stringMti.setSerializable(true);
- stringMti.setMaybeInstantiated(true);
-
- // IncompatibleRemoteServiceException is always serializable
- MetaTypeInfo incompatibleRemoteServiceExceptionMti = getMetaTypeInfo(typeOracle.getType(IncompatibleRemoteServiceException.class.getName()));
- incompatibleRemoteServiceExceptionMti.setSerializable(true);
- incompatibleRemoteServiceExceptionMti.setMaybeInstantiated(true);
} catch (NotFoundException e) {
rootLogger.log(TreeLogger.ERROR, null, e);
throw new UnableToCompleteException();
@@ -753,29 +621,76 @@
initializeProperties(rootLogger, propertyOracle);
+ try {
+ // String is always instantiable.
+ JClassType stringType = typeOracle.getType(String.class.getName());
+ if (!checkTypeInstantiable(rootLogger, stringType, false, false)) {
+ throw new UnableToCompleteException();
+ }
+ // IncompatibleRemoteServiceException is always serializable
+ JClassType icseType = typeOracle.getType(IncompatibleRemoteServiceException.class.getName());
+ if (!checkTypeInstantiable(rootLogger, icseType, false, false)) {
+ throw new UnableToCompleteException();
+ }
+ } catch (NotFoundException e) {
+ rootLogger.log(TreeLogger.ERROR, null, e);
+ throw new UnableToCompleteException();
+ }
+
TreeLogger logger = rootLogger.branch(TreeLogger.DEBUG, "Analyzing '"
+ remoteService.getParameterizedQualifiedSourceName()
+ "' for serializable types", null);
+ alreadyCheckedObject = false;
+
validateRemoteService(logger, remoteService);
- if (validationFailed) {
- // the validation code has already logged why
- throw new UnableToCompleteException();
+ // Compute covariant arrays.
+ // Cache a list to prevent comodification.
+ List typeInfoComputed = new ArrayList(typeToTypeInfoComputed.values());
+ Iterator iterTypes = typeInfoComputed.iterator();
+ while (iterTypes.hasNext()) {
+ TypeInfoComputed tic = (TypeInfoComputed) iterTypes.next();
+ if (tic.isInstantiable()) {
+ JArrayType arrayType = tic.getType().isArray();
+ if (arrayType != null) {
+ JType leafType = arrayType.getLeafType();
+ int rank = arrayType.getRank();
+ JClassType classType = leafType.isClassOrInterface();
+ if (classType != null) {
+ List instantiableSubTypes = new ArrayList();
+ JClassType[] subTypes = classType.getSubtypes();
+ for (int i = 0; i < subTypes.length; ++i) {
+ if (getTypeInfoComputed(subTypes[i]).isInstantiable()) {
+ instantiableSubTypes.add(subTypes[i]);
+ }
+ }
+ List covariantTypes = getAllTypesBetweenRootTypeAndLeaves(
+ classType, instantiableSubTypes);
+ for (int i = 0, c = covariantTypes.size(); i < c; ++i) {
+ JArrayType covariantArray = getArrayType(typeOracle, rank,
+ (JType) covariantTypes.get(i));
+ getTypeInfoComputed(covariantArray).setInstantiable(true);
+ }
+ }
+ }
+ }
}
Set possiblyInstantiatedTypes = new HashSet();
List serializableTypesList = new ArrayList();
- Iterator iterTypes = typeToMetaTypeInfo.values().iterator();
+ iterTypes = typeToTypeInfoComputed.values().iterator();
while (iterTypes.hasNext()) {
- MetaTypeInfo mti = (MetaTypeInfo) iterTypes.next();
- JType type = mti.getType();
-
- if (mti.isSerializable() && type.isInterface() == null) {
- if (mti.maybeInstantiated()) {
+ TypeInfoComputed tic = (TypeInfoComputed) iterTypes.next();
+ JType type = tic.getType();
+ // Only record real types
+ if (type.isParameterized() == null) {
+ if (tic.isInstantiable()) {
possiblyInstantiatedTypes.add(type);
}
- serializableTypesList.add(type);
+ if (tic.isFieldSerializable()) {
+ serializableTypesList.add(type);
+ }
}
}
@@ -801,154 +716,138 @@
*
* @param localLogger
*/
- private void checkAllSubtypesOfObject(TreeLogger localLogger) {
+ private void checkAllSubtypesOfObject(TreeLogger logger) {
+ if (alreadyCheckedObject) {
+ return;
+ }
+ alreadyCheckedObject = true;
+
/*
* This will pull in the world and the set of serializable types will be
* larger than it needs to be. We exclude types that do not qualify for
* serialization to avoid generating false errors due to types that do not
* qualify for serialization and have no serializable subtypes.
*/
+ TreeLogger localLogger = logger.branch(TreeLogger.WARN,
+ "Checking all subtypes of Object which qualify for serialization", null);
JClassType[] allTypes = typeOracle.getJavaLangObject().getSubtypes();
for (int i = 0; i < allTypes.length; ++i) {
JClassType cls = allTypes[i];
- MetaTypeInfo mti = getMetaTypeInfo(cls);
- if (mti.qualifiesForSerialization()) {
- checkType(localLogger, cls, true);
+ if (getTypeInfo(cls).isDeclaredSerializable()) {
+ checkTypeInstantiable(localLogger, cls, true, true);
}
}
}
- private void checkClassOrInterface(TreeLogger logger, JClassType type,
- boolean checkSubtypes) {
+ private boolean checkClassOrInterfaceInstantiable(TreeLogger logger,
+ JClassType type, boolean isSpeculative) {
- JClassType superclass = type.getSuperclass();
- if (superclass != null) {
- MetaTypeInfo superMti = getMetaTypeInfo(superclass);
- if (superMti.qualifiesForSerialization()) {
- checkType(
- logger.branch(TreeLogger.DEBUG, "Analyzing superclass:", null),
- superclass, false);
- } else {
- logger.branch(TreeLogger.DEBUG, "Not analyzing superclass '"
- + superclass.getParameterizedQualifiedSourceName()
- + "' because it is not assignable to '"
- + IsSerializable.class.getName() + "' or '"
- + Serializable.class.getName()
- + "' nor does it have a custom field serializer", null);
- }
- }
+ TypeInfo typeInfo = getTypeInfo(type);
+ TypeInfoComputed tic = getTypeInfoComputed(type);
- MetaTypeInfo mti = getMetaTypeInfo(type);
- if (mti.qualifiesForSerialization()) {
- if (mti.qualifiesForManualSerialization()) {
- List failures = CustomFieldSerializerValidator.validate(
- streamReaderClass, streamWriterClass, mti.getManualSerializer(),
- type);
- if (!failures.isEmpty()) {
- validationFailed = true;
- markAsUnserializableAndLog(logger, TreeLogger.ERROR, failures, mti);
- return;
- }
- } else {
- if (!mti.directlyImplementsMarkerInterface()) {
- if (superclass != null
- && !getMetaTypeInfo(superclass).isSerializable()) {
- markAsUnserializableAndLog(logger, TreeLogger.WARN, "Superclass '"
- + superclass.getQualifiedSourceName()
- + "' is not serializable and this type does not implement '"
- + IsSerializable.class.getName() + "' or '"
- + Serializable.class.getName() + "'; see previous log entries",
- mti);
- return;
- }
- }
-
- if (type.isLocalType()) {
- markAsUnserializableAndLog(
- logger,
- TreeLogger.WARN,
- "Is a local type, it will be excluded from the set of serializable types",
- mti);
- return;
- }
-
- if (type.isMemberType() && !type.isStatic()) {
- markAsUnserializableAndLog(
- logger,
- TreeLogger.WARN,
- "Is nested but not static, it will be excluded from the set of serializable types",
- mti);
- return;
- }
-
- // TODO: revisit this check; we probably want to field serialize a type
- // that is not default constructable, for the sake of subclasses.
- if (type.isClass() != null && !type.isAbstract()
- && !type.isDefaultInstantiable()) {
- markAsUnserializableAndLog(
- logger,
- TreeLogger.WARN,
- "Was not default instantiable (it must have a zero-argument, public constructor or no constructors at all)",
- mti);
- return;
- }
- }
-
- mti.setSerializable(true);
-
- checkFields(logger, type);
-
- checkMethods(logger, type);
- } else {
+ if (!typeInfo.isDeclaredSerializable()) {
logger.branch(TreeLogger.DEBUG, "Type '"
+ type.getParameterizedQualifiedSourceName()
+ "' is not assignable to '" + IsSerializable.class.getName()
+ "' or '" + Serializable.class.getName()
+ "' nor does it have a custom field serializer", null);
+ return false;
}
- if (checkSubtypes) {
- if (!type.isAbstract()
- && (type.isDefaultInstantiable() || mti.qualifiesForManualSerialization())) {
- mti.setMaybeInstantiated(true);
+ if (typeInfo.isManuallySerializable()) {
+ List failures = CustomFieldSerializerValidator.validate(
+ streamReaderClass, streamWriterClass, typeInfo.getManualSerializer(),
+ type);
+ if (!failures.isEmpty()) {
+ markAsUninstantiableAndLog(logger, isSpeculative, failures, tic);
+ return false;
+ }
+ } else {
+ assert (typeInfo.isAutoSerializable());
+
+ if (type.isLocalType()) {
+ markAsUninstantiableAndLog(
+ logger,
+ isSpeculative,
+ type.getParameterizedQualifiedSourceName()
+ + " is a local type, it will be excluded from the set of serializable types",
+ tic);
+ return false;
}
- JClassType[] subtypes = type.getSubtypes();
- if (subtypes.length > 0) {
- TreeLogger localLogger = logger.branch(TreeLogger.DEBUG,
- "Analyzing subclasses:", null);
+ if (type.isMemberType() && !type.isStatic()) {
+ markAsUninstantiableAndLog(
+ logger,
+ isSpeculative,
+ type.getParameterizedQualifiedSourceName()
+ + " is nested but not static, it will be excluded from the set of serializable types",
+ tic);
+ return false;
+ }
- for (int i = 0; i < subtypes.length; ++i) {
- JClassType subType = subtypes[i];
- MetaTypeInfo smti = getMetaTypeInfo(subType);
- if (smti.qualifiesForSerialization()) {
- checkType(localLogger, subType, false);
- if (!subType.isAbstract()
- && (subType.isDefaultInstantiable() || smti.qualifiesForManualSerialization())) {
- smti.setMaybeInstantiated(true);
- }
- } else {
- localLogger.branch(TreeLogger.DEBUG, "Not analyzing subclass '"
- + subType.getParameterizedQualifiedSourceName()
- + "' because it is not assignable to '"
- + IsSerializable.class.getName() + "' or '"
- + Serializable.class.getName()
- + "' nor does it have a custom field serializer", null);
- }
+ if (type.isInterface() != null || type.isAbstract()) {
+ // Quietly return false.
+ return false;
+ }
+
+ boolean isDefaultInstantiable = false;
+ if (type.getConstructors().length == 0) {
+ isDefaultInstantiable = true;
+ } else {
+ JConstructor ctor = type.findConstructor(new JType[0]);
+ if (ctor != null && !ctor.isPrivate()) {
+ isDefaultInstantiable = true;
}
}
+
+ if (!isDefaultInstantiable) {
+ // Warn and return false.
+ logger.log(
+ TreeLogger.WARN,
+ "Was not default instantiable (it must have a zero-argument, non-private constructor or no constructors at all)",
+ null);
+ return false;
+ }
}
+
+ // Check all fields, including inherited fields
+ if (!checkFields(logger, type, isSpeculative)) {
+ return false;
+ }
+
+ checkMethods(logger, type);
+ return true;
}
- private void checkFields(TreeLogger logger, JClassType classOrInterface) {
- TreeLogger localLogger = logger;
- MetaTypeInfo mti = getMetaTypeInfo(classOrInterface);
+ private boolean checkFields(TreeLogger logger, JClassType classOrInterface,
+ boolean isSpeculative) {
+ TypeInfo typeInfo = getTypeInfo(classOrInterface);
+
+ // Check all super type fields first (recursively).
+ JClassType superType = classOrInterface.getSuperclass();
+ if (superType != null && getTypeInfo(superType).isDeclaredSerializable()) {
+ boolean superTypeOk = checkFields(logger, superType, isSpeculative);
+ /*
+ * If my super type did not check out, then I am not instantiable and we
+ * should error out... UNLESS I am *directly* serializable myself, in
+ * which case it's ok for me to be the root of a new instantiable
+ * hierarchy.
+ */
+ if (!superTypeOk && !typeInfo.isDirectlySerializable()) {
+ return false;
+ }
+ }
+
+ if (typeInfo.isManuallySerializable()) {
+ // All fields on a manual serializable are considered speculative.
+ isSpeculative = true;
+ }
+
+ boolean allSucceeded = true;
JField[] fields = classOrInterface.getFields();
if (fields.length > 0) {
- localLogger = localLogger.branch(TreeLogger.DEBUG, "Analyzing Fields:",
- null);
-
- typesBeingAnalyzed.push(classOrInterface);
+ TreeLogger localLogger = logger.branch(TreeLogger.DEBUG,
+ "Analyzing Fields:", null);
for (int i = 0; i < fields.length; ++i) {
JField field = fields[i];
@@ -969,18 +868,22 @@
field.toString(), null);
JType fieldType = field.getType();
- if (!checkTypeRoot(fieldLogger, fieldType, false)) {
- if (mti.qualifiesForAutoSerialization()) {
- mti.setSerializable(false);
- }
+ if (typeInfo.isManuallySerializable()
+ && fieldType.getLeafType() == typeOracle.getJavaLangObject()) {
+ checkAllSubtypesOfObject(fieldLogger.branch(TreeLogger.WARN,
+ "Object was reached from a manually serializable type", null));
+ } else {
+ allSucceeded &= checkTypeInstantiable(fieldLogger, fieldType,
+ isSpeculative, false);
}
}
-
- typesBeingAnalyzed.pop();
-
- } else {
- localLogger.branch(TreeLogger.DEBUG, "No fields to analyze", null);
}
+
+ boolean succeeded = allSucceeded || typeInfo.isManuallySerializable();
+ if (succeeded) {
+ getTypeInfoComputed(classOrInterface).setFieldSerializable();
+ }
+ return succeeded;
}
private void checkForUnparameterizedType(TreeLogger logger, JType type) {
@@ -1010,6 +913,7 @@
return;
}
+ // TODO: consider looking up type hierarchy.
JMethod[] methods = classOrInterface.getMethods();
for (int i = 0; i < methods.length; ++i) {
JMethod method = methods[i];
@@ -1023,218 +927,121 @@
}
}
- /**
- * Checks that a type which qualifies as either automatically serializable or
- * manually serializable actually is.
- */
- private void checkType(TreeLogger logger, JType type, boolean isRootType) {
- if (type == null || type.isPrimitive() != null) {
- return;
+ private boolean checkTypeInstantiable(TreeLogger logger, JType type,
+ boolean isSpeculative, boolean rawTypeOk) {
+ assert (type != null);
+ if (type.isPrimitive() != null) {
+ return true;
}
TreeLogger localLogger = logger.branch(TreeLogger.DEBUG,
type.getParameterizedQualifiedSourceName(), null);
- MetaTypeInfo mti = getMetaTypeInfo(type);
- TypeState state = mti.getState();
-
- if (state == SerializableTypeOracleBuilder.CHECK_FAILED) {
- logReasonsForUnserializability(localLogger, mti);
- return;
- } else if (state == SerializableTypeOracleBuilder.CHECK_IN_PROGRESS) {
- localLogger.branch(TreeLogger.DEBUG, "'"
- + type.getParameterizedQualifiedSourceName()
- + "' is being analyzed; skipping", null);
- return;
- } else if (state == SerializableTypeOracleBuilder.CHECK_SUCCEEDED) {
- if (!mti.needToRecheck(isRootType)) {
- localLogger.branch(TreeLogger.DEBUG, "Type has already been analyzed",
- null);
- return;
- }
-
- mti.reset();
+ TypeInfoComputed tic = getTypeInfoComputed(type);
+ if (tic.isPendingInstantiable()) {
+ // just early out and pretend we will succeed
+ return true;
+ } else if (tic.isDone()) {
+ return tic.isInstantiable();
}
- mti.setState(SerializableTypeOracleBuilder.CHECK_IN_PROGRESS);
+ tic.setPendingInstantiable();
+
+ if (type.getLeafType() == typeOracle.getJavaLangObject()) {
+ markAsUninstantiableAndLog(
+ logger,
+ isSpeculative,
+ "In order to produce smaller client-side code, 'Object' is not allowed; consider using a more specific type",
+ tic);
+ return false;
+ }
if (type.isParameterized() != null) {
JParameterizedType parameterized = type.isParameterized();
- checkType(
- localLogger.branch(TreeLogger.DEBUG, "Analyzing raw type", null),
- parameterized.getRawType(), true);
+ boolean allSucceeded = checkTypeInstantiable(localLogger.branch(
+ TreeLogger.DEBUG, "Analyzing raw type", null),
+ parameterized.getRawType(), isSpeculative, true);
TreeLogger branch = localLogger.branch(TreeLogger.DEBUG,
"Analyzing type args", null);
JType[] typeArgs = parameterized.getTypeArgs();
for (int i = 0; i < typeArgs.length; ++i) {
- checkType(branch, typeArgs[i], true);
+ allSucceeded &= checkTypeInstantiable(branch, typeArgs[i],
+ isSpeculative, false);
}
+ tic.setInstantiable(allSucceeded);
+ return allSucceeded;
} else if (type.isArray() != null) {
- checkType(localLogger.branch(TreeLogger.DEBUG,
- "Analyzing component type:", null),
- type.isArray().getComponentType(), true);
+ TreeLogger branch = localLogger.branch(TreeLogger.DEBUG,
+ "Analyzing component type:", null);
+ boolean success = checkTypeInstantiable(branch,
+ type.isArray().getComponentType(), isSpeculative, false);
+ tic.setInstantiable(success);
+ return success;
} else if (type.isClassOrInterface() != null) {
- checkClassOrInterface(localLogger, type.isClassOrInterface(), isRootType);
- }
-
- if (mti.getState() != SerializableTypeOracleBuilder.CHECK_FAILED) {
- mti.setState(SerializableTypeOracleBuilder.CHECK_SUCCEEDED);
- }
-
- mti.setTypeRoot(isRootType);
- }
-
- /**
- * Check any type that is used in the method signature of a
- * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService} method
- * or as the field type of a type reachable from the method signature.
- */
- private boolean checkTypeRoot(TreeLogger logger, JType type,
- boolean errorOnNoSerializableSubtypes) {
-
- if (type.getLeafType() == typeOracle.getJavaLangObject()) {
- if (!inManualSerializationContext()) {
- markAsUnserializableAndLog(
- logger,
- TreeLogger.WARN,
- "In order to produce smaller client-side code, 'Object' is not allowed; consider using a more specific type",
- getMetaTypeInfo(type));
-
- if (errorOnNoSerializableSubtypes) {
- validationFailed = true;
- }
-
- return false;
+ JClassType classType = type.isClassOrInterface();
+ TypeInfo typeInfo = getTypeInfo(classType);
+ if (isSpeculative && typeInfo.isDirectlySerializable()) {
+ isSpeculative = false;
}
- logger.branch(
- TreeLogger.WARN,
- "Object was reached from a manually serializable type; all subtypes of Object which qualify for serialization will be considered",
- null);
- }
+ boolean anySubtypes = false;
+ if (checkClassOrInterfaceInstantiable(localLogger, classType,
+ isSpeculative)) {
+ tic.setInstantiable(true);
+ anySubtypes = true;
- checkForUnparameterizedType(logger, type);
- checkType(logger, type, true);
-
- List serializableTypes = getSerializableTypesAssignableTo(type);
- if (serializableTypes.size() == 0) {
- markAsUnserializableAndLog(
- logger,
- errorOnNoSerializableSubtypes ? TreeLogger.ERROR : TreeLogger.WARN,
- "Type '"
- + type.getParameterizedQualifiedSourceName()
- + "' was not serializable and none of its subtypes were either; see previous log entries",
- getMetaTypeInfo(type));
-
- if (errorOnNoSerializableSubtypes) {
- validationFailed = true;
+ if (!rawTypeOk) {
+ checkForUnparameterizedType(logger, classType);
+ }
}
- return false;
- } else if (!containsConcreteSerializableTypes(serializableTypes)) {
- logger.branch(TreeLogger.WARN,
- "There are only abstract serializable types assignable to '"
- + type.getParameterizedQualifiedSourceName() + "'", null);
- }
+ // Speculatively check all subtypes.
+ JClassType[] subtypes = classType.getSubtypes();
+ if (subtypes.length > 0) {
+ TreeLogger subLogger = localLogger.branch(TreeLogger.DEBUG,
+ "Analyzing subclasses:", null);
- return true;
- }
-
- private MetaTypeInfo getMetaTypeInfo(JType type) {
- MetaTypeInfo mti = (MetaTypeInfo) typeToMetaTypeInfo.get(type);
- if (mti == null) {
- boolean autoSerializable = false;
- JClassType manualSerializer = null;
- JClassType classOrInterface = type.isClassOrInterface();
- if (classOrInterface != null) {
- autoSerializable = classOrInterface.isAssignableTo(isSerializableClass)
- || classOrInterface.isAssignableTo(serializableClass);
- manualSerializer = findCustomFieldSerializer(typeOracle,
- classOrInterface);
- }
-
- mti = new MetaTypeInfo(type, autoSerializable, manualSerializer);
- typeToMetaTypeInfo.put(type, mti);
- }
-
- return mti;
- }
-
- /**
- * Returns the list of serializable types that can be assigned to the
- * specified type. If the list was empty then there were no types which
- * qualified.
- */
- private List getSerializableTypesAssignableTo(JType type) {
- MetaTypeInfo mti = getMetaTypeInfo(type);
- List serializableTypes = mti.getSerializableTypesAssignableToMe();
- if (serializableTypes == null) {
- JArrayType isArray = type.isArray();
- JClassType isClassOrInterface = type.isClassOrInterface();
- JParameterizedType isParameterized = type.isParameterized();
- JPrimitiveType isPrimitive = type.isPrimitive();
-
- serializableTypes = new ArrayList();
- if (isArray != null) {
- // array
- JType leafType = isArray.getLeafType();
- if (leafType.isPrimitive() != null) {
- serializableTypes.add(isArray);
- mti.setSerializable(true);
- mti.setMaybeInstantiated(true);
- } else {
- List leafTypes = getSerializableTypesAssignableTo(leafType);
- List covariantLeafTypes = getAllTypesBetweenRootTypeAndSerializableLeaves(
- leafType.isClassOrInterface(), leafTypes);
-
- Iterator iter = covariantLeafTypes.iterator();
- while (iter.hasNext()) {
- JClassType clazz = (JClassType) iter.next();
- JArrayType covariantArray = getArrayType(typeOracle,
- isArray.getRank(), clazz);
- serializableTypes.add(covariantArray);
-
- MetaTypeInfo cmti = getMetaTypeInfo(covariantArray);
- cmti.setSerializable(true);
- cmti.setMaybeInstantiated(true);
- }
- }
- } else if (isParameterized != null) {
- // parameterized type
- JType[] typeArgs = isParameterized.getTypeArgs();
- boolean failed = false;
- for (int i = 0; i < typeArgs.length && !failed; ++i) {
- JType typeArg = typeArgs[i];
- failed = (getSerializableTypesAssignableTo(typeArg).size() == 0);
- }
-
- if (!failed) {
- serializableTypes = getSerializableTypesAssignableTo(isParameterized.getRawType());
- }
- } else if (isClassOrInterface != null) {
- // class or interface
- if (getMetaTypeInfo(type).isSerializable()) {
- serializableTypes.add(type);
- }
-
- JClassType[] subtypes = isClassOrInterface.getSubtypes();
for (int i = 0; i < subtypes.length; ++i) {
- JClassType subtype = subtypes[i];
- if (getMetaTypeInfo(subtype).isSerializable()) {
- serializableTypes.add(subtype);
+ JClassType subType = subtypes[i];
+ if (checkClassOrInterfaceInstantiable(subLogger, subType, true)) {
+ getTypeInfoComputed(subType).setInstantiable(true);
+ anySubtypes = true;
}
}
-
- } else {
- assert (isPrimitive != null && isPrimitive != JPrimitiveType.VOID);
- serializableTypes.add(type);
}
- mti.setSerializableTypesAssignableToMe(serializableTypes);
+ if (!anySubtypes && !isSpeculative) {
+ logger.log(
+ getLogLevel(isSpeculative),
+ "Type '"
+ + type.getParameterizedQualifiedSourceName()
+ + "' was not serializable and has no concrete serializable subtypes",
+ null);
+ }
+ return anySubtypes;
+ } else {
+ assert (false);
+ return false;
}
+ }
- return serializableTypes;
+ private TypeInfo getTypeInfo(JClassType type) {
+ TypeInfo ti = (TypeInfo) typeToTypeInfo.get(type);
+ if (ti == null) {
+ ti = new TypeInfo(type);
+ typeToTypeInfo.put(type, ti);
+ }
+ return ti;
+ }
+
+ private TypeInfoComputed getTypeInfoComputed(JType type) {
+ TypeInfoComputed tic = (TypeInfoComputed) typeToTypeInfoComputed.get(type);
+ if (tic == null) {
+ tic = new TypeInfoComputed(type);
+ typeToTypeInfoComputed.put(type, tic);
+ }
+ return tic;
}
private void initializeProperties(TreeLogger logger,
@@ -1253,28 +1060,6 @@
}
/**
- * Returns <code>true</code> if the type which caused us to analyze the
- * current type uses manual serialization.
- *
- * @return <code>true</code> if the type which caused us to analyze the
- * current type uses manual serialization
- */
- private boolean inManualSerializationContext() {
- if (typesBeingAnalyzed.isEmpty()) {
- return false;
- }
-
- JType parent = (JType) typesBeingAnalyzed.peek();
- JClassType parentClass = parent.isClassOrInterface();
-
- if (parentClass != null) {
- return getMetaTypeInfo(parentClass).qualifiesForManualSerialization();
- }
-
- return false;
- }
-
- /**
* Returns <code>true</code> if the type is defined by the JRE.
*/
private boolean isDefinedInJREEmulation(JClassType type) {
@@ -1286,39 +1071,30 @@
return false;
}
- private void logReasonsForUnserializability(TreeLogger logger,
- MetaTypeInfo mti) {
- Set /* <SerializationIssue> */serializationIssues = mti.getSerializationIssues();
- Iterator iter = serializationIssues.iterator();
+ private void markAsUninstantiableAndLog(TreeLogger logger,
+ boolean isSpeculative, List es, TypeInfoComputed tic) {
+ Iterator iter = es.iterator();
while (iter.hasNext()) {
- MetaTypeInfo.SerializationIssue serializationIssue = (MetaTypeInfo.SerializationIssue) iter.next();
- logger.branch(serializationIssue.issueType,
- serializationIssue.issueMessage, null);
+ markAsUninstantiableAndLog(logger, isSpeculative, (String) iter.next(),
+ tic);
}
}
- private void markAsUnserializableAndLog(TreeLogger logger,
- TreeLogger.Type logType, List failures, MetaTypeInfo mti) {
- Iterator iter = failures.iterator();
- while (iter.hasNext()) {
- markAsUnserializableAndLog(logger, logType, (String) iter.next(), mti);
- }
+ private void markAsUninstantiableAndLog(TreeLogger logger,
+ boolean isSpeculative, String logMessage, TypeInfoComputed tic) {
+ tic.setInstantiable(false);
+ tic.addSerializationIssue(isSpeculative, logMessage);
+ logger.branch(getLogLevel(isSpeculative), logMessage, null);
}
- private void markAsUnserializableAndLog(TreeLogger logger,
- TreeLogger.Type logType, String logMessage, MetaTypeInfo mti) {
- mti.setState(SerializableTypeOracleBuilder.CHECK_FAILED);
- mti.setSerializable(false);
- mti.addSerializationIssue(logType, logMessage);
- logger.branch(logType, logMessage, null);
- }
-
- private void validateRemoteService(TreeLogger logger, JClassType remoteService) {
+ private void validateRemoteService(TreeLogger logger, JClassType remoteService)
+ throws UnableToCompleteException {
JMethod[] methods = remoteService.getOverridableMethods();
TreeLogger validationLogger = logger.branch(TreeLogger.DEBUG,
"Analyzing methods:", null);
+ boolean allSucceeded = true;
for (int i = 0; i < methods.length; ++i) {
JMethod method = methods[i];
TreeLogger methodLogger = validationLogger.branch(TreeLogger.DEBUG,
@@ -1328,7 +1104,8 @@
TreeLogger returnTypeLogger = methodLogger.branch(TreeLogger.DEBUG,
"Return type: " + returnType.getParameterizedQualifiedSourceName(),
null);
- checkTypeRoot(returnTypeLogger, returnType, true);
+ allSucceeded &= checkTypeInstantiable(returnTypeLogger, returnType,
+ false, false);
}
JParameter[] params = method.getParameters();
@@ -1337,7 +1114,8 @@
TreeLogger paramLogger = methodLogger.branch(TreeLogger.DEBUG,
"Parameter: " + param.toString(), null);
JType paramType = param.getType();
- checkTypeRoot(paramLogger, paramType, true);
+ allSucceeded &= checkTypeInstantiable(paramLogger, paramType, false,
+ false);
}
JType[] exs = method.getThrows();
@@ -1355,9 +1133,15 @@
null);
}
- checkTypeRoot(throwsLogger, ex, true);
+ allSucceeded &= checkTypeInstantiable(throwsLogger, ex, false, false);
}
}
}
+
+ if (!allSucceeded) {
+ // the validation code has already logged why
+ throw new UnableToCompleteException();
+ }
}
+
}
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java
index f775a69..19ab5e3 100644
--- a/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java
@@ -40,14 +40,24 @@
}
/**
+ * This class is here to make the code generator think that there is at least
+ * one serializable subclass of the AnonymousClassInterface.
+ */
+ public static class AnonymousClassInterfaceImplementor implements
+ AnonymousClassInterface {
+ public void foo() {
+ }
+ }
+
+ /**
* TODO: document me.
*/
public static class Circle extends Shape {
private String name;
public native void doStuff() /*-{
- alert("foo");
- }-*/;
+ alert("foo");
+ }-*/;
}
/**
@@ -79,15 +89,6 @@
}
/**
- * This class is here to make the code generator think that there is atleast
- * on serializable subclass of the AnonymousClassInterface
- */
- public static class MyClass implements AnonymousClassInterface {
- public void foo() {
- }
- }
-
- /**
* Used to test <a
* href="http://code.google.com/p/google-web-toolkit/issues/detail?id=1163">Issue
* 1163</a>.
@@ -105,6 +106,14 @@
}
/**
+ * This class is here to make the code generator think that there is at least
+ * one serializable subclass of the MySerializableInterfaceSubtype.
+ */
+ public static class MySerializableInterfaceSubtypeImplementor implements
+ MySerializableInterfaceSubtype {
+ }
+
+ /**
* TODO: document me.
*/
public static class SerializableClass implements IsSerializable {
diff --git a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
index d16f8fc..97b1bbf 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
@@ -228,11 +228,12 @@
* Tests that a method signature which has no serializable types will result
* in a failure.
*/
- public void testNoSerializableTypes() throws NotFoundException {
+ public void testNoSerializableTypes() throws NotFoundException,
+ UnableToCompleteException {
+ JClassType testServiceClass = typeOracle.getType(NoSerializableTypes.class.getName());
+ SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+ logger, typeOracle);
try {
- JClassType testServiceClass = typeOracle.getType(NoSerializableTypes.class.getName());
- SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
- logger, typeOracle);
stob.build(propertyOracle, testServiceClass);
fail("Should have thrown an UnableToCompleteException");
} catch (UnableToCompleteException ex) {
@@ -267,11 +268,12 @@
/**
* Tests that a method signature which only has Object in its signature fails.
*/
- public void testObjectArrayInMethodSignature() throws NotFoundException {
+ public void testObjectArrayInMethodSignature() throws NotFoundException,
+ UnableToCompleteException {
JClassType testServiceClass = typeOracle.getType(ObjectArrayInMethodSignature.class.getName());
- SerializableTypeOracleBuilder stob;
+ SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+ logger, typeOracle);
try {
- stob = new SerializableTypeOracleBuilder(logger, typeOracle);
stob.build(propertyOracle, testServiceClass);
fail("Expected UnableToCompleteException");
} catch (UnableToCompleteException e) {
@@ -282,11 +284,12 @@
/**
* Tests that a method signature which only has Object in its signature fails.
*/
- public void testObjectInMethodSignature() throws NotFoundException {
+ public void testObjectInMethodSignature() throws NotFoundException,
+ UnableToCompleteException {
JClassType testServiceClass = typeOracle.getType(ObjectInMethodSignature.class.getName());
- SerializableTypeOracleBuilder stob;
+ SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+ logger, typeOracle);
try {
- stob = new SerializableTypeOracleBuilder(logger, typeOracle);
stob.build(propertyOracle, testServiceClass);
fail("Expected UnableToCompleteException");
} catch (UnableToCompleteException e) {
@@ -296,7 +299,7 @@
/**
* Tests that a method signature which only has abstract serializable types
- * does not fail.
+ * fails.
*/
public void testOnlyAbstractSerializableTypes()
throws UnableToCompleteException, NotFoundException {
@@ -304,12 +307,11 @@
JClassType testServiceClass = typeOracle.getType(AbstractSerializableTypes.class.getName());
SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
logger, typeOracle);
- SerializableTypeOracle sto = stob.build(propertyOracle, testServiceClass);
- TypeInfo[] expected = new TypeInfo[] {
- new TypeInfo(IncompatibleRemoteServiceException.class.getName(), true),
- new TypeInfo(AbstractSerializableTypes.AbstractClass.class.getName(),
- false), new TypeInfo(String.class.getName(), true)};
-
- validateSTO(sto, expected);
+ try {
+ stob.build(propertyOracle, testServiceClass);
+ fail("Expected UnableToCompleteException");
+ } catch (UnableToCompleteException e) {
+ // Should get here
+ }
}
}
diff --git a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/AbstractSerializableTypes.java b/user/test/com/google/gwt/user/rebind/rpc/testcases/client/AbstractSerializableTypes.java
index 8fafd7a..8eec178 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/AbstractSerializableTypes.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/testcases/client/AbstractSerializableTypes.java
@@ -26,13 +26,13 @@
*/
public interface AbstractSerializableTypes extends RemoteService {
/**
- * Regular interface
+ * Regular interface.
*/
interface IFoo extends IsSerializable {
}
/**
- * Abstract class
+ * Abstract class.
*/
abstract class AbstractClass implements IsSerializable {
}
diff --git a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/CovariantArrays.java b/user/test/com/google/gwt/user/rebind/rpc/testcases/client/CovariantArrays.java
index 792a1ba..f4f5c6b 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/CovariantArrays.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/testcases/client/CovariantArrays.java
@@ -51,7 +51,7 @@
}
/**
- * Not auto serializable due to bad field
+ * Not auto serializable due to bad field.
*/
class C extends B {
Object field;