Revert "Dramatically improves generics support in UiBinder." This reverts commit ba30ecd58ec03a7009ed17e6863a41d01a946828. This breaks existing use case with local type variables (e.g. <T> T createX()) due to a bug in Class#isAssignableFrom. I will try again later. Change-Id: I2965cc49953b90f03a70d43bfdbaf3326e902778
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java b/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java index 7a8f593..5e1e6a0 100644 --- a/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java +++ b/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java
@@ -140,7 +140,7 @@ writer.die(elem, "Duplicate attribute name: %s", propertyName); } - if (unfilledRequiredParams.containsKey(propertyName)) { + if (unfilledRequiredParams.keySet().contains(propertyName)) { JType paramType = unfilledRequiredParams.get(propertyName); String value = elem.consumeAttributeWithDefault(attribute.getName(), null, paramType);
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldReference.java b/user/src/com/google/gwt/uibinder/rebind/FieldReference.java index 1de4f3d..3092525 100644 --- a/user/src/com/google/gwt/uibinder/rebind/FieldReference.java +++ b/user/src/com/google/gwt/uibinder/rebind/FieldReference.java
@@ -53,7 +53,7 @@ } else if (i > 0) { b.append(", "); } - b.append(types[i]); + b.append(types[i].getQualifiedSourceName()); } return b.toString(); @@ -139,7 +139,7 @@ for (JType leftType : left.types) { - if (leftType.equals(rightHandType)) { + if (leftType == rightHandType) { return; } @@ -178,7 +178,7 @@ * fact, which will halt processing. */ logger.error(left.source, "%s required, but %s returns %s", renderTypesList(left.types), - FieldReference.this, rightHandType); + FieldReference.this, rightHandType.getQualifiedSourceName()); } private boolean handleMismatchedNonNumericPrimitives(JType leftType, JType rightHandType,
diff --git a/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java b/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java index 0078d66..a2fd077 100644 --- a/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java +++ b/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java
@@ -25,6 +25,7 @@ import com.google.gwt.event.shared.EventHandler; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.uibinder.rebind.model.OwnerClass; +import com.google.gwt.uibinder.rebind.model.OwnerField; import com.google.web.bindery.event.shared.HandlerRegistration; /** @@ -154,6 +155,9 @@ + "in the template."), boundMethod, objectName); } JClassType objectType = fieldWriter.getInstantiableType(); + if (objectType.isGenericType() != null) { + objectType = tryEnhancingTypeInfo(objectName, objectType); + } // Retrieves the "add handler" method in the object. JMethod addHandlerMethodType = getAddHandlerMethodForObject(objectType, handlerType); @@ -169,6 +173,23 @@ } } + private JClassType tryEnhancingTypeInfo(String objectName, JClassType objectType) { + OwnerField uiField = ownerClass.getUiField(objectName); + if (uiField != null) { + JParameterizedType pType = uiField.getRawType().isParameterized(); + if (pType != null) { + // Even field is parameterized, it might be a super class. In that case, if we use the field + // type then we might miss some add handlers methods from the objectType itself; something + // we don't want to happen! + if (pType.getBaseType().equals(objectType)) { + // Now we proved type from UiField is more specific, let's use that one + return pType; + } + } + } + return objectType; + } + /** * Writes a handler entry using the given writer. *
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java index 3a9ccb0..f94ca7f 100644 --- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java +++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -917,15 +917,8 @@ // Get the class associated with this element. JClassType type = findFieldType(elem); - - // If the element has a name then let's try enhancing the type info. - String fieldName = getFieldName(elem); - if (fieldName != null) { - type = tryEnhancingTypeInfo(fieldName, type); - } - // Declare its field. - FieldWriter field = declareField(elem, type, fieldName); + FieldWriter field = declareField(elem, type.getQualifiedSourceName()); /* * Push the field that will hold this widget on top of the parsedFieldStack @@ -1093,10 +1086,17 @@ /** * Declares a field of the given type name, returning the name of the declared - * field. If {@code fieldName} is {@code null}, it will be generated. + * field. If the element has a field or id attribute, use its value. + * Otherwise, create and return a new, private field name for it. */ - private FieldWriter declareField(XMLElement source, JClassType type, String fieldName) + private FieldWriter declareField(XMLElement source, String typeName) throws UnableToCompleteException { + JClassType type = oracle.findType(typeName); + if (type == null) { + die(source, "Unknown type %s", typeName); + } + + String fieldName = getFieldName(source); if (fieldName == null) { // TODO(rjrjr) could collide with user declared name, as is // also a worry in HandlerEvaluator. Need a general scheme for @@ -1108,28 +1108,6 @@ return fieldManager.registerField(type, fieldName); } - /** - * This method tries to improve the existing type information by looking at the ui field. - * declaration. (Although the ui.xml cannot define the type parameters for generic types, the - * field declaration itself inside the class might include this information.) - */ - private JClassType tryEnhancingTypeInfo(String fieldName, JClassType fieldType) { - OwnerField uiField = ownerClass.getUiField(fieldName); - if (uiField != null) { - JParameterizedType pType = uiField.getRawType().isParameterized(); - if (pType != null) { - // Even if the field is parameterized, the type of the field might be a super class of the - // type declared in the xml. In that case, the new type would be less specific, we don't - // want that to happen: - if (pType.getBaseType().equals(fieldType)) { - // Now we proved type from UiField is more specific, let's use that one. - return pType; - } - } - } - return fieldType; - } - private void dieGettingEventTypeName(JMethod jMethod, Exception e) throws UnableToCompleteException { die("Could not obtain DomEvent.Type object for first parameter of %s (%s)",
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/OwnerClass.java b/user/src/com/google/gwt/uibinder/rebind/model/OwnerClass.java index ac7bc03..7a997ae 100644 --- a/user/src/com/google/gwt/uibinder/rebind/model/OwnerClass.java +++ b/user/src/com/google/gwt/uibinder/rebind/model/OwnerClass.java
@@ -32,7 +32,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.TreeMap; /** @@ -63,12 +62,6 @@ new HashMap<JClassType, JMethod>(); /** - * Map from raw type to the method that produces it. - */ - private final Map<JClassType, JMethod> uiFactoriesForRawTypes = - new HashMap<JClassType, JMethod>(); - - /** * List of all @UiHandler methods in the owner class. */ private final List<JMethod> uiHandlers = new ArrayList<JMethod>(); @@ -79,7 +72,6 @@ private final UiBinderContext context; - /** * Constructor. * @@ -93,7 +85,6 @@ this.context = context; findUiFields(ownerType); findUiFactories(ownerType); - findRawUiFactories(); findUiHandlers(ownerType); } @@ -113,26 +104,7 @@ forType = genericType.getRawType(); } - // Exact match - JMethod jMethod = uiFactories.get(forType); - - // If A<T>, A<String> or A<?> are queried, match to A as backward compatibility: - if (jMethod == null && forType.isParameterized() != null) { - jMethod = uiFactories.get(forType.getErasedType()); - } - - // If A or A<?> is queried, match to A<T>, A<String> etc. as it is a valid assignment: - if (jMethod == null && (forType.isRawType() != null || isParametrizedWithWildcard(forType))) { - jMethod = uiFactoriesForRawTypes.get(forType.getErasedType()); - } - - return jMethod; - } - - private static boolean isParametrizedWithWildcard(JClassType type) { - JParameterizedType parameterized = type.isParameterized(); - return parameterized != null - && parameterized.isAssignableFrom(parameterized.getBaseType().asParameterizedByWildcards()); + return uiFactories.get(forType); } /** @@ -178,13 +150,14 @@ } /** - * Scans the owner class to find all methods annotated with @UiFactory, and puts them in - * {@link #uiFactories}. + * Scans the owner class to find all methods annotated with @UiFactory, and + * puts them in {@link #uiFactories}. * * @param ownerType the type of the owner class * @throws UnableToCompleteException */ - private void findUiFactories(JClassType ownerType) throws UnableToCompleteException { + private void findUiFactories(JClassType ownerType) + throws UnableToCompleteException { JMethod[] methods = ownerType.getMethods(); for (JMethod method : methods) { if (method.isAnnotationPresent(UiFactory.class)) { @@ -195,6 +168,11 @@ + method.getName()); } + JParameterizedType paramType = factoryType.isParameterized(); + if (paramType != null) { + factoryType = paramType.getRawType(); + } + if (uiFactories.containsKey(factoryType)) { logger.die("Duplicate factory in class " + method.getEnclosingType().getName() + " for type " @@ -212,15 +190,6 @@ } } - private void findRawUiFactories() { - for (Entry<JClassType, JMethod> entry : uiFactories.entrySet()) { - JParameterizedType parameterizedType = entry.getKey().isParameterized(); - if (parameterizedType != null) { - uiFactoriesForRawTypes.put(parameterizedType.getRawType(), entry.getValue()); - } - } - } - /** * Scans the owner class to find all fields annotated with @UiField, and puts * them in {@link #uiFields} and {@link #uiFieldTypes}.
diff --git a/user/test/com/google/gwt/uibinder/rebind/model/OwnerClassTest.java b/user/test/com/google/gwt/uibinder/rebind/model/OwnerClassTest.java index d72aea9..8e1293f 100644 --- a/user/test/com/google/gwt/uibinder/rebind/model/OwnerClassTest.java +++ b/user/test/com/google/gwt/uibinder/rebind/model/OwnerClassTest.java
@@ -20,9 +20,7 @@ import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JParameter; -import com.google.gwt.core.ext.typeinfo.JParameterizedType; import com.google.gwt.core.ext.typeinfo.JType; -import com.google.gwt.core.ext.typeinfo.JWildcardType.BoundType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.CompilerContext; import com.google.gwt.dev.javac.CompilationState; @@ -173,6 +171,20 @@ } }, new MockJavaResource( + "com.google.gwt.uibinder.rebind.model.WildcardWidgetFactory") { + @Override + public CharSequence getContent() { + StringBuffer code = new StringBuffer(); + code.append("package com.google.gwt.uibinder.rebind.model;\n"); + code.append("import com.google.gwt.uibinder.client.UiFactory;\n"); + code.append("public class WildcardWidgetFactory {"); + code.append(" @UiFactory"); + code.append(" Abstract<?> createOne() { return null; }"); + code.append("}\n"); + return code; + } + }, + new MockJavaResource( "com.google.gwt.uibinder.rebind.model.ParamterizedWidgetFactory") { @Override public CharSequence getContent() { @@ -195,8 +207,6 @@ code.append("import com.google.gwt.uibinder.client.UiFactory;\n"); code.append("public class TooManyGenerics {"); code.append(" @UiFactory"); - code.append(" Abstract create() { return null; }"); - code.append(" @UiFactory"); code.append(" Abstract<?> createSomething() { return null; }"); code.append(" @UiFactory"); code.append(" Abstract<String> createStringThing() { return null; }"); @@ -297,54 +307,36 @@ public void testParameterizedWidgets() throws UnableToCompleteException { JClassType ownerType = types.findType("com.google.gwt.uibinder.rebind.model.ParamterizedWidgetFactory"); JClassType abstractType = types.findType("com.google.gwt.uibinder.rebind.model.Abstract"); - JClassType abstractTypeWildcard = createParameterizedWithWildcard(abstractType); - JClassType abstractTypeString = createParameterizedWithString(abstractType); - JClassType abstractTypeObject = createParameterizedWithObject(abstractType); - OwnerClass ownerClass = new OwnerClass(ownerType, MortalLogger.NULL, uiBinderCtx); + OwnerClass ownerClass = new OwnerClass(ownerType, MortalLogger.NULL, + uiBinderCtx); JMethod expected = ownerType.findMethod("createOne", new JType[] {}); + JMethod uiFactoryMethod = ownerClass.getUiFactoryMethod(abstractType); - assertEquals(expected, ownerClass.getUiFactoryMethod(abstractType)); - assertEquals(expected, ownerClass.getUiFactoryMethod(abstractTypeWildcard)); - assertEquals(expected, ownerClass.getUiFactoryMethod(abstractTypeString)); - assertEquals(null, ownerClass.getUiFactoryMethod(abstractTypeObject)); + assertEquals(expected, uiFactoryMethod); } - public void testOwnerClass_uiFactoryWithMoreGenerics() - throws UnableToCompleteException { - JClassType ownerType = types.findType("com.google.gwt.uibinder.rebind.model.TooManyGenerics"); + public void testWildcardWidgets() throws UnableToCompleteException { + JClassType ownerType = types.findType("com.google.gwt.uibinder.rebind.model.WildcardWidgetFactory"); JClassType abstractType = types.findType("com.google.gwt.uibinder.rebind.model.Abstract"); - JClassType abstractTypeWildcard = createParameterizedWithWildcard(abstractType); - JClassType abstractTypeString = createParameterizedWithString(abstractType); - JClassType abstractTypeObject = createParameterizedWithObject(abstractType); - OwnerClass ownerClass = new OwnerClass(ownerType, MortalLogger.NULL, uiBinderCtx); + OwnerClass ownerClass = new OwnerClass(ownerType, MortalLogger.NULL, + uiBinderCtx); - JMethod expected; + JMethod expected = ownerType.findMethod("createOne", new JType[] {}); + JMethod uiFactoryMethod = ownerClass.getUiFactoryMethod(abstractType); - expected = ownerType.findMethod("create", new JType[] {}); - assertEquals(expected, ownerClass.getUiFactoryMethod(abstractType)); - assertEquals(expected, ownerClass.getUiFactoryMethod(abstractTypeObject)); - - expected = ownerType.findMethod("createSomething", new JType[] {}); - assertEquals(expected, ownerClass.getUiFactoryMethod(abstractTypeWildcard)); - - expected = ownerType.findMethod("createStringThing", new JType[] {}); - assertEquals(expected, ownerClass.getUiFactoryMethod(abstractTypeString)); + assertEquals(expected, uiFactoryMethod); } - private JParameterizedType createParameterizedWithString(JClassType abstractType) { - return types.getParameterizedType( - abstractType.isGenericType(), new JClassType[] {types.findType("java.lang.String")}); - } + public void testHowSuckyWeReallyAreWithGenerics() { + JClassType ownerType = types.findType("com.google.gwt.uibinder.rebind.model.TooManyGenerics"); - private JParameterizedType createParameterizedWithObject(JClassType abstractType) { - return types.getParameterizedType( - abstractType.isGenericType(), new JClassType[] {types.getJavaLangObject()}); - } - - private JParameterizedType createParameterizedWithWildcard(JClassType abstractType) { - return types.getParameterizedType(abstractType.isGenericType(), - new JClassType[] {types.getWildcardType(BoundType.UNBOUND, types.getJavaLangObject())}); + try { + new OwnerClass(ownerType, MortalLogger.NULL, uiBinderCtx); + fail(); + } catch (UnableToCompleteException e) { + /* pass */ + } } public void testOwnerClass_uiFactoryBadType() {
diff --git a/user/test/com/google/gwt/uibinder/test/client/Constants.java b/user/test/com/google/gwt/uibinder/test/client/Constants.java index 6cec350..4d3f017 100644 --- a/user/test/com/google/gwt/uibinder/test/client/Constants.java +++ b/user/test/com/google/gwt/uibinder/test/client/Constants.java
@@ -18,9 +18,6 @@ import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlUtils; -import java.util.Arrays; -import java.util.List; - /** * Used to test static imports in UiBinder templates. */ @@ -46,8 +43,6 @@ public static String CONST_FOO = "Foo"; - public static List<String> CONST_LIST = Arrays.asList("1", "2", "3"); - public SafeHtml getSafeHtml() { return SafeHtmlUtils.fromSafeConstant("<b>This text should be bold!</b>"); }
diff --git a/user/test/com/google/gwt/uibinder/test/client/MyValueListBox.java b/user/test/com/google/gwt/uibinder/test/client/MyValueListBox.java deleted file mode 100644 index bcf7133..0000000 --- a/user/test/com/google/gwt/uibinder/test/client/MyValueListBox.java +++ /dev/null
@@ -1,24 +0,0 @@ -/* - * Copyright 2013 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.uibinder.test.client; - -import com.google.gwt.user.client.ui.ValueListBox; - -/** - * A custom widget that add type parameter to its base class. - */ -class MyValueListBox extends ValueListBox<String> { -}
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java index 2fd12ba..84f1d77 100644 --- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java +++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
@@ -65,7 +65,6 @@ import com.google.gwt.user.client.ui.Tree; import com.google.gwt.user.client.ui.TreeItem; import com.google.gwt.user.client.ui.ValueLabel; -import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; import java.util.List; @@ -199,8 +198,8 @@ @UiField DateLabel myDateLabel3; @UiField NumberLabel<Float> myNumberLabel; @UiField NumberLabel<Float> myNumberLabel2; - @UiField(provided = true) - Renderer<Double> doubleRenderer = DoubleRenderer.instance(); + @UiField(provided = true) @SuppressWarnings("rawtypes") + Renderer doubleRenderer = DoubleRenderer.instance(); @UiField ValueLabel<Double> myValueLabel; @UiField DoubleBox myDoubleBox; @SuppressWarnings("rawtypes") @@ -213,7 +212,6 @@ @UiField HTML htmlWithComputedSafeHtml; @UiField HTML htmlWithComputedText; @UiField Label labelWithComputedText; - @UiField ValueListBox<String> myValueListBox; ValueChangeEvent<Double> doubleValueChangeEvent; @UiHandler("myDoubleBox")
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml index fd25232..5eea996 100644 --- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml +++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
@@ -84,10 +84,6 @@ Tests the static import of a single constant into the local namespace. </ui:import> -<ui:import field='com.google.gwt.uibinder.test.client.Constants.CONST_LIST'> - Tests the static import of a single constant with generics. -</ui:import> - <ui:import field='com.google.gwt.uibinder.test.client.Constants.Inner.*'> Tests the static import of multiple constants into the local namespace. </ui:import> @@ -702,9 +698,6 @@ <img src="{values.aUrl}" ui:field='myImage'/> - <gwt:ValueListBox ui:field="myValueListBox" acceptableValues="{CONST_LIST}" /> - <demo:MyValueListBox acceptableValues="{CONST_LIST}" /> - <gwt:HTML ui:field='htmlWithComputedSafeHtml'><ui:safehtml from="{constants.getSafeHtml}" /></gwt:HTML> <gwt:HTML ui:field='htmlWithComputedText'><ui:text from="{constants.getText}" /></gwt:HTML> <gwt:Label ui:field='labelWithComputedText'><ui:text from="{constants.getText}"/></gwt:Label>