Fixes UiBinder regression that broke custom subclasses of Image
Review at http://gwt-code-reviews.appspot.com/302801

Review by: amitmanjhi@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7859 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/ImageParser.java b/user/src/com/google/gwt/uibinder/elementparsers/ImageParser.java
index ea3d122..8c122ea 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/ImageParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/ImageParser.java
@@ -17,9 +17,11 @@
 
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.uibinder.rebind.UiBinderWriter;
 import com.google.gwt.uibinder.rebind.XMLElement;
-import com.google.gwt.user.client.ui.Image;
 
 /**
  * Custom parsing of Image widgets. Sets ImageResource via constructor, because
@@ -29,11 +31,17 @@
 
   public void parse(XMLElement elem, String fieldName, JClassType type,
       UiBinderWriter writer) throws UnableToCompleteException {
-    String resource = elem.consumeImageResourceAttribute("resource");
-    if (null != resource) {
-      writer.setFieldInitializerAsConstructor(fieldName,
-          writer.getOracle().findType(Image.class.getName()),
-          resource);
+    if (hasImageResourceConstructor(writer.getOracle(), type)) {
+      String resource = elem.consumeImageResourceAttribute("resource");
+      if (null != resource) {
+        writer.setFieldInitializerAsConstructor(fieldName, type, resource);
+      }
     }
   }
+
+  private boolean hasImageResourceConstructor(TypeOracle typeOracle,
+      JClassType type) {
+    JType imageResourceType = typeOracle.findType(ImageResource.class.getName());
+    return type.findConstructor(new JType[] {imageResourceType}) != null;
+  }
 }
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/ImageParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/ImageParserTest.java
index d2793ea..16a8705 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/ImageParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/ImageParserTest.java
@@ -16,6 +16,7 @@
 package com.google.gwt.uibinder.elementparsers;
 
 import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
 import com.google.gwt.uibinder.rebind.FieldWriter;
 
 import junit.framework.TestCase;
@@ -30,6 +31,32 @@
 public class ImageParserTest extends TestCase {
   private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.Image";
 
+  private static final MockJavaResource IMAGE_SUBCLASS_NO_CONSTRUCTOR = new MockJavaResource(
+      "my.MyImage") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.Image;\n");
+      code.append("public class MyImage extends Image {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private static final MockJavaResource IMAGE_SUBCLASS_RESOURCE_CONSTRUCTOR = new MockJavaResource(
+      "my.MyConstructedImage") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.Image;\n");
+      code.append("import com.google.gwt.resources.client.ImageResource;\n");
+      code.append("public class MyConstructedImage extends Image {\n");
+      code.append("  public MyConstructedImage(ImageResource r) { super(r); }");
+      code.append("}\n");
+      return code;
+    }
+  };
   private ElementParserTester tester;
 
   @Override
@@ -38,6 +65,52 @@
     tester = new ElementParserTester(PARSED_TYPE, new ImageParser());
   }
 
+  public void testHappyWithDefaultInstantiableSubclass()
+      throws UnableToCompleteException, SAXException, IOException {
+    tester = new ElementParserTester("my.MyImage", new ImageParser(),
+        IMAGE_SUBCLASS_NO_CONSTRUCTOR, IMAGE_SUBCLASS_RESOURCE_CONSTRUCTOR);
+    ImageParser parser = new ImageParser();
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyImage resource='{someImageResource}'/> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyImage"), "fieldName", 
+        tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertNull(w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithSubclassWithImageResourceConstructor()
+      throws UnableToCompleteException, SAXException, IOException {
+    ImageParser parser = new ImageParser();
+    tester = new ElementParserTester("my.MyConstructedImage", new ImageParser(),
+        IMAGE_SUBCLASS_NO_CONSTRUCTOR, IMAGE_SUBCLASS_RESOURCE_CONSTRUCTOR);
+
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyConstructedImage resource='{someImageResource}'/> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyConstructedImage"), "fieldName", 
+        tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertEquals("new my.MyConstructedImage(someImageResource)",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
   public void testHappyWithResource() throws UnableToCompleteException,
       SAXException, IOException {
     StringBuffer b = new StringBuffer();
diff --git a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
index 861a0a7..c9e5c0e 100644
--- a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
+++ b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
@@ -174,8 +174,10 @@
     protected CharSequence getContent() {
       StringBuffer code = new StringBuffer();
       code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("import com.google.gwt.resources.client.ImageResource;\n");
       code.append("public class Image extends Widget {\n");
       code.append("  public Image() {} ");
+      code.append("  public Image(ImageResource r) {} ");
       code.append("}\n");
       return code;
     }
@@ -222,7 +224,7 @@
     }
   };
   public static final MockJavaResource LIST_BOX = new MockJavaResource(
-    "com.google.gwt.user.client.ui.ListBox") {
+      "com.google.gwt.user.client.ui.ListBox") {
     @Override
     protected CharSequence getContent() {
       StringBuffer code = new StringBuffer();
diff --git a/user/test/com/google/gwt/uibinder/test/client/FooImage.java b/user/test/com/google/gwt/uibinder/test/client/FooImage.java
new file mode 100644
index 0000000..cfddeea
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/FooImage.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+import com.google.gwt.user.client.ui.Image;
+
+/**
+ * Tests that custom Image subclasses work
+ */
+public class FooImage extends Image {
+  public FooImage() {
+    super();
+  }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
index 1967fdf..d519e4b 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -445,6 +445,15 @@
     assertEquals("funny characters \" ' ' & < > > { }", t);
   }
 
+  public void testCustomImageClass() {
+    ImageResource resource = widgetUi.prettyImage;
+    Image widget = widgetUi.fooImage;
+    assertEquals(resource.getWidth(), widget.getOffsetWidth());
+    assertEquals(resource.getHeight(), widget.getOffsetHeight());
+    assertEquals(resource.getTop(), widget.getOriginTop());
+    assertEquals(resource.getLeft(), widget.getOriginLeft());
+  }
+  
   public void testImageResourceInImageWidget() {
     ImageResource resource = widgetUi.prettyImage;
     Image widget = widgetUi.babyWidget;
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
index a74ceac..6040b3a 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
@@ -126,6 +126,7 @@
   @UiField SpanElement totallyPrivateStyleSpan;
   @UiField ImageResource prettyImage;
   @UiField ImageResource prettyTilingImage;
+  @UiField FooImage fooImage;
   @UiField Image babyWidget;
   @UiField ParagraphElement simpleSpriteParagraph;
   @UiField DataResource heartCursorResource;
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
index 40e8dba..09fa323 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
@@ -198,6 +198,9 @@
       <gwt:Image ui:field='babyWidget' resource='{prettyImage}'
           altText='expected alt text' styleName='expected style name'
       />
+      <demo:FooImage ui:field='fooImage' resource='{prettyImage}'
+          altText='expected alt text' styleName='expected style name'
+      />
       </div>
 
       <p ui:field='simpleSpriteParagraph'