Nukes the deprecated and over complicated
create-the-root-now-create-the-rest-later flow from UiBinder, and in the process
squashes a number of reported and unreported bugs.

Not as big a change as it looks, most of the listed files are a result of
compulsive method name change refactoring.

The real meat is in moving the parsing of the root UiBinder element out of
UiBinderWriter and into its own parser, and greatly simplified bootstrapping of
the parsing process.

Because we now start parsing above the UI, at the ui:UiBinder element,
parseElementToField (was parseWidget) gets a crack at the topmost element of the
UI--it gets treated like every other element, and various inconsistencies in its
handling (esp. with {computed.attributes} and localizable ones) evaporate.

Reviewed by: jgw


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6062 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/client/AbstractUiBinder.java b/user/src/com/google/gwt/uibinder/client/AbstractUiBinder.java
deleted file mode 100644
index 1718aa5..0000000
--- a/user/src/com/google/gwt/uibinder/client/AbstractUiBinder.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2008 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;
-
-/**
- * Convenient base class for implementations of {@link UiBinder}, 
- * generated or otherwise.
- * 
- * @param <U> The type of the UI's root object
- * @param <O> The type of the owner of the UI
- */
-public abstract class AbstractUiBinder<U,O> implements UiBinder<U, O> {
-  
-  /**
-   * An interface used by some generated implementations of UiBinder.
-   * 
-   * @param <U> The type of the UI's root object
-   * @param <O> The type of the owner of the UI
-   */
-  protected interface InstanceBinder<U, O> {
-    U makeUi();
-    void doBind(O owner);
-  }
-
-  public U createAndBindUi(O owner) {
-    U ui = createUiRoot(owner);
-    bindUi(ui, owner);
-    return ui;
-  }
-}
diff --git a/user/src/com/google/gwt/uibinder/client/DomHolder.java b/user/src/com/google/gwt/uibinder/client/DomHolder.java
deleted file mode 100644
index 00d7306..0000000
--- a/user/src/com/google/gwt/uibinder/client/DomHolder.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2008 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.Element;
-import com.google.gwt.user.client.ui.UIObject;
-
-/**
- * Runtime helper for templates.
- */
-public class DomHolder extends UIObject {
-  public DomHolder(Element element) {
-    setElement(element);
-  }
-}
diff --git a/user/src/com/google/gwt/uibinder/client/UiBinder.java b/user/src/com/google/gwt/uibinder/client/UiBinder.java
index bfff7f6..52e2bcb 100644
--- a/user/src/com/google/gwt/uibinder/client/UiBinder.java
+++ b/user/src/com/google/gwt/uibinder/client/UiBinder.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 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
@@ -26,38 +26,17 @@
  * in {@code /bar/baz/Foo.ui.xml}. (To use a different template file, put the
  * {@link UiTemplate} annotation on your UiBinder interface declaration to point
  * the code generator at it.)
- * 
+ *
  * @param <U> The type of the root object of the generated UI, typically a
  *          subclass of {@link com.google.gwt.dom.client.Element} or
  *          {@link com.google.gwt.user.client.ui.UIObject}
  * @param <O> The type of the object that will own the generated UI
  */
 public interface UiBinder<U, O> {
-
-  /**
-   * Creates and returns the root object of the UI. If possible the creation of
-   * the rest of the UI is deferred until {@link #bindUi} is called.
-   * 
-   * @deprecated The use case for this complexity never materialized. Use
-   *             {@link #createAndBindUi}
-   */
-  @Deprecated
-  U createUiRoot(O owner);
-
-  /**
-   * Completes the creation of a UI started with a call to {@link #createUiRoot}, 
-   * and fills any owner fields tagged with {@link UiField}.
-   * 
-   * @deprecated The use case for this complexity never materialized. Use
-   *             {@link #createAndBindUi}
-   */
-  @Deprecated
-  void bindUi(U root, O owner);
-
   /**
    * Creates and returns the root object of the UI, and fills any fields of owner
    * tagged with {@link UiField}.
-   * 
+   *
    * @param owner the object whose {@literal @}UiField needs will be filled
    */
   U createAndBindUi(O owner);
diff --git a/user/src/com/google/gwt/uibinder/parsers/CellPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/CellPanelParser.java
index 4a91e84..0490af6 100644
--- a/user/src/com/google/gwt/uibinder/parsers/CellPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/CellPanelParser.java
@@ -90,14 +90,14 @@
         if (widget == null) {
           writer.die("Cell must contain a single child widget");
         }
-        String childFieldName = writer.parseWidget(widget);
+        String childFieldName = writer.parseElementToField(widget);
         writer.addStatement("%1$s.add(%2$s);", fieldName, childFieldName);
 
         // Parse the cell tag's alignment & size attributes.
         parseCellAttributes(child, fieldName, childFieldName, writer);
       } else {
         // It's just a normal child, so parse it as a widget.
-        String childFieldName = writer.parseWidget(child);
+        String childFieldName = writer.parseElementToField(child);
         writer.addStatement("%1$s.add(%2$s);", fieldName, childFieldName);
       }
     }
diff --git a/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java b/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java
index 722db79..79c8a26 100644
--- a/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java
@@ -82,14 +82,14 @@
           writer.die("In %s, DisclosurePanel cannot contain more than one header widget.", elem);
         }
         child.consumeAttribute(headerAttributeName);
-        headerFieldName = writer.parseWidget(child);
+        headerFieldName = writer.parseElementToField(child);
         childIsHeader = true;
       }
       if (!childIsHeader) {
         if (childFieldName != null) {
           writer.die("In %s, DisclosurePanel cannot contain more than one content widget.", elem);
         }
-        childFieldName = writer.parseWidget(child);
+        childFieldName = writer.parseElementToField(child);
       }
     }
 
