Revision: 10129
Author:   her...@google.com
Date:     Tue May  3 08:15:07 2011
Log: Promoting LazyDomElement to be used externally. LazyDomElement can be
used to boost rendering time. Today, html elements marked with
"ui:field" need to call getElementById() by the time the template is
created even if is not used. LazyDomElement delays this.

Review at http://gwt-code-reviews.appspot.com/1427809

http://code.google.com/p/google-web-toolkit/source/detail?r=10129

Added:
 /trunk/user/src/com/google/gwt/uibinder/client/LazyDomElement.java
/trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfLazyDomElement.java /trunk/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfExistingTypeTest.java /trunk/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfLazyDomElementTest.java
Modified:
 /trunk/user/src/com/google/gwt/uibinder/client/UiBinderUtil.java
/trunk/user/src/com/google/gwt/uibinder/elementparsers/WidgetInterpreter.java /trunk/user/src/com/google/gwt/uibinder/elementparsers/WidgetPlaceholderInterpreter.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriterType.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/model/OwnerField.java
 /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java

=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/uibinder/client/LazyDomElement.java Tue May 3 08:15:07 2011
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2011 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.client;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+
+/**
+ * Wraps a call to a DOM element. LazyDomElement can boost performance of html + * elements and delay calls to getElementById() to when the element is actually + * used. But note that it will throw a RuntimeException in case the element is
+ * accessed but not yet attached in the DOM tree.
+ *
+ * Usage example:
+ *
+ * <b>Template:</b>
+ * <pre>
+ *   &lt;gwt:HTMLPanel&gt;
+ *      &lt;div ui:field="myDiv" /&gt;
+ *   &lt;/gwt:HTMLPanel&gt;
+ * </pre>
+ *
+ * <b>Class:</b>
+ * <pre>
+ *   @UiField LazyDomElement&lt;DivElement&gt; myDiv;
+ *
+ *   public setText(String text) {
+ *     myDiv.get().setInnerHtml(text);
+ *   }
+ * </pre>
+ *
+ * @param <T> the Element type associated
+ */
+public class LazyDomElement<T extends Element> {
+
+  private T element;
+  private final String domId;
+
+ /**
+  * Creates an instance to fetch the element with the given id.
+  */
+  public LazyDomElement(String domId) {
+    this.domId = domId;
+  }
+
+ /**
+  * Returns the dom element.
+  *
+  * @return the dom element
+  * @throws RuntimeException if the element cannot be found
+  */
+  public T get() {
+    if (element == null) {
+      element = Document.get().getElementById(domId).cast();
+      if (element == null) {
+        throw new RuntimeException("Cannot find element with id \"" + domId
+            + "\". Perhaps it is not attached to the document body.");
+      }
+      element.removeAttribute("id");
+    }
+    return element;
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfLazyDomElement.java Tue May 3 08:15:07 2011
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 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.rebind;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JParameterizedType;
+import com.google.gwt.uibinder.rebind.model.OwnerField;
+
+/**
+ * Implementation of FieldWriter for a {@link com.google.gwt.uibinder.client.LazyDomElement}.
+ */
+public class FieldWriterOfLazyDomElement extends AbstractFieldWriter {
+
+  /**
+   * The field type for @UiField LazyDomElement&lt;T&gt;.
+   */
+  private final JParameterizedType ownerFieldType;
+
+  /**
+   * The T parameter in LazyDomElement&lt;T&gt;.
+   */
+  private final JClassType parameterType;
+
+  public FieldWriterOfLazyDomElement(JClassType templateFieldType,
+ OwnerField ownerField, MortalLogger logger) throws UnableToCompleteException {
+    super(ownerField.getName(), FieldWriterType.DEFAULT, logger);
+
+    // ownerFieldType null means LazyDomElement is not parameterized.
+    this.ownerFieldType = ownerField.getRawType().isParameterized();
+    if (ownerFieldType == null) {
+ logger.die("LazyDomElement must be of type LazyDomElement<? extends Element>.");
+    }
+
+ // Parameterized LazyDomElement<T> must match its respective html element.
+    // Example:
+    //  DivElement -> div
+    //  SpanElement -> span
+    parameterType = ownerFieldType.getTypeArgs()[0];
+    if (!templateFieldType.isAssignableTo(parameterType)) {
+ logger.die("Field %s is %s<%s>, must be %s<%s>.", ownerField.getName(),
+          ownerFieldType.getQualifiedSourceName(), parameterType,
+          ownerFieldType.getQualifiedSourceName(), templateFieldType);
+    }
+  }
+
+  public JClassType getAssignableType() {
+    return ownerFieldType;
+  }
+
+  public JClassType getInstantiableType() {
+    return ownerFieldType;
+  }
+
+  public String getQualifiedSourceName() {
+    return ownerFieldType.getQualifiedSourceName()
+        + "<" + parameterType.getQualifiedSourceName() + ">";
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfExistingTypeTest.java Tue May 3 08:15:07 2011
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2011 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.rebind;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JGenericType;
+import com.google.gwt.core.ext.typeinfo.JRawType;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.expect;
+
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+
+/**
+ * Tests for FieldWriterOfExistingType.
+ */
+public class FieldWriterOfExistingTypeTest extends TestCase {
+
+  private static final String FIELD_NAME = "field_name";
+ private static final String QUALIFIED_SOURCE_NAME = "qualified_source_name"; + private static final String ARG_QUALIFIED_SOURCE_NAME = "arg_qualified_source_name";
+
+  private IMocksControl control;
+
+  private JClassType type;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+
+    control = EasyMock.createControl();
+
+    type = control.createMock(JClassType.class);
+  }
+
+  /**
+   * Null type not allowed, must fail.
+   */
+  public void testNullType() throws Exception {
+    control.replay();
+    try {
+      FieldWriter field = new FieldWriterOfExistingType(
+          FieldWriterType.DEFAULT, null, FIELD_NAME, MortalLogger.NULL);
+      fail("Expected exception not thrown.");
+    } catch (IllegalArgumentException e) {
+      // Expected
+    }
+    control.verify();
+  }
+
+  /**
+   * Generic type.
+   */
+  public void testGenericType() throws Exception {
+    JGenericType genericType = control.createMock(JGenericType.class);
+    expect(type.isGenericType()).andReturn(genericType);
+
+    JRawType rawType = control.createMock(JRawType.class);
+    expect(genericType.getRawType()).andReturn(rawType);
+
+ expect(rawType.getQualifiedSourceName()).andReturn(QUALIFIED_SOURCE_NAME);
+
+    control.replay();
+    FieldWriter field = new FieldWriterOfExistingType(
+        FieldWriterType.DEFAULT, type, FIELD_NAME, MortalLogger.NULL);
+
+    assertSame(rawType, field.getAssignableType());
+    assertSame(rawType, field.getInstantiableType());
+    assertEquals(QUALIFIED_SOURCE_NAME, field.getQualifiedSourceName());
+    control.verify();
+  }
+
+  /**
+   * Non generic type.
+   */
+  public void testNonGenericType() throws Exception {
+    expect(type.isGenericType()).andReturn(null);
+
+    expect(type.getQualifiedSourceName()).andReturn(QUALIFIED_SOURCE_NAME);
+
+    control.replay();
+    FieldWriter field = new FieldWriterOfExistingType(
+        FieldWriterType.DEFAULT, type, FIELD_NAME, MortalLogger.NULL);
+
+    assertSame(type, field.getAssignableType());
+    assertSame(type, field.getInstantiableType());
+    assertEquals(QUALIFIED_SOURCE_NAME, field.getQualifiedSourceName());
+    control.verify();
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfLazyDomElementTest.java Tue May 3 08:15:07 2011
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 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.rebind;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JParameterizedType;
+import com.google.gwt.uibinder.rebind.model.OwnerField;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.expect;
+
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+
+/**
+ * Tests for FieldWriterOfLazyDomElement.
+ */
+public class FieldWriterOfLazyDomElementTest extends TestCase {
+
+  private static final String FIELD_NAME = "field_name";
+ private static final String QUALIFIED_SOURCE_NAME = "qualified_source_name"; + private static final String ARG_QUALIFIED_SOURCE_NAME = "arg_qualified_source_name";
+
+  private IMocksControl control;
+
+  private JClassType templateFieldType;
+  private OwnerField ownerField;
+  private JClassType ownerFieldType;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+
+    control = EasyMock.createControl();
+
+    templateFieldType = control.createMock(JClassType.class);
+    ownerField = control.createMock(OwnerField.class);
+    ownerFieldType = control.createMock(JClassType.class);
+
+    expect(ownerField.getName()).andStubReturn(FIELD_NAME);
+    expect(ownerField.getRawType()).andStubReturn(ownerFieldType);
+  }
+
+  /**
+   * Not parameterized LazyDomElement must fail. Example:
+   * <pre>
+   *   @UiField LazyDomElement el;
+   * </pre>
+   */
+  public void testLazyDomElementNotParameterized() throws Exception {
+    expect(ownerFieldType.isParameterized()).andReturn(null);
+
+    control.replay();
+    try {
+      FieldWriter field = new FieldWriterOfLazyDomElement(
+          templateFieldType, ownerField, MortalLogger.NULL);
+      fail("Expected exception not thrown.");
+    } catch (UnableToCompleteException utce) {
+      // Expected
+    }
+    control.verify();
+  }
+
+  /**
+ * LazyDomElement has parameter but it's not assignable to the template field
+   * type. Example:
+   * <pre>
+   *   @UiField LazyDomElement&lt;DivElement&gt; el;
+   * </pre>
+   *
+   * but in the template 'el' is defined as:
+   * <pre>
+   *   &lt;span ui:field='el' /&gt;
+   * </pre>
+   */
+  public void testLazyDomElementIncompatibleParameter() throws Exception {
+ JParameterizedType parameterClass = control.createMock(JParameterizedType.class);
+    expect(ownerFieldType.isParameterized()).andReturn(parameterClass);
+
+    JClassType arg = control.createMock(JClassType.class);
+ expect(parameterClass.getTypeArgs()).andReturn(new JClassType[] { arg });
+
+    expect(templateFieldType.isAssignableTo(arg)).andReturn(false);
+ expect(parameterClass.getQualifiedSourceName()).andStubReturn(QUALIFIED_SOURCE_NAME);
+
+    control.replay();
+    try {
+      FieldWriter field = new FieldWriterOfLazyDomElement(
+          templateFieldType, ownerField, MortalLogger.NULL);
+      fail("Expected exception not thrown.");
+    } catch (UnableToCompleteException utce) {
+      // Expected
+    }
+    control.verify();
+  }
+
+  /**
+   * The success test, everything works fine.
+   */
+  public void testLazyDomElementCompatibleType() throws Exception {
+ JParameterizedType parameterClass = control.createMock(JParameterizedType.class);
+    expect(ownerFieldType.isParameterized()).andReturn(parameterClass);
+
+    JClassType arg = control.createMock(JClassType.class);
+ expect(parameterClass.getTypeArgs()).andReturn(new JClassType[] { arg });
+
+    expect(templateFieldType.isAssignableTo(arg)).andReturn(true);
+
+ expect(parameterClass.getQualifiedSourceName()).andStubReturn(QUALIFIED_SOURCE_NAME); + expect(arg.getQualifiedSourceName()).andReturn(ARG_QUALIFIED_SOURCE_NAME);
+
+    control.replay();
+ FieldWriter field = new FieldWriterOfLazyDomElement(templateFieldType, ownerField, MortalLogger.NULL);
+    assertSame(parameterClass, field.getAssignableType());
+    assertSame(parameterClass, field.getInstantiableType());
+ assertEquals(QUALIFIED_SOURCE_NAME + "<" + ARG_QUALIFIED_SOURCE_NAME + ">",
+      field.getQualifiedSourceName());
+    control.verify();
+  }
+}
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/client/UiBinderUtil.java Fri Apr 22 11:18:50 2011 +++ /trunk/user/src/com/google/gwt/uibinder/client/UiBinderUtil.java Tue May 3 08:15:07 2011
@@ -26,27 +26,6 @@
  * so please don't use them for non-UiBinder code.
  */
 public class UiBinderUtil {
-
-  /**
-   * A helper class to enable lazy creation of DOM elements.
-   */
-  public static class LazyDomElement {
-
-    private Element element;
-    private final String domId;
-
-    public LazyDomElement(String domId) {
-      this.domId = domId;
-    }
-
-    public Element get() {
-      if (element == null) {
-        element = Document.get().getElementById(domId).cast();
-        element.removeAttribute("id");
-      }
-      return element;
-    }
-  }

   /**
    * Temporary attachment record that keeps track of where an element was
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/WidgetInterpreter.java Wed Apr 27 13:54:04 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/WidgetInterpreter.java Tue May 3 08:15:07 2011
@@ -16,9 +16,9 @@
 package com.google.gwt.uibinder.elementparsers;

 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.uibinder.client.UiBinderUtil.LazyDomElement;
 import com.google.gwt.uibinder.rebind.FieldManager;
 import com.google.gwt.uibinder.rebind.FieldWriter;
+import com.google.gwt.uibinder.client.LazyDomElement;
 import com.google.gwt.uibinder.rebind.UiBinderWriter;
 import com.google.gwt.uibinder.rebind.XMLElement;

@@ -97,8 +97,8 @@
       // Register a DOM id field.
       String lazyDomElementPath = LazyDomElement.class.getCanonicalName();
FieldWriter elementWriter = fieldManager.registerField(lazyDomElementPath, elementPointer);
-      elementWriter.setInitializer(String.format("new %s(%s)",
- lazyDomElementPath, fieldManager.convertFieldToGetter(idHolder)));
+      elementWriter.setInitializer(String.format("new %s<Element>(%s)",
+ lazyDomElementPath, fieldManager.convertFieldToGetter(idHolder)));

       // Add attach/detach sections for this element.
       fieldWriter.addAttachStatement("%s.get();",
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/WidgetPlaceholderInterpreter.java Wed Apr 27 13:54:04 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/WidgetPlaceholderInterpreter.java Tue May 3 08:15:07 2011
@@ -18,9 +18,9 @@
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.uibinder.client.UiBinderUtil.LazyDomElement;
 import com.google.gwt.uibinder.rebind.FieldManager;
 import com.google.gwt.uibinder.rebind.FieldWriter;
+import com.google.gwt.uibinder.client.LazyDomElement;
 import com.google.gwt.uibinder.rebind.UiBinderWriter;
 import com.google.gwt.uibinder.rebind.XMLElement;
 import com.google.gwt.uibinder.rebind.messages.MessageWriter;
@@ -131,7 +131,7 @@
         String elementPointer = idHolder + "Element";
         FieldWriter elementWriter = fieldManager.registerField(
             lazyDomElementPath, elementPointer);
-        elementWriter.setInitializer(String.format("new %s(%s)",
+        elementWriter.setInitializer(String.format("new %s<Element>(%s)",
lazyDomElementPath, fieldManager.convertFieldToGetter(idHolder)));

         // Add attach/detach sections for this element.
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/FieldManager.java Mon May 2 12:52:38 2011 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/FieldManager.java Tue May 3 08:15:07 2011
@@ -21,6 +21,7 @@
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.uibinder.rebind.model.ImplicitCssResource;
+import com.google.gwt.uibinder.rebind.model.OwnerField;
 import com.google.gwt.uibinder.rebind.model.OwnerClass;

 import java.util.Arrays;
@@ -209,6 +210,27 @@
types.findType(String.class.getCanonicalName()), cssResource, logger);
     return registerField(cssResource.getName(), field);
   }
+
+  /**
+ * Register a new field for {@link com.google.gwt.uibinder.client.LazyDomElement} + * types. LazyDomElement fields can only be associated with html elements. Example:
+   *
+   *  <li>LazyDomElement&lt;DivElement&gt; -&gt; &lt;div&gt;</li>
+   *  <li>LazyDomElement&lt;Element&gt; -&gt; &lt;div&gt;</li>
+   *  <li>LazyDomElement&lt;SpanElement&gt; -&gt; &lt;span&gt;</li>
+   *
+ * @param templateFieldType the html type to bind, eg, SpanElement, DivElement, etc
+   * @param ownerField the field instance
+   */
+ public FieldWriter registerFieldForLazyDomElement(JClassType templateFieldType,
+      OwnerField ownerField) throws UnableToCompleteException {
+    if (ownerField == null) {
+ throw new RuntimeException("Cannot register a null owner field for LazyDomElement.");
+    }
+    FieldWriter field = new FieldWriterOfLazyDomElement(
+        templateFieldType, ownerField, logger);
+    return registerField(ownerField.getName(), field);
+  }

   /**
* Used to declare fields of a type (other than CssResource) that is to be
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriterType.java Mon May 2 12:52:38 2011 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriterType.java Tue May 3 08:15:07 2011
@@ -21,9 +21,10 @@
  */
 enum FieldWriterType {

-  GENERATED_BUNDLE(4),
-  GENERATED_CSS(3),
-  IMPORTED(2),  // ui:with clauses.
+  GENERATED_BUNDLE(5),
+  GENERATED_CSS(4),
+  IMPORTED(3),  // ui:with clauses.
+  DOM_ID_HOLDER(2),
   DEFAULT(1);

   /**
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Mon May 2 12:52:38 2011 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Tue May 3 08:15:07 2011
@@ -25,8 +25,8 @@
 import com.google.gwt.uibinder.attributeparsers.AttributeParsers;
 import com.google.gwt.uibinder.attributeparsers.BundleAttributeParser;
 import com.google.gwt.uibinder.attributeparsers.BundleAttributeParsers;
+import com.google.gwt.uibinder.client.LazyDomElement;
 import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiBinderUtil.LazyDomElement;
 import com.google.gwt.uibinder.elementparsers.AttributeMessageParser;
 import com.google.gwt.uibinder.elementparsers.BeanParser;
 import com.google.gwt.uibinder.elementparsers.ElementParser;
@@ -198,6 +198,8 @@

   private final JClassType attachableClassType;

+  private final JClassType lazyDomElementClass;
+
   private final OwnerClass ownerClass;

   private final FieldManager fieldManager;
@@ -279,6 +281,7 @@
     uiOwnerType = typeArgs[1];

attachableClassType = oracle.findType(Attachable.class.getCanonicalName()); + lazyDomElementClass = oracle.findType(LazyDomElement.class.getCanonicalName());

     ownerClass = new OwnerClass(uiOwnerType, logger, uiBinderCtx);
bundleClass = new ImplicitClientBundle(baseClass.getPackage().getName(),
@@ -373,13 +376,26 @@
     if (useLazyWidgetBuilders) {
       // Create and initialize the dom field with LazyDomElement.
       FieldWriter field = fieldManager.require(fieldName);
-      field.setInitializer(formatCode("new %s(%s).get().cast()",
-          LazyDomElement.class.getCanonicalName(),
-          fieldManager.convertFieldToGetter(name)));
-
-      // The dom must be created by its ancestor.
-      fieldManager.require(ancestorField).addAttachStatement(
-          fieldManager.convertFieldToGetter(fieldName) + ";");
+
+      /**
+ * But if the owner field is an instance of LazyDomElement then the code + * can be optimized, no cast is needed and the getter doesn't need to be
+       * called in its ancestral.
+       */
+      if (isOwnerFieldLazyDomElement(fieldName)) {
+        field.setInitializer(formatCode("new %s(%s)",
+            field.getQualifiedSourceName(),
+            fieldManager.convertFieldToGetter(name)));
+      } else {
+
+        field.setInitializer(formatCode("new %s(%s).get().cast()",
+            LazyDomElement.class.getCanonicalName(),
+            fieldManager.convertFieldToGetter(name)));
+
+        // The dom must be created by its ancestor.
+        fieldManager.require(ancestorField).addAttachStatement(
+            fieldManager.convertFieldToGetter(fieldName) + ";");
+      }
     } else {
       setFieldInitializer(fieldName, "null");
       addInitStatement(
@@ -399,7 +415,7 @@
    */
   public String declareDomIdHolder() throws UnableToCompleteException {
     String domHolderName = "domId" + domId++;
-    FieldWriter domField = fieldManager.registerField(
+ FieldWriter domField = fieldManager.registerField(FieldWriterType.DOM_ID_HOLDER,
         oracle.findType(String.class.getName()), domHolderName);
domField.setInitializer("com.google.gwt.dom.client.Document.get().createUniqueId()");

@@ -442,7 +458,16 @@
       throws UnableToCompleteException {
     String fieldName = getFieldName(elem);
     if (fieldName != null) {
-      fieldManager.registerField(findFieldType(elem), fieldName);
+
+      /**
+       * We can switch types if useLazyWidgetBuilders is enabled and the
+       * respective owner field is a LazyDomElement.
+       */
+      if (useLazyWidgetBuilders && isOwnerFieldLazyDomElement(fieldName)) {
+ fieldManager.registerFieldForLazyDomElement(findFieldType(elem), ownerClass.getUiField(fieldName));
+      } else {
+        fieldManager.registerField(findFieldType(elem), fieldName);
+      }
     }
     return fieldName;
   }
@@ -672,6 +697,18 @@
     String uri = elem.getNamespaceUri();
     return uri != null && UiBinderGenerator.BINDER_URI.equals(uri);
   }
+
+  /**
+   * Checks whether the given owner field name is a LazyDomElement or not.
+   */
+  public boolean isOwnerFieldLazyDomElement(String fieldName) {
+    OwnerField ownerField = ownerClass.getUiField(fieldName);
+    if (ownerField == null) {
+      return false;
+    }
+
+ return lazyDomElementClass.isAssignableFrom(ownerField.getType().getRawType());
+  }

   public boolean isWidgetElement(XMLElement elem) {
     String uri = elem.getNamespaceUri();
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/model/OwnerField.java Thu Sep 9 08:24:17 2010 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/model/OwnerField.java Tue May 3 08:15:07 2011
@@ -74,6 +74,14 @@
   public String getName() {
     return name;
   }
+
+  /**
+   * Gets the type associated with this field.
+   */
+  public JClassType getRawType() {
+    // This shorten getType().getRawType() and make tests easier.
+    return getType().getRawType();
+  }

   /**
    * Returns a descriptor for the type of the field.
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java Fri Apr 22 09:21:14 2011 +++ /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java Tue May 3 08:15:07 2011
@@ -45,7 +45,9 @@
 import com.google.gwt.uibinder.elementparsers.HasTreeItemsParserTest;
 import com.google.gwt.uibinder.elementparsers.UIObjectParserTest;
 import com.google.gwt.uibinder.rebind.DesignTimeUtilsTest;
+import com.google.gwt.uibinder.rebind.FieldWriterOfExistingTypeTest;
import com.google.gwt.uibinder.rebind.FieldWriterOfGeneratedCssResourceTest;
+import com.google.gwt.uibinder.rebind.FieldWriterOfLazyDomElementTest;
 import com.google.gwt.uibinder.rebind.GwtResourceEntityResolverTest;
 import com.google.gwt.uibinder.rebind.HandlerEvaluatorTest;
 import com.google.gwt.uibinder.rebind.TokenatorTest;
@@ -66,7 +68,9 @@
     TestSuite suite = new TestSuite("UiBinder tests that require the JRE");

     // rebind
+    suite.addTestSuite(FieldWriterOfExistingTypeTest.class);
     suite.addTestSuite(FieldWriterOfGeneratedCssResourceTest.class);
+    suite.addTestSuite(FieldWriterOfLazyDomElementTest.class);
     suite.addTestSuite(GwtResourceEntityResolverTest.class);
     suite.addTestSuite(HandlerEvaluatorTest.class);
     suite.addTestSuite(TokenatorTest.class);

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to