Ensure that enum types reachable through AutoBean method parameterizations are included in the EnumMap.
Patch by: bobv
Review by: jbrosenberg
Review at http://gwt-code-reviews.appspot.com/1240801
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9482 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java
index c73ef79..9268c26 100644
--- a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java
+++ b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java
@@ -249,7 +249,7 @@
AutoBeanMethod toAdd = builder.build();
// Collect referenced enums
- if (toAdd.isEnum()) {
+ if (toAdd.hasEnumMap()) {
allEnumConstants.putAll(toAdd.getEnumMap());
}
diff --git a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java
index f9b2d0d..0362aea 100644
--- a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java
+++ b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java
@@ -21,6 +21,7 @@
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
+import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.editor.rebind.model.ModelUtils;
@@ -158,40 +159,29 @@
toReturn.method = method;
TypeOracle oracle = method.getEnclosingType().getOracle();
- toReturn.isValueType = ModelUtils.isValueType(oracle,
- method.getReturnType());
+ JType returnType = method.getReturnType();
+ toReturn.isValueType = ModelUtils.isValueType(oracle, returnType);
if (!toReturn.isValueType) {
// See if it's a collection or a map
- JClassType returnClass = method.getReturnType().isClassOrInterface();
+ JClassType returnClass = returnType.isClassOrInterface();
JClassType collectionInterface = oracle.findType(Collection.class.getCanonicalName());
JClassType mapInterface = oracle.findType(Map.class.getCanonicalName());
if (collectionInterface.isAssignableFrom(returnClass)) {
JClassType[] parameterizations = ModelUtils.findParameterizationOf(
collectionInterface, returnClass);
toReturn.elementType = parameterizations[0];
+ maybeProcessEnumType(toReturn.elementType);
} else if (mapInterface.isAssignableFrom(returnClass)) {
JClassType[] parameterizations = ModelUtils.findParameterizationOf(
mapInterface, returnClass);
toReturn.keyType = parameterizations[0];
toReturn.valueType = parameterizations[1];
+ maybeProcessEnumType(toReturn.keyType);
+ maybeProcessEnumType(toReturn.valueType);
}
- }
-
- JEnumType enumType = method.getReturnType().isEnum();
- if (enumType != null) {
- Map<JEnumConstant, String> map = new LinkedHashMap<JEnumConstant, String>();
- for (JEnumConstant e : enumType.getEnumConstants()) {
- String name;
- PropertyName annotation = e.getAnnotation(PropertyName.class);
- if (annotation == null) {
- name = e.getName();
- } else {
- name = annotation.value();
- }
- map.put(e, name);
- }
- toReturn.enumMap = map;
+ } else {
+ maybeProcessEnumType(returnType);
}
}
@@ -202,6 +192,39 @@
public void setStaticImp(JMethod staticImpl) {
toReturn.staticImpl = staticImpl;
}
+
+ /**
+ * Call {@link #processEnumType(JEnumType)} if {@code type} is a
+ * {@link JEnumType}.
+ */
+ private void maybeProcessEnumType(JType type) {
+ assert type != null : "type == null";
+ JEnumType enumType = type.isEnum();
+ if (enumType != null) {
+ processEnumType(enumType);
+ }
+ }
+
+ /**
+ * Adds a JEnumType to the AutoBeanMethod's enumMap so that the
+ * AutoBeanFactoryGenerator can embed extra metadata about the enum values.
+ */
+ private void processEnumType(JEnumType enumType) {
+ Map<JEnumConstant, String> map = toReturn.enumMap;
+ if (map == null) {
+ map = toReturn.enumMap = new LinkedHashMap<JEnumConstant, String>();
+ }
+ for (JEnumConstant e : enumType.getEnumConstants()) {
+ String name;
+ PropertyName annotation = e.getAnnotation(PropertyName.class);
+ if (annotation == null) {
+ name = e.getName();
+ } else {
+ name = annotation.value();
+ }
+ map.put(e, name);
+ }
+ }
}
private Action action;
@@ -255,12 +278,12 @@
return valueType;
}
- public boolean isCollection() {
- return elementType != null;
+ public boolean hasEnumMap() {
+ return enumMap != null;
}
- public boolean isEnum() {
- return enumMap != null;
+ public boolean isCollection() {
+ return elementType != null;
}
public boolean isMap() {
diff --git a/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java b/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java
index 027d454..348dfe3 100644
--- a/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java
+++ b/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java
@@ -49,6 +49,22 @@
AutoBean<Simple> simple();
}
+ /*
+ * These enums are used to verify that a List<Enum> or Map<Enum, Enum> pulls
+ * in the necessary metadata.
+ */
+ enum EnumReachableThroughList {
+ FOO_LIST
+ }
+
+ enum EnumReachableThroughMapKey {
+ FOO_KEY
+ }
+
+ enum EnumReachableThroughMapValue {
+ FOO_VALUE
+ }
+
interface HasAutoBean {
Splittable getSimple();
@@ -79,6 +95,10 @@
Map<MyEnum, Integer> getMap();
+ List<EnumReachableThroughList> getParameterizedList();
+
+ Map<EnumReachableThroughMapKey, EnumReachableThroughMapValue> getParameterizedMap();
+
void setEnum(MyEnum value);
void setEnums(List<MyEnum> value);
@@ -157,13 +177,6 @@
assertTrue(decodedBean.as().getList().isEmpty());
}
- private <T> AutoBean<T> checkEncode(AutoBean<T> bean) {
- Splittable split = AutoBeanCodex.encode(bean);
- AutoBean<T> decoded = AutoBeanCodex.decode(f, bean.getType(), split);
- assertTrue(AutoBeanUtils.deepEquals(bean, decoded));
- return decoded;
- }
-
public void testEnum() {
EnumMap map = (EnumMap) f;
assertEquals("BAR", map.getToken(MyEnum.BAR));
@@ -192,6 +205,24 @@
assertEquals(mapValue, decoded.as().getMap());
}
+ /**
+ * Ensures that enum types that are reachable only through a method
+ * parameterization are included in the enum map.
+ */
+ public void testEnumReachableOnlyThroughParameterization() {
+ EnumMap map = (EnumMap) f;
+ assertEquals("FOO_LIST", map.getToken(EnumReachableThroughList.FOO_LIST));
+ assertEquals("FOO_KEY", map.getToken(EnumReachableThroughMapKey.FOO_KEY));
+ assertEquals("FOO_VALUE",
+ map.getToken(EnumReachableThroughMapValue.FOO_VALUE));
+ assertEquals(EnumReachableThroughList.FOO_LIST,
+ map.getEnum(EnumReachableThroughList.class, "FOO_LIST"));
+ assertEquals(EnumReachableThroughMapKey.FOO_KEY,
+ map.getEnum(EnumReachableThroughMapKey.class, "FOO_KEY"));
+ assertEquals(EnumReachableThroughMapValue.FOO_VALUE,
+ map.getEnum(EnumReachableThroughMapValue.class, "FOO_VALUE"));
+ }
+
public void testMap() {
AutoBean<HasMap> bean = f.hasMap();
Map<String, Simple> map = new HashMap<String, Simple>();
@@ -291,4 +322,11 @@
protected void gwtSetUp() throws Exception {
f = GWT.create(Factory.class);
}
+
+ private <T> AutoBean<T> checkEncode(AutoBean<T> bean) {
+ Splittable split = AutoBeanCodex.encode(bean);
+ AutoBean<T> decoded = AutoBeanCodex.decode(f, bean.getType(), split);
+ assertTrue(AutoBeanUtils.deepEquals(bean, decoded));
+ return decoded;
+ }
}