diff --git a/user/src/com/google/gwt/uibinder/parsers/DockPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/DockPanelParser.java
index 1d4be30..088aa00 100644
--- a/user/src/com/google/gwt/uibinder/parsers/DockPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/DockPanelParser.java
@@ -69,7 +69,7 @@
       if (widget == null) {
         writer.die("Dock must contain a single child widget.");
       }
-      String childFieldName = writer.parseWidget(widget);
+      String childFieldName = writer.parseElementToField(widget);
       writer.addStatement("%1$s.add(%2$s, %3$s);", fieldName, childFieldName, translated);
 
       // And they can optionally have a width.
diff --git a/user/src/com/google/gwt/uibinder/parsers/DomElementParser.java b/user/src/com/google/gwt/uibinder/parsers/DomElementParser.java
index ba2619a..aab67e0 100644
--- a/user/src/com/google/gwt/uibinder/parsers/DomElementParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/DomElementParser.java
@@ -21,36 +21,24 @@
 import com.google.gwt.uibinder.rebind.XMLElement;
 
 /**
- * Parses a raw dom element, as opposed to a widget or uiobject. Note that this
- * parser does not get a crack at every dom element--it only handles the case of
- * a dom element as ui root. Note also that it is intended to be used only by
- * {@link UiBinderWriter}, and will generate cast class exceptions if used
- * otherwise.
+ * Parses a dom element and all of its children. Note that this parser does not
+ * make recursive calls to parse child elements, unlike what goes on with widget
+ * parsers. Instead, we consume the inner html of the given element into
+ * a single string literal, used to instantiate the dom tree at run time.
  */
 public class DomElementParser implements ElementParser {
 
   public void parse(XMLElement elem, String fieldName, JClassType type,
       UiBinderWriter writer) throws UnableToCompleteException {
     HtmlInterpreter interpreter =
-        new HtmlInterpreter(writer, "root", new HtmlMessageInterpreter(writer,
-            "root"));
-
-    writer.setFieldInitializer(fieldName, "null");
+        new HtmlInterpreter(writer, fieldName, new HtmlMessageInterpreter(writer,
+            fieldName));
 
     interpreter.interpretElement(elem);
-    String rootHtml = elem.consumeOpeningTag() + elem.getClosingTag();
-    String rootType = getFQTypeName(type);
-    writer.genRoot(String.format(
-        "(%1$s) UiBinderUtil.fromHtml(\"%2$s\")", rootType, rootHtml));
 
-    String innerHtml = elem.consumeInnerHtml(interpreter);
-
-    if (innerHtml.trim().length() > 0) { // TODO(rjrjr) Really want this check?
-      writer.addStatement("root.setInnerHTML(\"%s\");", innerHtml);
-    }
-  }
-
-  private String getFQTypeName(JClassType type) {
-    return type.getPackage().getName() + "." + type.getName();
+    String html = elem.consumeOpeningTag() + elem.consumeInnerHtml(interpreter)
+      + elem.getClosingTag();
+    writer.setFieldInitializer(fieldName, String.format(
+        "(%1$s) UiBinderUtil.fromHtml(\"%2$s\")", type.getQualifiedSourceName(), html));
   }
 }
diff --git a/user/src/com/google/gwt/uibinder/parsers/HasWidgetsParser.java b/user/src/com/google/gwt/uibinder/parsers/HasWidgetsParser.java
index 808bb38..c2da747 100644
--- a/user/src/com/google/gwt/uibinder/parsers/HasWidgetsParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/HasWidgetsParser.java
@@ -32,7 +32,7 @@
       UiBinderWriter writer) throws UnableToCompleteException {
     // Parse children.
     for (XMLElement child : elem.consumeChildElements()) {
-      String childFieldName = writer.parseWidget(child);
+      String childFieldName = writer.parseElementToField(child);
       writer.addStatement("%1$s.add(%2$s);", fieldName, childFieldName);
     }
   }
diff --git a/user/src/com/google/gwt/uibinder/parsers/MenuBarParser.java b/user/src/com/google/gwt/uibinder/parsers/MenuBarParser.java
index 0325997..2d1cedc 100644
--- a/user/src/com/google/gwt/uibinder/parsers/MenuBarParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/MenuBarParser.java
@@ -51,7 +51,7 @@
         }
       }
 
-      String itemFieldName = writer.parseWidget(child);
+      String itemFieldName = writer.parseElementToField(child);
 
       writer.addStatement("%1$s.addItem(%2$s);", fieldName, itemFieldName);
     }
diff --git a/user/src/com/google/gwt/uibinder/parsers/MenuItemParser.java b/user/src/com/google/gwt/uibinder/parsers/MenuItemParser.java
index 128aa96..57f0393 100644
--- a/user/src/com/google/gwt/uibinder/parsers/MenuItemParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/MenuItemParser.java
@@ -64,7 +64,7 @@
           writer.die("In %s, only one MenuBar may be contained in a MenuItem",
               errorContext);
         }
-        menuBarField = writer.parseWidget(elem);
+        menuBarField = writer.parseElementToField(elem);
         return "";
       }
 
diff --git a/user/src/com/google/gwt/uibinder/parsers/StackPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/StackPanelParser.java
index 3a406b9..aa35ac8 100644
--- a/user/src/com/google/gwt/uibinder/parsers/StackPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/StackPanelParser.java
@@ -39,7 +39,7 @@
         stackItemLabel = child.consumeAttribute(variableAttributeName);
       }
 
