Introducing FieldTypeWriter, an enum that identifies field writers and
defines precedences useful for disambiguation when sorting builders
in the Widgets ctor.

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


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10127 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java b/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
index ecb25e5..8eb5814 100644
--- a/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
@@ -58,15 +58,17 @@
   private String initializer;
   private boolean written;
   private int buildPrecedence;
-  private MortalLogger logger;
+  private final MortalLogger logger;
+  private final FieldWriterType fieldType;
 
-  public AbstractFieldWriter(String name, MortalLogger logger) {
+  public AbstractFieldWriter(String name, FieldWriterType fieldType, MortalLogger logger) {
     if (name == null) {
       throw new RuntimeException("name cannot be null");
     }
     this.name = name;
     this.logger = logger;
     this.buildPrecedence = 1;
+    this.fieldType = fieldType;
   }
 
   @Override
@@ -89,6 +91,11 @@
     return buildPrecedence;
   }
 
+  @Override
+  public FieldWriterType getFieldType() {
+    return fieldType;
+  }
+
   public String getInitializer() {
     return initializer;
   }
@@ -165,14 +172,15 @@
   public void writeFieldBuilder(IndentedWriter w, int getterCount,
     OwnerField ownerField) throws UnableToCompleteException {
     if (getterCount > 1) {
-      w.write("%s;  // more than one getter call detected. Precedence: %s",
-            FieldManager.getFieldBuilder(name), getBuildPrecedence());
+      w.write("%s;  // more than one getter call detected. Type: %s, precedence: %s",
+            FieldManager.getFieldBuilder(name), getFieldType(), getBuildPrecedence());
       return;
     }
 
     if (getterCount == 0 && ownerField != null) {
-      w.write("%s;  // no getter call detected but must bind to ui:field. Precedence: %s",
-          FieldManager.getFieldBuilder(name), getBuildPrecedence());
+      w.write("%s;  // no getter call detected but must bind to ui:field. "
+          + "Type: %s, precedence: %s", FieldManager.getFieldBuilder(name),
+          getFieldType(), getBuildPrecedence());
     }
   }
 
@@ -208,8 +216,8 @@
 
     w.newline();
     w.write("/**");
