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); } }