Allows owner class to provide a parameterized type.
Fixes incorrect direction of isAssignable check when using @UiField(provided = true)
Also deletes some unused code: declareDomField no longer uses its element param, because ensureCurrentFieldAttached no longer uses its arg, etc.
Review at http://gwt-code-reviews.appspot.com/359801
Review by: jgw@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7940 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/FieldInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/FieldInterpreter.java
index 8c2f3c1..4e7f502 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/FieldInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/FieldInterpreter.java
@@ -37,7 +37,7 @@
throws UnableToCompleteException {
String fieldName = writer.declareFieldIfNeeded(elem);
if (fieldName != null) {
- String token = writer.declareDomField(fieldName, element);
+ String token = writer.declareDomField(fieldName);
if (elem.hasAttribute("id")) {
writer.die(String.format(
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/WidgetInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/WidgetInterpreter.java
index 686cb2a..225133b 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/WidgetInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/WidgetInterpreter.java
@@ -75,7 +75,7 @@
// we'll reuse ids for any template rendered more than once.
String idHolder = uiWriter.declareDomIdHolder();
String childField = uiWriter.parseElementToField(elem);
- uiWriter.ensureFieldAttached(fieldName);
+ uiWriter.ensureCurrentFieldAttached();
String elementPointer = idHolder + "Element";
uiWriter.addInitStatement(
diff --git a/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java b/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
index 912c5b7..c61f284 100644
--- a/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
@@ -71,21 +71,6 @@
}
public void setInitializer(String initializer) {
- if (this.initializer != null) {
- throw new IllegalStateException(String.format(
- "Second attempt to set initializer for field \"%s\", "
- + "from \"%s\" to \"%s\"", name, this.initializer, initializer));
- }
- setInitializerMaybe(initializer);
- }
-
- @Deprecated
- public void setInitializerMaybe(String initializer) {
- if (this.initializer != null && !this.initializer.equals(initializer)) {
- throw new IllegalStateException(String.format(
- "Attempt to change initializer for field \"%s\", "
- + "from \"%s\" to \"%s\"", name, this.initializer, initializer));
- }
this.initializer = initializer;
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
index 95e81aa..77456d5 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
@@ -74,9 +74,6 @@
* Used to provide an initializer string to use instead of a
* {@link com.google.gwt.core.client.GWT#create()} call. Note that this is an
* RHS expression. Don't include the leading '=', and don't end it with ';'.
- * <p>
- * TODO(rjrjr) Should be able to make this a constructor argument when
- * BundleAttributeParser dies.
*
* @throws UnableToCompleteException
* @throws IllegalStateException on second attempt to set the initializer
@@ -84,16 +81,6 @@
void setInitializer(String initializer);
/**
- * @deprecated needed only by
- * {@link com.google.gwt.uibinder.attributeparsers.BundleAttributeParser}
- * , which will die soon
- * @throws IllegalStateException if initializer in a later call doesn't match
- * earlier call
- */
- @Deprecated
- void setInitializerMaybe(String initializer);
-
- /**
* Write the field delcaration.
*/
void write(IndentedWriter w) throws UnableToCompleteException;
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java
index bf2b7f0..b7aa445 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java
@@ -16,6 +16,7 @@
package com.google.gwt.uibinder.rebind;
import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JGenericType;
/**
* Implementation of FieldWriter for fields whose type already exists (that is,
@@ -31,6 +32,12 @@
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}
+
+ JGenericType genericType = type.isGenericType();
+ if (genericType != null) {
+ type = genericType.getRawType();
+ }
+
this.type = type;
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index a013d27..53e7466 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -129,8 +129,7 @@
* @param type the base type
* @return a breadth-first collection of its type hierarchy
*/
- static Iterable<JClassType> getClassHierarchyBreadthFirst(
- JClassType type) {
+ static Iterable<JClassType> getClassHierarchyBreadthFirst(JClassType type) {
LinkedList<JClassType> list = new LinkedList<JClassType>();
LinkedList<JClassType> q = new LinkedList<JClassType>();
@@ -324,13 +323,10 @@
* call and assign the Element instance to its field.
*
* @param fieldName The name of the field being declared
- * @param parentElementExpression an expression to be evaluated at runtime,
- * which will return an Element that is an ancestor of this one
- * (needed by the getElementById call mentioned above).
*/
- public String declareDomField(String fieldName, String parentElementExpression)
+ public String declareDomField(String fieldName)
throws UnableToCompleteException {
- ensureAttached(parentElementExpression);
+ ensureAttached();
String name = declareDomIdHolder();
setFieldInitializer(fieldName, "null");
addInitStatement(
@@ -444,10 +440,9 @@
/**
* Ensure that the specified element is attached to the DOM.
*
- * @param element variable name of element to be attached
* @see #beginAttachedSection(String)
*/
- public void ensureAttached(String element) {
+ public void ensureAttached() {
String attachSectionElement = attachSectionElements.getFirst();
if (!attachedVars.containsKey(attachSectionElement)) {
String attachedVar = "attachRecord" + nextAttachVar;
@@ -464,11 +459,10 @@
* an object that responds to Element getElement(). Convenience wrapper for
* {@link ensureAttached}<code>(field + ".getElement()")</code>.
*
- * @param field variable name of the field to be attached
* @see #beginAttachedSection(String)
*/
- public void ensureFieldAttached(String field) {
- ensureAttached(field + ".getElement()");
+ public void ensureCurrentFieldAttached() {
+ ensureAttached();
}
/**
@@ -723,7 +717,7 @@
*
* @throws UnableToCompleteException
*/
- private void ensureAttachmentCleanedUp() throws UnableToCompleteException {
+ private void ensureAttachmentCleanedUp() {
if (!attachSectionElements.isEmpty()) {
throw new IllegalStateException("Attachments not cleaned up: "
+ attachSectionElements);
@@ -856,15 +850,34 @@
throws UnableToCompleteException {
JClassType fieldType = ownerField.getType().getRawType();
- if (!templateClass.isAssignableTo(fieldType)) {
- die("Template field and owner field types don't match: %s != %s",
- templateClass.getQualifiedSourceName(),
- fieldType.getQualifiedSourceName());
- }
-
if (!ownerField.isProvided()) {
+ /*
+ * Normally check that the type the template created can be slammed into
+ * the @UiField annotated field in the owning class
+ */
+ if (!templateClass.isAssignableTo(fieldType)) {
+ die(
+ "In @UiField %s, template field and owner field types don't match: %s is not assignable to %s",
+ ownerField.getName(), templateClass.getQualifiedSourceName(),
+ fieldType.getQualifiedSourceName());
+ }
+ /*
+ * And initialize the field
+ */
niceWriter.write("owner.%1$s = %2$s;", ownerField.getName(),
templateField);
+ } else {
+ /*
+ * But with @UiField(provided=true) the user builds it, so reverse the
+ * direction of the assignability check and do no init.
+ */
+ if (!fieldType.isAssignableTo(templateClass)) {
+ die(
+ "In UiField(provided = true) %s, template field and field types don't match: "
+ + "@UiField(provided=true)%s is not assignable to %s",
+ ownerField.getName(), fieldType.getQualifiedSourceName(),
+ templateClass.getQualifiedSourceName());
+ }
}
}
@@ -979,7 +992,8 @@
// createAndBindUi method
w.write("public %s createAndBindUi(final %s owner) {",
- uiRootType.getParameterizedQualifiedSourceName(), uiOwnerType.getParameterizedQualifiedSourceName());
+ uiRootType.getParameterizedQualifiedSourceName(),
+ uiOwnerType.getParameterizedQualifiedSourceName());
w.indent();
w.newline();
@@ -1010,7 +1024,9 @@
private void writeClassOpen(IndentedWriter w) {
w.write("public class %s implements UiBinder<%s, %s>, %s {", implClassName,
- uiRootType.getParameterizedQualifiedSourceName(), uiOwnerType.getParameterizedQualifiedSourceName(), baseClass.getParameterizedQualifiedSourceName());
+ uiRootType.getParameterizedQualifiedSourceName(),
+ uiOwnerType.getParameterizedQualifiedSourceName(),
+ baseClass.getParameterizedQualifiedSourceName());
w.indent();
}
@@ -1039,11 +1055,9 @@
String fieldName = ownerField.getName();
FieldWriter fieldWriter = fieldManager.lookup(fieldName);
- // TODO(hermes) This can be null due to http://b/1836504. If that
- // is fixed properly, a null fieldWriter will be an error
- // (would that be a user error or a runtime error? Not sure)
+ // TODO why can this be null?
if (fieldWriter != null) {
- fieldManager.lookup(fieldName).setInitializerMaybe(
+ fieldManager.lookup(fieldName).setInitializer(
formatCode("owner.%1$s", fieldName));
}
}
diff --git a/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.java b/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.java
index d31db80..1a6213c 100644
--- a/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.java
+++ b/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.java
@@ -31,16 +31,16 @@
static final Binder binder = GWT.create(Binder.class);
- @UiField
- Abstract<?> a;
-
+ @UiField Abstract<?> fromFactory;
+ @UiField(provided = true) Specific<T> provided = new Specific<T>();
+
ParameterizedWidget() {
initWidget(binder.createAndBindUi(this));
}
@UiFactory
- Abstract<?> createA() {
- return new Abstract<String>() {
+ Abstract<T> createA() {
+ return new Abstract<T>() {
};
}
}
diff --git a/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.ui.xml b/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.ui.xml
index 5a707f8..0c6fe45 100644
--- a/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/ParameterizedWidget.ui.xml
@@ -1,4 +1,8 @@
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
- xmlns:t="urn:import:com.google.gwt.uibinder.test.client">
- <t:Abstract ui:field='a'></t:Abstract>
-</ui:UiBinder>
\ No newline at end of file
+ xmlns:g="urn:import:com.google.gwt.user.client.ui"
+ xmlns:t="urn:import:com.google.gwt.uibinder.test.client">
+ <g:FlowPanel>
+ <t:Abstract ui:field='fromFactory' />
+ <t:Abstract ui:field='provided' />
+ </g:FlowPanel>
+</ui:UiBinder>
diff --git a/user/test/com/google/gwt/uibinder/test/client/Specific.java b/user/test/com/google/gwt/uibinder/test/client/Specific.java
new file mode 100644
index 0000000..dbeb021
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/Specific.java
@@ -0,0 +1,26 @@
+/*
+ * 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.uibinder.test.client;
+
+/**
+ * A specific implementation of {@link Abstract}, used to test generics in
+ * UiBinder. See {@link ParameterizedWidget}.
+ *
+ * @param <T> a param type
+ */
+public class Specific<T> extends Abstract<T> {
+
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/TestParameterizedWidgets.java b/user/test/com/google/gwt/uibinder/test/client/TestParameterizedWidgets.java
index 249c3db..398c95a 100644
--- a/user/test/com/google/gwt/uibinder/test/client/TestParameterizedWidgets.java
+++ b/user/test/com/google/gwt/uibinder/test/client/TestParameterizedWidgets.java
@@ -28,6 +28,6 @@
public void testHappy() {
ParameterizedWidget<String> ui = new ParameterizedWidget<String>();
- assertNotNull(ui.a);
+ assertNotNull(ui.fromFactory);
}
}