-    w.write(" * Getter for %s called %s times. Build precedence: %s.",
-        name, getterCount, getBuildPrecedence());
+    w.write(" * Getter for %s called %s times. Type: %s. Build precedence: %s.",
+        name, getterCount, getFieldType(), getBuildPrecedence());
     w.write(" */");
     if (getterCount > 1) {
       w.write("private %1$s %2$s;", getQualifiedSourceName(), name);
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldManager.java b/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
index 158618e..5abd2a9 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
@@ -42,7 +42,13 @@
   private static final Comparator<FieldWriter> BUILD_DEFINITION_SORT =
       new Comparator<FieldWriter>() {
     public int compare(FieldWriter field1, FieldWriter field2) {
-      return field2.getBuildPrecedence() - field1.getBuildPrecedence();
+      // First get type precedence, if ties the field precedence is used.
+      int precedence = field2.getFieldType().getBuildPrecedence()
+          - field1.getFieldType().getBuildPrecedence();
+      if (precedence == 0) {
+        precedence = field2.getBuildPrecedence() - field1.getBuildPrecedence();
+      }
+      return precedence;
     }
   };
 
@@ -158,16 +164,22 @@
    * fields (see {@link UiBinderWriter#declareDomIdHolder()}) used by an HTMLPanel
    * will be declared before it is.
    *
+   * @param fieldWriterType the field writer type associated
    * @param fieldType the type of the new field
    * @param fieldName the name of the new field
    * @return a new {@link FieldWriter} instance
    * @throws UnableToCompleteException on duplicate name
    */
+  public FieldWriter registerField(FieldWriterType fieldWriterType,
+      JClassType fieldType, String fieldName) throws UnableToCompleteException {
+    FieldWriter field = new FieldWriterOfExistingType(
+        fieldWriterType, fieldType, fieldName, logger);
+    return registerField(fieldName, field);
+  }
+
   public FieldWriter registerField(JClassType fieldType, String fieldName)
       throws UnableToCompleteException {
-    FieldWriter field = new FieldWriterOfExistingType(fieldType, fieldName,
-        logger);
-    return registerField(fieldName, field);
+    return registerField(FieldWriterType.DEFAULT, fieldType, fieldName);
   }
 
   public FieldWriter registerField(String type, String fieldName)
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
index 7cfab03..6ed3527 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
@@ -94,6 +94,11 @@
   int getBuildPrecedence();
 
   /**
+   * Gets the type of this field.
+   */
+  FieldWriterType getFieldType();
+
+  /**
    * Returns the custom initializer for this field, or null if it is not set.
    */
   String getInitializer();
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java
index b7aa445..a9df6e7 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfExistingType.java
@@ -26,8 +26,9 @@
   final JClassType type;
   final MortalLogger logger;
 
-  FieldWriterOfExistingType(JClassType type, String name, MortalLogger logger) {
-    super(name, logger);
+  FieldWriterOfExistingType(FieldWriterType fieldType,
+      JClassType type, String name, MortalLogger logger) {
+    super(name, fieldType, logger);
     this.logger = logger;
     if (type == null) {
       throw new IllegalArgumentException("type cannot be null");
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResource.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResource.java
index 315ae19..6d074b7 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResource.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResource.java
@@ -35,7 +35,7 @@
 
   public FieldWriterOfGeneratedCssResource(JType stringType,
       ImplicitCssResource css, MortalLogger logger) {
-    super(css.getName(), logger);
+    super(css.getName(), FieldWriterType.GENERATED_CSS, logger);
     this.stringType = stringType;
     this.css = css;
   }
@@ -74,7 +74,7 @@
   @Override
   public void writeFieldBuilder(IndentedWriter w,
       int getterCount, OwnerField ownerField) throws UnableToCompleteException {
-    w.write("%s;  // generated css resource must be always created. Precedence: %s",
-        FieldManager.getFieldBuilder(getName()), getBuildPrecedence());
+    w.write("%s;  // generated css resource must be always created. Type: %s. Precedence: %s",
+        FieldManager.getFieldBuilder(getName()), getFieldType(), getBuildPrecedence());
   }
 }
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedType.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedType.java
index 1cd3a1c..5b353b8 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedType.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedType.java
@@ -27,9 +27,9 @@
   private final String typeName;
   private final JClassType assignableType;
 
-  public FieldWriterOfGeneratedType(JClassType assignableType,
-      String typePackage, String typeName, String name, MortalLogger logger) {
-    super(name, logger);
+  public FieldWriterOfGeneratedType(JClassType assignableType, String typePackage,
+      String typeName, String name, MortalLogger logger) {
+    super(name, FieldWriterType.GENERATED_BUNDLE, logger);
     if (assignableType == null) {
       throw new RuntimeException("assignableType must not be null");
     }
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriterType.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriterType.java
new file mode 100644
index 0000000..2747e24
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriterType.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * A simple enum holding all FieldWriter types.
+ */
+enum FieldWriterType {
+
+  GENERATED_BUNDLE(4),
+  GENERATED_CSS(3),
+  IMPORTED(2),  // ui:with clauses.
+  DEFAULT(1);
+
+  /**
+   * Holds the build precedence for this type. This is used when sorting the
+   * field builders in the Widgets constructor.
+   * {@see com.google.gwt.uibinder.rebind.initializeWidgetsInnerClass}
+   */
+  private int buildPrecedence;
+
+  private FieldWriterType(int precedence) {
+    this.buildPrecedence = precedence;
+  }
+
+  public int getBuildPrecedence() {
+    return buildPrecedence;
+  }
+}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
index 4cf8a47..ab6b5ad 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -259,8 +259,8 @@
       writer.die(elem, "Should only find attributes \"field\" and \"type\"");
     }
 
-    FieldWriter fieldWriter = fieldManager.registerField(resourceType,
-        resourceName);
+    FieldWriter fieldWriter = fieldManager.registerField(
+        FieldWriterType.IMPORTED, resourceType, resourceName);
     OwnerField ownerField = writer.getOwnerClass().getUiField(resourceName);
 
     /* Perhaps it is provided via @UiField */
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index f0fd59b..1496c59 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -1083,8 +1083,7 @@
     fieldManager.registerFieldOfGeneratedType(
         oracle.findType(ClientBundle.class.getName()),
         bundleClass.getPackageName(), bundleClass.getClassName(),
-        bundleClass.getFieldName())
-      .setBuildPrecedence(Integer.MAX_VALUE);  // must be the first thing built.
+        bundleClass.getFieldName());
 
     // Allow GWT.create() to init the field, the default behavior
 
@@ -1102,7 +1101,6 @@
         String fieldName = css.getName();
         FieldWriter cssField = fieldManager.require(fieldName);
         cssField.addStatement("%s.ensureInjected();", fieldName);
-        cssField.setBuildPrecedence(Integer.MAX_VALUE - 1);  // must be just below its bundle.
       }
       writeBinderForAttachableStrategy(niceWriter, rootField);
     } else {
diff --git a/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java b/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java
index 4e2f10e..9fc1691 100644
--- a/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java
@@ -63,6 +63,7 @@
 
     assertEquals(stringType, f.getReturnType(new String[] {
         "fieldName", "ableBaker"}, new MonitoredLogger(TreeLogger.NULL)));
+    assertEquals(FieldWriterType.GENERATED_CSS, f.getFieldType());
   }
 
   public void testDashesMatchesCamels() {
@@ -78,5 +79,7 @@
 
     assertEquals(stringType, f.getReturnType(new String[] {
         "fieldName", "able-baker"}, new MonitoredLogger(TreeLogger.NULL)));
+
+    assertEquals(FieldWriterType.GENERATED_CSS, f.getFieldType());
   }
 }