-      String childFieldName = writer.parseWidget(child);
+      String childFieldName = writer.parseElementToField(child);
       if (stackItemLabel == null) {
         writer.addStatement("%1$s.add(%2$s);", fieldName, childFieldName);
       } else {
diff --git a/user/src/com/google/gwt/uibinder/parsers/TabPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/TabPanelParser.java
index 6965740..099c112 100644
--- a/user/src/com/google/gwt/uibinder/parsers/TabPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/TabPanelParser.java
@@ -61,7 +61,7 @@
           if (childFieldName != null) {
             writer.die("gwt:Tab may only have a single child widget");
           }
-          childFieldName = writer.parseWidget(tabChild);
+          childFieldName = writer.parseElementToField(tabChild);
         }
       }
 
diff --git a/user/src/com/google/gwt/uibinder/parsers/WidgetInterpreter.java b/user/src/com/google/gwt/uibinder/parsers/WidgetInterpreter.java
index 78f7a22..efe2bab 100644
--- a/user/src/com/google/gwt/uibinder/parsers/WidgetInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/parsers/WidgetInterpreter.java
@@ -73,7 +73,7 @@
   }
 
   public String interpretElement(XMLElement elem) throws UnableToCompleteException {
-    if (uiWriter.isWidget(elem)) {
+    if (uiWriter.isWidgetElement(elem)) {
       // Allocate a local variable to hold the dom id for this widget. Note
       // that idHolder is a local variable reference, not a string id. We
       // have to generate the ids at runtime, not compile time, or else
@@ -102,7 +102,7 @@
      */
     for (String idHolder : idToWidgetElement.keySet()) {
       XMLElement childElem = idToWidgetElement.get(idHolder);
-      String childField = uiWriter.parseWidget(childElem);
+      String childField = uiWriter.parseElementToField(childElem);
       uiWriter.addInitStatement("%1$s.addAndReplaceElement(%2$s, %3$s);", fieldName,
           childField, idHolder);
     }
diff --git a/user/src/com/google/gwt/uibinder/parsers/WidgetPlaceholderInterpreter.java b/user/src/com/google/gwt/uibinder/parsers/WidgetPlaceholderInterpreter.java
index b337b4a..70f09c3 100644
--- a/user/src/com/google/gwt/uibinder/parsers/WidgetPlaceholderInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/parsers/WidgetPlaceholderInterpreter.java
@@ -77,11 +77,11 @@
   public String interpretElement(XMLElement elem)
       throws UnableToCompleteException {
 
-    if (!uiWriter.isWidget(elem)) {
+    if (!uiWriter.isWidgetElement(elem)) {
       return super.interpretElement(elem);
     }
 
-    JClassType type = uiWriter.findWidgetOrElementType(elem);
+    JClassType type = uiWriter.findFieldType(elem);
     TypeOracle oracle = uiWriter.getOracle();
 
     MessagesWriter mw = uiWriter.getMessages();
@@ -112,7 +112,7 @@
   public String postProcess(String consumed) throws UnableToCompleteException {
     for (String idHolder : idToWidgetElement.keySet()) {
       XMLElement childElem = idToWidgetElement.get(idHolder);
-      String childField = uiWriter.parseWidget(childElem);
+      String childField = uiWriter.parseElementToField(childElem);
 
       genSetWidgetTextCall(idHolder, childField);
       uiWriter.addInitStatement("%1$s.addAndReplaceElement(%2$s, %3$s);",
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
index d467c4e..b42ec81 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2009 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
@@ -55,13 +55,6 @@
   }
 
   /**
-   * @return the fully qualified name of this field's type
-   */
-  public String getFullTypeName() {
-    return type.getPackage().getName() + "." + type.getName();
-  }
-
-  /**
    * @return the type of this field
    */
   public JClassType getType() {
@@ -79,7 +72,7 @@
    * 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 ';'.
-   * 
+   *
    * @throws IllegalStateException on second attempt to set the initializer
    */
   public void setInitializer(String initializer) {
@@ -112,7 +105,7 @@
 
   /**
    * Write the field delcaration.
-   * 
+   *
    * @return false if unable to write for lack of a default constructor
    */
   // TODO(rjrjr) This return code thing is silly. We should
@@ -138,10 +131,10 @@
         return false;
       }
       initializer = String.format("(%1$s) GWT.create(%1$s.class)",
-          getFullTypeName());
+          type.getQualifiedSourceName());
     }
 
-    w.write("%s %s = %s;", getFullTypeName(), name, initializer);
+    w.write("%s %s = %s;", type.getQualifiedSourceName(), name, initializer);
 
     this.written = true;
     return true;
diff --git a/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java b/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java
index 5237375..6c10827 100644
--- a/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java
+++ b/user/src/com/google/gwt/uibinder/rebind/HandlerEvaluator.java
@@ -63,8 +63,18 @@
  */
 class HandlerEvaluator {
 
-  private static final String HANDLER_BASE_NAME = "handler";
-
+  private static final String HANDLER_BASE_NAME =
+    "handlerMethodWithNameVeryUnlikelyToCollideWithUserFieldNames";
+  /*
+   * TODO(rjrjr) The correct fix is to put the handlers in a locally defined
+   * class, making the generated code look like this:
+   *
+   *
+   * http://docs.google.com/Doc?docid=0AQfnKgX9tAdgZGZ2cTM5YjdfMmQ4OTk0eGhz&hl=en
+   *
+   * But that needs to wait for a refactor to get most of this stuff out of here
+   * and into com.google.gwt.uibinder.rebind.model
+   */
   private int varCounter = 0;
 
   private final TreeLogger logger;
@@ -222,7 +232,7 @@
    */
   void writeAddHandler(IndentedWriter writer, String handlerVarName,
       String addHandlerMethodName, String objectName) {
-    writer.write("this.%1$s.%2$s(%3$s);", objectName,
+    writer.write("%1$s.%2$s(%3$s);", objectName,
         addHandlerMethodName, handlerVarName);
   }
 
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
new file mode 100644
index 0000000..db760a2
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2009 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.JMethod;
+import com.google.gwt.uibinder.rebind.messages.MessagesWriter;
+import com.google.gwt.uibinder.rebind.model.OwnerField;
+
+/**
+ * Parses the root UiBinder element, and kicks of the parsing of the rest of the
+ * document.
+ */
+public class UiBinderParser {
+  // TODO(rjrjr) Make all the ElementParsers receive their dependencies via
+  // constructor like this one does, and make this an ElementParser
+
+  private final UiBinderWriter writer;
+  private final MessagesWriter messagesWriter;
+  private final FieldManager fieldManager;
+
+  public UiBinderParser(UiBinderWriter writer, MessagesWriter messagesWriter,
+      FieldManager fieldManager) {
+    this.writer = writer;
+    this.messagesWriter = messagesWriter;
+    this.fieldManager = fieldManager;
+  }
+
+  /**
+   * Parses the root UiBinder element, and kicks off the parsing of the rest of
+   * the document.
+   */
+  public String parse(XMLElement elem)
+      throws UnableToCompleteException {
+    findResources(elem);
+    messagesWriter.findMessagesConfig(elem);
+    XMLElement uiRoot = elem.consumeSingleChildElement();
+    return writer.parseElementToField(uiRoot);
+  }
+
+  /**
+   * Interprets <ui:with> elements.
+   */
+  private void createResource(XMLElement elem)
+      throws UnableToCompleteException {
+    String resourceName = elem.consumeRequiredAttribute("name");
+    String resourceTypeName = elem.consumeRequiredAttribute("type");
+
+    JClassType resourceType = writer.getOracle().findType(resourceTypeName);
+    if (resourceType == null) {
+      writer.die("In %s, no such type %s", elem, resourceTypeName);
+    }
+
+    if (elem.getAttributeCount() > 0) {
+      writer.die("In %s, should only find attributes \"name\" and \"type\"");
+    }
+
+    FieldWriter fieldWriter = fieldManager.registerField(resourceTypeName,
+        resourceName);
+    OwnerField ownerField = writer.getOwnerClass().getUiField(resourceName);
+
+    // Perhaps it is provided via @UiField
+
+    if (ownerField != null) {
+      if (!resourceType.equals(ownerField.getType().getRawType())) {
+        writer.die("In %s, type must match %s", ownerField);
+      }
+
+      if (ownerField.isProvided()) {
+        fieldWriter.setInitializer("owner." + ownerField.getName());
+        return;
+      }
+    }
+
+    // Nope. Maybe a @UiFactory will make it
+
+    JMethod factoryMethod = writer.getOwnerClass().getUiFactoryMethod(
+        resourceType);
+    if (factoryMethod != null) {
+      fieldWriter.setInitializer(String.format("owner.%s()",
+          factoryMethod.getName()));
+    }
+
+    // If neither of the above, the FieldWriter's default GWT.create call will
+    // do just fine.
+  }
+
+  private void findResources(XMLElement binderElement)
+      throws UnableToCompleteException {
+    binderElement.consumeChildElements(new XMLElement.Interpreter<Boolean>() {
+      public Boolean interpretElement(XMLElement elem)
+          throws UnableToCompleteException {
+        if (!(writer.isBinderElement(elem)
+            && "with".equals(elem.getLocalName()))) {
+          return false; // Not of interest, do not consume
+        }
+
+        createResource(elem);
+
+        return true; // Yum
+      }
+    });
+  }
+
+}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index d53a53e..3e9d483 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 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
@@ -48,12 +48,13 @@
 
 /**
  * Writer for UiBinder generated classes.
- * 
+ *
  * TODO(rdamazio): Refactor this, extract model classes, improve ordering
  * guarantees, etc. TODO(rjrjr): Improve error messages
  */
+@SuppressWarnings("deprecation")
 public class UiBinderWriter {
-  private static final String GWT_URI = "urn:ui:com.google.gwt.uibinder";
+  private static final String BINDER_URI = "urn:ui:com.google.gwt.uibinder";
   private static final String BUNDLE_URI_SCHEME = "urn:with:";
   private static final String PACKAGE_URI_SCHEME = "urn:import:";
 
@@ -141,7 +142,7 @@
   /**
    * Returns a list of the given type and all its superclasses and implemented
    * interfaces in a breadth-first traversal.
-   * 
+   *
    * @param type the base type
    * @return a breadth-first collection of its type hierarchy
    */
@@ -181,7 +182,7 @@
   /**
    * Class names of parsers for values of attributes with no namespace prefix,
    * keyed by method parameter signatures.
-   * 
+   *
    * TODO(rjrjr) Seems like the attribute parsers belong in BeanParser, which is
    * the only thing that uses them.
    */
@@ -229,8 +230,6 @@
 
   private String rendered;
 
-  private String rootDeclaration;
-
   UiBinderWriter(JClassType baseClass, String implClassName,
       String templatePath, TypeOracle oracle, TreeLogger logger)
       throws UnableToCompleteException {
@@ -282,7 +281,7 @@
    * generate a unique dom id at runtime. Further code will be generated to be
    * run after widgets are instantiated, to use that dom id in a getElementById
    * 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
@@ -302,7 +301,7 @@
   /**
    * Declare a variable that will be filled at runtime with a unique id, safe
    * for use as a dom element's id attribute.
-   * 
+   *
    * @return that variable's name.
    */
   public String declareDomIdHolder() throws UnableToCompleteException {
@@ -332,14 +331,14 @@
    * If this element has a gwt:field attribute, create a field for it of the
    * appropriate type, and return the field name. If no gwt:field attribute is
    * found, do nothing and return null
-   * 
+   *
    * @return The new field name, or null if no field is created
    */
   public String declareFieldIfNeeded(XMLElement elem)
       throws UnableToCompleteException {
     String fieldName = getFieldName(elem);
     if (fieldName != null) {
-      String typeName = findWidgetOrElementType(elem).getQualifiedSourceName();
+      String typeName = findFieldType(elem).getQualifiedSourceName();
       fieldManager.registerField(typeName, fieldName);
     }
     return fieldName;
@@ -378,15 +377,15 @@
   /**
    * Finds the JClassType that corresponds to this XMLElement, which must be a
    * Widget or an Element.
-   * 
+   *
    * @throws UnableToCompleteException If no such widget class exists
    * @throws RuntimeException if asked to handle a non-widget, non-DOM element
    */
-  public JClassType findWidgetOrElementType(XMLElement elem)
+  public JClassType findFieldType(XMLElement elem)
       throws UnableToCompleteException {
     String tagName = elem.getLocalName();
 
-    if (!isWidget(elem)) {
+    if (!isWidgetElement(elem)) {
       return findElementTypeForTag(tagName);
     }
 
@@ -418,16 +417,6 @@
   }
 
   /**
-   * Provide the expression to generate only the root element of the UI. If this
-   * is called, the code to create the bulk of the ui will be in the
-   * {@link UiBinder#bindUi} method. If it is not called, all code to create the
-   * ui will be in the {@link UiBinder#createUiRoot} method.
-   */
-  public void genRoot(String initString) {
-    rootDeclaration = initString;
-  }
-
-  /**
    * Generates the code to set a string property.
    */
   public void genStringPropertySet(String fieldName, String propName,
@@ -450,7 +439,7 @@
     if (params.length == 1) {
       return new StrictAttributeParser();
     }
-    
+
     return null;
   }
 
@@ -472,7 +461,7 @@
   /**
    * Finds an attribute {@link BundleAttributeParser} for the given xml
    * attribute, if any, based on its namespace uri.
-   * 
+   *
    * @return the parser or null
    * @deprecated exists only to support {@link BundleAttributeParser}, which
    *             will be leaving us soon.
@@ -525,33 +514,37 @@
     return ownerClass;
   }
 
-  public boolean isWidget(XMLElement elem) {
+  public boolean isBinderElement(XMLElement elem) {
+    String uri = elem.getNamespaceUri();
+    return uri != null && BINDER_URI.equals(uri);
+  }
+
+  public boolean isWidgetElement(XMLElement elem) {
     String uri = elem.getNamespaceUri();
     return uri != null && uri.startsWith(PACKAGE_URI_SCHEME);
   }
 
   /**
-   * Parses the widget associated with the specified element, and returns the
-   * name of the field (possibly private) that will hold the object it
-   * describes.
-   * 
+   * Parses the object associated with the specified element, and returns the
+   * name of the field (possibly private) that will hold it.
+   *
    * @param elem the xml element to be parsed
    * @return the name of the field containing the parsed widget
    */
-  public String parseWidget(XMLElement elem) throws UnableToCompleteException {
+  public String parseElementToField(XMLElement elem) throws UnableToCompleteException {
     if (elementParsers.isEmpty()) {
       registerParsers();
     }
 
     // Get the class associated with this element.
-    JClassType type = findWidgetOrElementType(elem);
+    JClassType type = findFieldType(elem);
 
     // Declare its field.
     String fieldName = declareField(type.getQualifiedSourceName(), elem);
 
     FieldWriter field = fieldManager.lookup(fieldName);
 
-    // Push the field that will hold this widget to the top of parsedFieldStack
+    // Push the field that will hold this widget on top of the parsedFieldStack
     // to ensure that fields registered by its parsers will be noted as
     // dependencies of the new widget. See registerField.
     fieldManager.push(field);
@@ -567,7 +560,7 @@
   /**
    * Gives the writer the initializer to use for this field instead of the
    * default GWT.create call.
-   * 
+   *
    * @throws IllegalStateException if an initializer has already been set
    */
   public void setFieldInitializer(String fieldName, String factoryMethod) {
@@ -591,7 +584,7 @@
    * token, surrounded by plus signs. This is useful in strings to be handed to
    * setInnerHTML() and setText() calls, to allow a unique dom id attribute or
    * other runtime expression in the string.
-   * 
+   *
    * @param expression
    */
   public String tokenForExpression(String expression) {
@@ -618,8 +611,16 @@
    * of its children being parsed as well).
    */
   void parseDocument(Document doc) throws UnableToCompleteException {
+    JClassType uiBinderClass = getOracle().findType(UiBinder.class.getName());
+    if (!baseClass.isAssignableTo(uiBinderClass)) {
+      die(baseClass.getName() + " must implement UiBinder");
+    }
+
     Element documentElement = doc.getDocumentElement();
-    this.rendered = tokenator.detokenate(parseElement(documentElement));
+    gwtPrefix = documentElement.lookupPrefix(BINDER_URI);
+
+    XMLElement elem = new XMLElement(documentElement, this);
+    this.rendered = tokenator.detokenate(parseDocumentElement(elem));
   }
 
   void write(PrintWriter printWriter) {
@@ -684,59 +685,11 @@
 
   private MessagesWriter createMessagesWriter(String templatePath,
       TreeLogger logger) {
-    return new MessagesWriter(GWT_URI, logger, templatePath, getPackageName(),
+    return new MessagesWriter(BINDER_URI, logger, templatePath, getPackageName(),
         this.implClassName);
   }
 
   /**
-   * Interprets <ui:with> elements.
-   */
-  private void createResource(XMLElement elem) throws UnableToCompleteException {
-    String resourceName = elem.consumeRequiredAttribute("name");
-    String resourceTypeName = elem.consumeRequiredAttribute("type");
-
-    JClassType resourceType = oracle.findType(resourceTypeName);
-    if (resourceType == null) {
-      die("In %s, no such type %s", elem, resourceTypeName);
-    }
-
-    if (elem.getAttributeCount() > 0) {
-      die("In %s, should only find attributes \"name\" and \"type\"");
-    }
-
-    // TODO(rjrjr) This is redundant with BeanParser, I think. Probably
-    // should refactor from here and there to FieldWriter
-
-    FieldWriter fieldWriter = fieldManager.registerField(resourceTypeName,
-        resourceName);
-    OwnerField ownerField = getOwnerClass().getUiField(resourceName);
-
-    // Perhaps it is provided via @UiField
-
-    if (ownerField != null) {
-      if (!resourceType.equals(ownerField.getType().getRawType())) {
-        die("In %s, type must match %s", ownerField);
-      }
-
-      if (ownerField.isProvided()) {
-        fieldWriter.setInitializer("owner." + ownerField.getName());
-        return;
-      }
-    }
-
-    // Nope. Maybe a @UiFactory will make it
-
-    JMethod factoryMethod = getOwnerClass().getUiFactoryMethod(resourceType);
-    if (factoryMethod != null) {
-      fieldWriter.setInitializer(String.format("owner.%s()",
-          factoryMethod.getName()));
-    }
-
-    // If neither of the above, the FieldWriter's default GWT.create call will
-    // do just fine.
-  }
-
-  /**
    * Outputs a bundle resource for a given bundle attribute parser.
    */
   private String declareStaticField(BundleAttributeParser parser) {
@@ -774,32 +727,16 @@
     return elementClass;
   }
 
-  private void findResources(XMLElement binderElement)
-      throws UnableToCompleteException {
-    binderElement.consumeChildElements(new XMLElement.Interpreter<Boolean>() {
-      public Boolean interpretElement(XMLElement elem)
-          throws UnableToCompleteException {
-        if (!(GWT_URI.equals(elem.getNamespaceUri()) && "with".equals(elem.getLocalName()))) {
-          return false; // Not of interest, do not consume
-        }
-
-        createResource(elem);
-
-        return true; // Yum
-      }
-    });
-  }
-
   /**
    * Inspects this element for a gwt:field attribute. If one is found, the
    * attribute is consumed and its value returned.
-   * 
+   *
    * @return The field name declared by an element, or null if none is declared
    */
   private String getFieldName(XMLElement elem) throws UnableToCompleteException {
     String fieldName = null;
     boolean hasOldSchoolId = false;
-    if (elem.hasAttribute("id") && isWidget(elem)) {
+    if (elem.hasAttribute("id") && isWidgetElement(elem)) {
       hasOldSchoolId = true;
       // If an id is specified on the element, use that.
       fieldName = elem.consumeAttribute("id");
@@ -855,7 +792,7 @@
 
   /**
    * Find a set of element parsers for the given ui type.
-   * 
+   *
    * The list of parsers will be returned in order from most- to least-specific.
    */
   private Iterable<ElementParser> getParsersForClass(JClassType type) {
@@ -864,7 +801,7 @@
     /*
      * Let this non-widget parser go first (it finds <m:attribute/> elements).
      * Any other such should land here too.
-     * 
+     *
      * TODO(rjrjr) Need a scheme to associate these with a namespace uri or
      * something?
      */
@@ -891,11 +828,6 @@
     return parsers;
   }
 
-  private String instanceBinderType() {
-    return String.format("AbstractUiBinder.InstanceBinder<%s, %s>",
-        uiRootType.getName(), uiOwnerType.getName());
-  }
-
   /**
    * Writes a field setter if the field is not provided and the field class is
    * compatible with its respective template field.
@@ -917,37 +849,28 @@
     }
   }
 
-  private String parseElement(Element documentElement)
+  /**
+   * Parse the document element and return the source of the Java
+   * class that will implement its UiBinder.
+   */
+  private String parseDocumentElement(XMLElement elem)
       throws UnableToCompleteException {
-    gwtPrefix = documentElement.lookupPrefix(GWT_URI);
 
-    JClassType uiBinderClass = getOracle().findType(UiBinder.class.getName());
-    if (!baseClass.isAssignableTo(uiBinderClass)) {
-      die(baseClass.getName() + " must implement UiBinder");
-    }
-
-    XMLElement elem = new XMLElement(documentElement, this);
-    findResources(elem);
-    messages.findMessagesConfig(elem);
-    elem = elem.consumeSingleChildElement();
-    String rootField = parseWidget(elem);
+    String rootField = new UiBinderParser(this, messages, fieldManager).parse(
+        elem);
 
     StringWriter stringWriter = new StringWriter();
     IndentedWriter niceWriter = new IndentedWriter(
         new PrintWriter(stringWriter));
 
-    if (rootDeclaration != null) {
-      writeBifurcatedBinder(niceWriter);
-    } else {
-      writeEagerBinder(niceWriter, rootField);
-    }
+    writeBinder(niceWriter, rootField);
 
     return stringWriter.toString();
   }
 
   /**
    * Parses a package uri (i.e. package://com.google...).
-   * 
+   *
    * @throws UnableToCompleteException on bad package name
    */
   private JPackage parseNamespacePackage(String ns)
@@ -970,7 +893,6 @@
     // TODO(rjrjr): Allow third-party parsers to register themselves
     // automagically, according to http://b/issue?id=1867118
 
-    // Parses the root element in UiBinder, for non-widget templates
     addParser("com.google.gwt.dom.client.Element",
         "com.google.gwt.uibinder.parsers.DomElementParser");
 
@@ -1018,59 +940,6 @@
   }
 
   /**
-   * Writes a binder that creates a root element in
-   * {@link UiBinder#createUiRoot}, and the rest of the dom in
-   * {@link UiBinder#bindUi}. See a sample in {@link "http://go/gwt-bif-binder"}
-   */
-  private void writeBifurcatedBinder(IndentedWriter w)
-      throws UnableToCompleteException {
-    writePackage(w);
-    writeImports(w);
-    w.newline();
-
-    writeClassOpen(w);
-    writeStatics(w);
-    w.newline();
-
-    // createUiRoot method
-    w.write("public %s createUiRoot(final %s owner) {", uiRootType.getName(),
-        uiOwnerType.getName());
-    w.indent();
-    w.write("return %s;", rootDeclaration);
-    w.outdent();
-    w.write("}");
-    w.newline();
-
-    // bindUi method
-    w.write("public void bindUi(%s root, %s owner) {", uiRootType.getName(),
-        uiOwnerType.getName());
-    w.indent();
-
-    writeGwtFields(w);
-    writeAddedStatements(w);
-    writeInitStatements(w);
-    writeFieldSetters(w);
-    writeHandlers(w);
-    w.newline();
-
-    // close bindUi method
-    w.outdent();
-    w.write("}");
-    w.newline();
-
-    // Close class
-    w.outdent();
-    w.write("}");
-  }
-
-  private void writeClassOpen(IndentedWriter w) {
-    w.write("public class %s extends AbstractUiBinder<%s, %s> \n"
-        + "implements %s {", implClassName, uiRootType.getName(),
-        uiOwnerType.getName(), baseClass.getName());
-    w.indent();
-  }
-
-  /**
    * Writes a binder that creates the entire ui in {@link UiBinder#createUiRoot}
    * and does nothing but fill the clients fields in {@link UiBinder#bindUi}.
    * <p>
@@ -1082,16 +951,13 @@
    * without the map, but am stumped.
    * <p>
    * See a sample in {@link "http://go/gwt-eager-binder"}
-   * 
+   *
    * @throws UnableToCompleteException
    */
-  private void writeEagerBinder(IndentedWriter w, String rootField)
+  private void writeBinder(IndentedWriter w, String rootField)
       throws UnableToCompleteException {
     writePackage(w);
 
-    // Add a few extra imports
-    w.write("import java.util.HashMap;");
-    w.write("import java.util.Map;");
     writeImports(w);
     w.newline();
 
@@ -1099,82 +965,41 @@
     writeStatics(w);
     w.newline();
 
-    // Map from root objects to instance binders
-    w.write("final Map<%1$s, %2$s> rootToBindCommand "
-        + "= new HashMap<%1$s, %2$s>();", uiRootType.getName(),
-        instanceBinderType());
-    w.newline();
-
-    // createUiRoot method
-    w.write("public %s createUiRoot(final %s owner) {", uiRootType.getName(),
+    // createAndBindUi method
+    w.write("public %s createAndBindUi(final %s owner) {", uiRootType.getName(),
         uiOwnerType.getName());
     w.indent();
     w.newline();
 
-    // write instance binder anon class
-    w.write("%1$s instanceBinder = new %1$s() {", instanceBinderType());
-    w.indent();
     writeGwtFields(w);
     w.newline();
 
-    w.write("public %s makeUi() {", uiRootType.getName());
-    w.indent();
     writeAddedStatements(w);
     w.newline();
+
     writeInitStatements(w);
     w.newline();
+
     writeHandlers(w);
     w.newline();
+
+    writeFieldSetters(w);
+
     w.write("return %s;", rootField);
     w.outdent();
     w.write("}");
-    w.newline();
-
-    w.write("public void doBind(%s owner) {", uiOwnerType.getName());
-    w.indent();
-    writeFieldSetters(w);
-    w.outdent();
-    w.write("}");
-
-    // close instance binder anon class
-    w.outdent();
-    w.write("};");
-    w.newline();
-
-    // use instance binder to make the ui, and store the binder away
-    // to wait for the call to bindUi
-    w.write("%s root = instanceBinder.makeUi();", uiRootType.getName());
-    w.write("rootToBindCommand.put(root, instanceBinder);");
-    w.write("return root;");
-
-    // close createUiRoot method
-    w.outdent();
-    w.write("}");
-    w.newline();
-
-    // bindUi method
-    w.write("public void bindUi(%s root, %s owner) {", uiRootType.getName(),
-        uiOwnerType.getName());
-    w.indent();
-
-    // fetch command and run it
-    w.write("%s instanceBinder = rootToBindCommand.remove(root);",
-        instanceBinderType());
-    w.write("assert instanceBinder != null : "
-        + "\"Attempted to bind an unknown UI, or to bind the same one twice\""
-        + ";");
-    w.write("instanceBinder.doBind(owner);");
-
-    // close bindUiMethod
-    w.outdent();
-    w.write("}");
-    w.newline();
 
     // Close class
     w.outdent();
     w.write("}");
   }
 
+  private void writeClassOpen(IndentedWriter w) {
+    w.write("public class %s implements UiBinder<%s, %s>, %s {", implClassName,
+        uiRootType.getName(), uiOwnerType.getName(), baseClass.getName());
+    w.indent();
+  }
+
   /**
    * Write the statements to fill in the fields of the UI owner.
    */
@@ -1211,7 +1036,7 @@
    * gwt:field in the template. For those that have not had constructor
    * generation suppressed, emit GWT.create() calls instantiating them (or die
    * if they have no default constructor).
-   * 
+   *
    * @throws UnableToCompleteException on constructor problem
    */
   private void writeGwtFields(IndentedWriter niceWriter)
@@ -1243,9 +1068,7 @@
 
   private void writeImports(IndentedWriter w) {
     w.write("import com.google.gwt.core.client.GWT;");
-    w.write("import com.google.gwt.dom.client.Element;");
-    w.write("import com.google.gwt.uibinder.client.AbstractUiBinder;");
-    w.write("import com.google.gwt.uibinder.client.DomHolder;");
+    w.write("import com.google.gwt.uibinder.client.UiBinder;");
     w.write("import com.google.gwt.uibinder.client.UiBinderUtil;");
     w.write("import %s.%s;", uiRootType.getPackage().getName(),
         uiRootType.getName());
diff --git a/user/src/com/google/gwt/uibinder/rebind/messages/PlaceholderInterpreter.java b/user/src/com/google/gwt/uibinder/rebind/messages/PlaceholderInterpreter.java
index 3d55938..69ea07b 100644
--- a/user/src/com/google/gwt/uibinder/rebind/messages/PlaceholderInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/messages/PlaceholderInterpreter.java
@@ -86,7 +86,7 @@
       return nextPlaceholder(name, example, value);
     }
 
-    if (uiWriter.isWidget(elem)) {
+    if (uiWriter.isWidgetElement(elem)) {
       uiWriter.die("Found %s in a message that cannot contain widgets", elem);
     }
     return null;
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/OwnerFieldClass.java b/user/src/com/google/gwt/uibinder/rebind/model/OwnerFieldClass.java
index f102a6f..772b959 100644
--- a/user/src/com/google/gwt/uibinder/rebind/model/OwnerFieldClass.java
+++ b/user/src/com/google/gwt/uibinder/rebind/model/OwnerFieldClass.java
@@ -57,7 +57,7 @@
     OwnerFieldClass clazz = FIELD_CLASSES.get(forType);
     if (clazz == null) {
       clazz = new OwnerFieldClass(forType);
-      FIELD_CLASSES.put(forType, clazz); 
+      FIELD_CLASSES.put(forType, clazz);
     }
     return clazz;
   }
@@ -96,6 +96,10 @@
    */
   public JMethod getSetter(String propertyName)
       throws UnableToCompleteException {
+    // TODO(rjrjr) This fails for CheckBox#setValue(Boolean) because it
+    // also finds CheckBox#setValue(Boolean, Boolean). Must fix for 2.0,
+    // when CheckBox#setChecked will go away and CheckBox#setValue must be used
+
     if (ambiguousSetters != null && ambiguousSetters.contains(propertyName)) {
       // TODO(rdamazio): proper logging
       System.out.println("Ambiguous setter requested: " + rawType.getName()
@@ -215,7 +219,7 @@
     for (String propertyName : allSetters.keySet()) {
       Collection<JMethod> propertySetters = allSetters.get(propertyName);
       JMethod setter = disambiguateSetters(propertySetters);
-      
+
       // If no setter could be disambiguated for this property, add it to the
       // set of ambiguous setters. This is later consulted if and only if the
       // setter is used.
diff --git a/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.java b/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.java
index 398e4f2..0ab9b90 100644
--- a/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.java
+++ b/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.java
@@ -24,7 +24,6 @@
 import com.google.gwt.resources.client.CssResource.Strict;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.uibinder.client.UiTemplate;
 
 /**
  * Sample use of a {@code UiBinder} with no dependency on
@@ -48,8 +47,6 @@
     String bodyFont();
   }
 
-  @UiTemplate("DomBasedUi.ui.xml")
-  // Actually, it will default to this name w/o annotation
   interface Binder extends UiBinder<Element, DomBasedUi> {
   }
 
@@ -60,34 +57,20 @@
 
   @UiField SpanElement nameSpan;
   @UiField Element tmElement;
-
-  private final Element root;
-  private final String yourNameHere;
-
-  private boolean gotRoot = false;
+  @UiField Element root;
 
   public DomBasedUi(String yourNameHere) {
-    this.yourNameHere = yourNameHere;
-    root = binder.createUiRoot(this);
-
     // Inject only once.
     if (!stylesInjected) {
       StyleInjector.injectStylesheet(res.style().getText());
       stylesInjected = true;
     }
 
-    // Or if you don't care about deferred rendering...
-//    root = binder.createAndBindUi(this);
-//    nameSpan.setInnerText(yourNameHere);
-    // ...and delete gotRoot and the bulk of #getElement
+    binder.createAndBindUi(this);
+    nameSpan.setInnerText(yourNameHere);
   }
 
   public Element getRoot() {
-    if (!gotRoot) {
-      binder.bindUi(root, this);
-      nameSpan.setInnerText(yourNameHere);
-      gotRoot = true;
-    }
     return root;
   }
 }
diff --git a/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.ui.xml b/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.ui.xml
index 776910d..a4b2688 100644
--- a/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.ui.xml
+++ b/user/src/com/google/gwt/uibinder/sample/client/DomBasedUi.ui.xml
@@ -14,14 +14,10 @@
 <ui:UiBinder
   xmlns:ui='urn:ui:com.google.gwt.uibinder'
   xmlns:res='urn:with:com.google.gwt.uibinder.sample.client.DomBasedUi.Resources'
-
-  ui:defaultLocale="en_us"
-  ui:generateKeys="com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator"
-  ui:generateFormat="com.google.gwt.i18n.rebind.format.PropertiesFormat"
-  ui:generateFilename="myapp_translate_source"
-  ui:generateLocales="default"
   >
-  <div res:class="style.bodyColor style.bodyFont">
+  <div ui:field='root' res:class="style.bodyColor style.bodyFont" 
+      title="The title of this div is localizable">
+    <ui:attribute name='title'/>
     Hello, <span ui:field="nameSpan" />.
     <ui:msg>How goes it?</ui:msg>
       <h2 res:class="style.bodyColor style.bodyFont">Placeholders in localizables</h2>