This fixes issue #785 and re-enables a disabled test in HostedTest related to hosted mode wrapped Java Objects answering "toString()" in JSNI code.
Review by: jat
knorton
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@840 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index a403cd5..659343a 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 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
@@ -83,17 +83,13 @@
*/
public synchronized int getDispId(String jsniMemberRef) {
/*
- * MAGIC: toString is id 0
- *
- * We need to check for toString early on to handle the JavaScript
- * toString method. We do a case insensitive check to make sure that
- * tostring in JavaScript would work.
+ * Map JS toString() onto the Java toString() method.
*
* TODO : is it true that tostring is valid in JavaScript? JavaScript is
* case sensitive.
*/
- if (jsniMemberRef.equalsIgnoreCase("toString")) {
- return 0;
+ if (jsniMemberRef.equals("toString")) {
+ jsniMemberRef = "@java.lang.Object::toString()";
}
// References are of the form "@class::field" or
@@ -205,7 +201,7 @@
return null;
}
- if (dispClassInfo == null) {
+ if (dispClassInfo == null) {
/*
* we need to create a new DispatchClassInfo since we have never seen
* this class before under any source or binary class name
diff --git a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
index c9e5b88..75fbb0a 100644
--- a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
+++ b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 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
@@ -61,10 +61,6 @@
return id.intValue();
}
- public Class getWrappedClass() {
- return cls;
- }
-
private void addMember(Member member, String sig) {
memberById.add(member);
int index = memberById.size() - 1;
@@ -131,38 +127,7 @@
private void lazyInitTargetMembers() {
if (memberById == null) {
memberById = new ArrayList();
- try {
- // MAGIC: 0 is the default property
- memberById.add(cls.getMethod("toString", null));
- } catch (SecurityException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- /*
- * Interfaces do not automatically inherit toString() implicitly. If
- * they have not defined a toString() method then we will pick the one
- * from java.lang.Object::toString() method and use that at slot zero.
- *
- * TODO(mmendez): How should we handle the case where a user writes JSNI
- * code to interact with an instance that is typed as a particular
- * interface? Should a user write JSNI code as follows:
- *
- * x.@com.google.gwt.HasFocus::equals(Ljava/lang/Object;)(y)
- *
- * or
- *
- * x.@java.lang.Object::equals(Ljava/lang/Object;)(y)
- */
- if (cls.isInterface()) {
- try {
- memberById.add(Object.class.getMethod("toString", null));
- } catch (Exception e1) {
- e1.printStackTrace();
- }
- } else {
- e.printStackTrace();
- }
- }
-
+ memberById.add(null); // 0 is reserved; it's magic on Win32
memberIdByName = new HashMap();
lazyInitTargetMembersUsingReflectionHelper(cls);
}
@@ -175,6 +140,19 @@
lazyInitTargetMembersUsingReflectionHelper(superclass);
}
+ /*
+ * TODO(mmendez): How should we handle the case where a user writes JSNI
+ * code to interact with an instance that is typed as a particular
+ * interface? Should a user write JSNI code as follows:
+ *
+ * x.@com.google.gwt.HasFocus::equals(Ljava/lang/Object;)(y)
+ *
+ * or
+ *
+ * x.@java.lang.Object::equals(Ljava/lang/Object;)(y)
+ *
+ */
+
// Get the methods on this class/interface.
//
Method[] methods = targetClass.getDeclaredMethods();
diff --git a/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java b/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
index 8d9ce4c..f83b84f 100644
--- a/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 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
@@ -136,17 +136,6 @@
* @return the member
*/
protected Member getMember(int dispId) {
- if (dispId == 0) {
- try {
- return Object.class.getDeclaredMethod("toString", null);
- } catch (SecurityException e) {
- // Should never get here
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- // Should never get here
- e.printStackTrace();
- }
- }
DispatchClassInfo clsInfo = classLoader.getClassInfoByDispId(dispId);
return clsInfo.getMember(dispId);
}
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java b/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java
index 54fb699..2ab6147 100644
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java
+++ b/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 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
@@ -27,7 +27,7 @@
import java.lang.reflect.Method;
/**
- * Wraps an arbitrary Java Object as a Dispatchable component. The class was
+ * Wraps an arbitrary Java Object as a Dispatch component. The class was
* motivated by the need to expose Java objects into JavaScript.
*
* An instance of this class with no target is used to globally access all
@@ -91,9 +91,6 @@
classLoader.putMethodDispatch(method, dispMethod);
}
jsValue.setWrappedFunction(method.toString(), dispMethod);
-// LowLevelMoz.wrapFunction(scriptObject, method.toString(),
-// dispMethod, (JsValueMoz)jsValue);
- return;
}
}
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java b/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java
index 413a8e1..409c3bd 100644
--- a/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java
+++ b/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java
@@ -27,7 +27,7 @@
import java.lang.reflect.Method;
/**
- * Wraps an arbitrary Java Object as a Dispatchable component. The class was
+ * Wraps an arbitrary Java Object as a Dispatch component. The class was
* motivated by the need to expose Java objects into JavaScript.
*
* An instance of this class with no target is used to globally access all
@@ -44,7 +44,6 @@
* static method calls and field references.
*
* @param cl this class's classLoader
- * @param aScriptObject the execution iframe's window
*/
WebKitDispatchAdapter(CompilingClassLoader cl) {
javaDispatch = new JavaDispatchImpl(cl);
@@ -55,7 +54,6 @@
* This constructor initializes a dispatcher, around a particular instance.
*
* @param cl this class's classLoader
- * @param aScriptObject the execution iframe's window
* @param target the object being wrapped as an IDispatch
*/
WebKitDispatchAdapter(CompilingClassLoader cl, Object target) {
@@ -114,4 +112,9 @@
Object val = JsValueGlue.get(jsValue, field.getType(), "setField");
javaDispatch.setFieldValue(dispId, val);
}
+
+ public String toString() {
+ return getTarget().toString();
+ }
+
}
diff --git a/eclipse/settings/english.dictionary b/eclipse/settings/english.dictionary
index f3d3628..4a93e10 100644
--- a/eclipse/settings/english.dictionary
+++ b/eclipse/settings/english.dictionary
@@ -47241,3 +47241,4 @@
slurp
rectifies
initialize
+initializes
diff --git a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
index bae732e..3e8003d 100644
--- a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
@@ -31,26 +31,47 @@
*/
public class HostedTest extends GWTTestCase {
+ /**
+ * Tests that we can use a source level name for a nested type instead of the
+ * binary name.
+ */
+ protected static class A {
+
+ /**
+ * TODO: document me.
+ */
+ public static class B {
+ int b = 1;
+ public native int getUsingBinaryRef() /*-{
+ return this.@com.google.gwt.dev.jjs.test.HostedTest$A$B::b;
+ }-*/;
+
+ public native int getUsingSourceRef() /*-{
+ return this.@com.google.gwt.dev.jjs.test.HostedTest.A.B::b;
+ }-*/;
+ }
+ }
+
static String sFoo(String s) {
return s + "foo";
}
-
- private native static JavaScriptObject getBoxedBooleanAsObject(boolean v) /*-{
- return new Boolean(v);
- }-*/;
private native static boolean getBoxedBooleanAsBool(boolean v) /*-{
return new Boolean(v);
}-*/;
- private native static JavaScriptObject getBoxedNumberAsObject(double v) /*-{
- return new Number(v);
+ private native static JavaScriptObject getBoxedBooleanAsObject(boolean v) /*-{
+ return new Boolean(v);
}-*/;
private native static double getBoxedNumberAsDouble(double v) /*-{
return new Number(v);
}-*/;
+ private native static JavaScriptObject getBoxedNumberAsObject(double v) /*-{
+ return new Number(v);
+ }-*/;
+
private native static JavaScriptObject getBoxedStringAsObject(String v) /*-{
return new String(v);
}-*/;
@@ -62,6 +83,14 @@
private native static double getDouble(double v) /*-{
return -v;
}-*/;
+
+ private static native float getFloat() /*-{
+ return myFloatValue;
+ }-*/;
+
+ private static native float getFloatString() /*-{
+ return Number(myFloatValue.toString());
+ }-*/;
private native static int getInt(int v) /*-{
return -v;
@@ -71,15 +100,19 @@
private static native Object getIntAsObject() /*-{
return 5;
}-*/;
-
+
private native static String getJSOAsString(JavaScriptObject jso) /*-{
return "" + jso;
}-*/;
-
+
private native static Object getObject(Object o) /*-{
return o;
}-*/;
+ private static native JavaScriptObject getsFooFunc() /*-{
+ return @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
+ }-*/;
+
private native static String getString(String s) /*-{
return s + "me";
}-*/;
@@ -89,26 +122,10 @@
return "test";
}-*/;
- private static native void storeFloat(float f) /*-{
- myFloatValue = f;
- }-*/;
-
- private static native float getFloat() /*-{
- return myFloatValue;
- }-*/;
-
- private static native float getFloatString() /*-{
- return Number(myFloatValue.toString());
- }-*/;
-
private static native int passThroughInt(int val) /*-{
return val;
}-*/;
- private static native JavaScriptObject getsFooFunc() /*-{
- return @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
- }-*/;
-
private static native String sFooCall(String s) /*-{
var func = @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
return func.call(null, s);
@@ -137,175 +154,19 @@
return fooFunc(s);
}-*/;
+ private static native void storeFloat(float f) /*-{
+ myFloatValue = f;
+ }-*/;
+
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
}
- public void testBasic() {
- int iv = getInt(14);
- assertEquals(iv, -14);
- double dv = getDouble(31.5);
- assertEquals(dv, -31.5, 0.0);
- String sv = getString("test");
- assertEquals(sv, "testme");
- Object oin = String.class;
- Object oout = getObject(oin);
- assertEquals(oin, oout);
- }
-
public void test32BitInt() {
assertEquals(Integer.MAX_VALUE, passThroughInt(Integer.MAX_VALUE));
assertEquals(Integer.MIN_VALUE, passThroughInt(Integer.MIN_VALUE));
}
- public void testByteMarshalling() {
- byte b = 100;
- assertEquals(100, byteAsInt(b));
- b = -125;
- assertEquals(-125, byteAsInt(b));
- }
-
- public void testFunctionCaching() {
- assertEquals("barfoo", sFooCall("bar"));
- assertEquals("barfoo", sFooDirect("bar"));
- assertEquals("barfoo", sFooInvoke("bar"));
- assertEquals("barfoo", sFooRoundTrip(getsFooFunc(), "bar"));
-
- assertEquals("barfoo", fooCall("bar"));
- assertEquals("barfoo", fooDirect("bar"));
- assertEquals("barfoo", fooRoundTrip(getFooFunc(), "bar"));
-
- String sFooString = getsFooFunc().toString();
- assertEquals(sFooString, sFooFuncAsStr());
- assertEquals(sFooString, sFooFuncToString());
- String fooString = getFooFunc().toString();
- assertEquals(fooString, fooFuncAsStr());
- assertEquals(fooString, fooFuncToString());
- }
-
- public void testJsniFormats() {
- jsniA();
- jsniB();
- jsniC();
- jsniD();
- jsniE();
- jsniF();
- jsniG();
- jsniH();
- jsniI();
- jsniJ();
- jsniK();
- jsniL();
- }
-
- public void testFloat() {
- storeFloat(Float.MIN_VALUE);
- float f = getFloat();
- assertTrue(f == Float.MIN_VALUE);
- f = getFloatString();
- assertTrue(f == Float.MIN_VALUE);
- storeFloat(Float.MAX_VALUE);
- f = getFloat();
- assertTrue(f == Float.MAX_VALUE);
- f = getFloatString();
- assertTrue(f == Float.MAX_VALUE);
- }
-
- public void testLocalJsni() {
-
- class Foo {
- native String a() /*-{
- return "blah";
- }-*/;
-
- native String b() /*-{
- return this.@com.google.gwt.dev.jjs.test.HostedTest$1$Foo::a()();
- }-*/;
-
- String c() {
- return a();
- }
- }
-
- Foo f = new Foo();
- assertEquals(f.a(), "blah");
- assertEquals(f.b(), "blah");
- assertEquals(f.c(), "blah");
-
- Foo fo = new Foo() {
- native String a() /*-{
- return "oblah";
- }-*/;
-
- native String b() /*-{
- return this.@com.google.gwt.dev.jjs.test.HostedTest$1$Foo::a()();
- }-*/;
-
- native String c() /*-{
- return this.@com.google.gwt.dev.jjs.test.HostedTest$1::a()();
- }-*/;
- };
-
- assertEquals(fo.a(), "oblah");
- assertEquals(fo.b(), "oblah");
- assertEquals(fo.c(), "oblah");
- }
-
- public void testLongMarshalling() {
- // a big number that cannot accurately be represented as a double
- long l = 1234567890123456789L;
- double d = l;
- assertTrue(isEq(l, d));
- }
-
- /**
- * Tests that we can use a source level name for a nested type instead of the
- * binary name.
- */
- protected static class A {
-
- /**
- * TODO: document me.
- */
- public static class B {
- int b = 1;
- public native int getUsingSourceRef() /*-{
- return this.@com.google.gwt.dev.jjs.test.HostedTest.A.B::b;
- }-*/;
-
- public native int getUsingBinaryRef() /*-{
- return this.@com.google.gwt.dev.jjs.test.HostedTest$A$B::b;
- }-*/;
- }
- }
-
- /**
- * Tests that we are able to use binary and source level names when referencing
- * a Java identifier from JSNI.
- */
- public void testJavaMemberRefResolution() {
- A.B b = new A.B();
- assertEquals(1, b.getUsingSourceRef());
- assertEquals(1, b.getUsingBinaryRef());
- }
-
- /*
- * Test that returning strings from methods declared as returning Object
- * works, and that returning a primitive does not.
- */
- public void testObjectReturns() {
- String str = (String)getStringAsObject();
- assertEquals(str, "test");
- try {
- getIntAsObject();
- // should have thrown an exception in hosted mode,
- // so fail unless we are in web mode
- assertTrue(GWT.isScript());
- } catch (IllegalArgumentException e) {
- // expected exception
- }
- }
-
/*
* Test that returning JavaScript boxed primitives works as expected.
* Currently only String is automatically unboxed, so Boolean and Number
@@ -326,12 +187,87 @@
assertEquals(sv, "test");
}
+ public void testBasic() {
+ int iv = getInt(14);
+ assertEquals(iv, -14);
+ double dv = getDouble(31.5);
+ assertEquals(dv, -31.5, 0.0);
+ String sv = getString("test");
+ assertEquals(sv, "testme");
+ Object oin = String.class;
+ Object oout = getObject(oin);
+ assertEquals(oin, oout);
+ }
+
+ public void testByteMarshalling() {
+ byte b = 100;
+ assertEquals(100, byteAsInt(b));
+ b = -125;
+ assertEquals(-125, byteAsInt(b));
+ }
+
+ public void testFloat() {
+ storeFloat(Float.MIN_VALUE);
+ float f = getFloat();
+ assertTrue(f == Float.MIN_VALUE);
+ f = getFloatString();
+ assertTrue(f == Float.MIN_VALUE);
+ storeFloat(Float.MAX_VALUE);
+ f = getFloat();
+ assertTrue(f == Float.MAX_VALUE);
+ f = getFloatString();
+ assertTrue(f == Float.MAX_VALUE);
+ }
+
+ public void testFunctionCaching() {
+ assertEquals("barfoo", sFooCall("bar"));
+ assertEquals("barfoo", sFooDirect("bar"));
+ assertEquals("barfoo", sFooInvoke("bar"));
+ assertEquals("barfoo", sFooRoundTrip(getsFooFunc(), "bar"));
+
+ assertEquals("barfoo", fooCall("bar"));
+ assertEquals("barfoo", fooDirect("bar"));
+ assertEquals("barfoo", fooRoundTrip(getFooFunc(), "bar"));
+
+ String sFooString = getsFooFunc().toString();
+ assertEquals(sFooString, sFooFuncAsStr());
+ assertEquals(sFooString, sFooFuncToString());
+ String fooString = getFooFunc().toString();
+ assertEquals(fooString, fooFuncAsStr());
+ assertEquals(fooString, fooFuncToString());
+ }
+
+ /**
+ * Tests that we are able to use binary and source level names when referencing
+ * a Java identifier from JSNI.
+ */
+ public void testJavaMemberRefResolution() {
+ A.B b = new A.B();
+ assertEquals(1, b.getUsingSourceRef());
+ assertEquals(1, b.getUsingBinaryRef());
+ }
+
+ public void testJsniFormats() {
+ jsniA();
+ jsniB();
+ jsniC();
+ jsniD();
+ jsniE();
+ jsniF();
+ jsniG();
+ jsniH();
+ jsniI();
+ jsniJ();
+ jsniK();
+ jsniL();
+ }
+
/**
* Tests that using the JavaScript toString method results in a call to
* the java.lang.Object::toString() method.
*
*/
- public void disabledTestJSNIToStringResolution() {
+ public void testJSNIToStringResolution() {
class Foo {
public String toString() {
return "FOO";
@@ -340,19 +276,83 @@
assertEquals("FOO", callJSNIToString(new Foo()));
}
-
- private native String callJSNIToString(Object obj) /*-{
- return obj.toString();
- }-*/;
+
+ public void testLocalJsni() {
+
+ class Foo {
+ native String a() /*-{
+ return "blah";
+ }-*/;
+
+ native String b() /*-{
+ return this.@com.google.gwt.dev.jjs.test.HostedTest$2$Foo::a()();
+ }-*/;
+
+ String c() {
+ return a();
+ }
+ }
+
+ Foo f = new Foo();
+ assertEquals(f.a(), "blah");
+ assertEquals(f.b(), "blah");
+ assertEquals(f.c(), "blah");
+
+ Foo fo = new Foo() {
+ native String a() /*-{
+ return "oblah";
+ }-*/;
+
+ native String b() /*-{
+ return this.@com.google.gwt.dev.jjs.test.HostedTest$2$Foo::a()();
+ }-*/;
+
+ native String c() /*-{
+ return this.@com.google.gwt.dev.jjs.test.HostedTest$1::a()();
+ }-*/;
+ };
+
+ assertEquals(fo.a(), "oblah");
+ assertEquals(fo.b(), "oblah");
+ assertEquals(fo.c(), "oblah");
+ }
+
+ public void testLongMarshalling() {
+ // a big number that cannot accurately be represented as a double
+ long l = 1234567890123456789L;
+ double d = l;
+ assertTrue(isEq(l, d));
+ }
+
+ /*
+ * Test that returning strings from methods declared as returning Object
+ * works, and that returning a primitive does not.
+ */
+ public void testObjectReturns() {
+ String str = (String)getStringAsObject();
+ assertEquals(str, "test");
+ try {
+ getIntAsObject();
+ // should have thrown an exception in hosted mode,
+ // so fail unless we are in web mode
+ assertTrue(GWT.isScript());
+ } catch (IllegalArgumentException e) {
+ // expected exception
+ }
+ }
String foo(String s) {
return s + "foo";
}
-
+
private native int byteAsInt(byte b) /*-{
return b;
}-*/;
+ private native String callJSNIToString(Object obj) /*-{
+ return obj.toString();
+ }-*/;
+
private native String fooCall(String s) /*-{
var f = this.@com.google.gwt.dev.jjs.test.HostedTest::foo(Ljava/lang/String;);
return f.call(this, s);