Improves Dev Mode reporting of JavaScriptException to include method
name and args.
Review at http://gwt-code-reviews.appspot.com/1570803
Review by: tobyr@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10704 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java b/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
index 63ad7ea..871e6db 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
@@ -28,6 +28,7 @@
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -241,8 +242,8 @@
// JSException
exceptionValue = returnValue.getValue().toString();
}
- RuntimeException exception = ModuleSpace.createJavaScriptException(
- ccl, exceptionValue);
+ RuntimeException exception = ModuleSpace.createJavaScriptException(ccl,
+ exceptionValue, methodName + "(" + Arrays.toString(args) + ")");
// reset the stack trace to here to minimize GWT infrastructure in
// the stack trace
exception.fillInStackTrace();
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
index ecb8ff6..9a11514 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
@@ -55,19 +55,28 @@
}
/**
+ * Equivalent to {@link #createJavaScriptException(ClassLoader,Object,String)
+ * createJavaScriptException(cl, exception, "")}.
+ */
+ protected static RuntimeException createJavaScriptException(ClassLoader cl,
+ Object exception) {
+ return createJavaScriptException(cl, exception, "");
+ }
+
+ /**
* Create a JavaScriptException object. This must be done reflectively, since
* this class will have been loaded from a ClassLoader other than the
* session's thread.
*/
protected static RuntimeException createJavaScriptException(ClassLoader cl,
- Object exception) {
+ Object exception, String message) {
Exception caught;
try {
Class<?> javaScriptExceptionClass = Class.forName(
"com.google.gwt.core.client.JavaScriptException", true, cl);
Constructor<?> ctor = javaScriptExceptionClass.getDeclaredConstructor(
- Object.class);
- return (RuntimeException) ctor.newInstance(new Object[] {exception});
+ Object.class, String.class);
+ return (RuntimeException) ctor.newInstance(new Object[] {exception, message});
} catch (InstantiationException e) {
caught = e;
} catch (IllegalAccessException e) {
diff --git a/user/src/com/google/gwt/core/client/JavaScriptException.java b/user/src/com/google/gwt/core/client/JavaScriptException.java
index 36efebc..5c44f48 100644
--- a/user/src/com/google/gwt/core/client/JavaScriptException.java
+++ b/user/src/com/google/gwt/core/client/JavaScriptException.java
@@ -45,23 +45,23 @@
*/
public final class JavaScriptException extends RuntimeException {
- private static String getDescription(Object e) {
+ private static String getExceptionDescription(Object e) {
if (e instanceof JavaScriptObject) {
- return getDescription0((JavaScriptObject) e);
+ return getExceptionDescription0((JavaScriptObject) e);
} else {
return e + "";
}
}
- private static native String getDescription0(JavaScriptObject e) /*-{
+ private static native String getExceptionDescription0(JavaScriptObject e) /*-{
return (e == null) ? null : e.message;
}-*/;
- private static String getName(Object e) {
+ private static String getExceptionName(Object e) {
if (e == null) {
return "null";
} else if (e instanceof JavaScriptObject) {
- return getName0((JavaScriptObject) e);
+ return getExceptionName0((JavaScriptObject) e);
} else if (e instanceof String) {
return "String";
} else {
@@ -69,11 +69,11 @@
}
}
- private static native String getName0(JavaScriptObject e) /*-{
+ private static native String getExceptionName0(JavaScriptObject e) /*-{
return (e == null) ? null : e.name;
}-*/;
- private static String getProperties(Object e) {
+ private static String getExceptionProperties(Object e) {
return (GWT.isScript() && e instanceof JavaScriptObject)
? StackTraceCreator.getProperties((JavaScriptObject) e) : "";
}
@@ -82,7 +82,7 @@
* The original description of the JavaScript exception this class wraps,
* initialized as <code>e.message</code>.
*/
- private String description;
+ private String description = "";
/**
* The underlying exception this class wraps.
@@ -104,7 +104,18 @@
* @param e the object caught in JavaScript that triggered the exception
*/
public JavaScriptException(Object e) {
+ this(e, "");
+ }
+
+ /**
+ * @param e the object caught in JavaScript that triggered the exception
+ * @param description to include in getMessage(), e.g. at the top of a stack
+ * trace
+ */
+ public JavaScriptException(Object e, String description) {
this.e = e;
+ this.description = description;
+
/*
* In Development Mode, JavaScriptExceptions are created exactly when the
* native method returns and their stack traces are fixed-up by the
@@ -117,7 +128,7 @@
StackTraceCreator.createStackTrace(this);
}
}
-
+
public JavaScriptException(String name, String description) {
this.message = "JavaScript " + name + " exception: " + description;
this.name = name;
@@ -176,9 +187,9 @@
}
private void init() {
- name = getName(e);
- description = getDescription(e);
- message = "(" + name + "): " + description + getProperties(e);
+ name = getExceptionName(e);
+ description = description + ": " + getExceptionDescription(e);
+ message = "(" + name + ") " + getExceptionProperties(e) + description;
}
}
diff --git a/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java b/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java
index 54d2eed..d4b193e 100644
--- a/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java
+++ b/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java
@@ -62,10 +62,10 @@
fail();
} catch (JavaScriptException e) {
assertEquals("myName", e.getName());
- assertEquals("myDescription", e.getDescription());
+ assertDescription(e, "myDescription");
assertSame(jso, e.getException());
assertTrue(e.getMessage().contains("myName"));
- assertTrue(e.getMessage().contains("myDescription"));
+ assertTrue(e.getMessage().contains(e.getDescription()));
if (extraPropertiesShouldBePresent) {
assertTrue(
"message does not contain 'extraField', but should: "
@@ -115,7 +115,7 @@
assertSame(e, t);
}
}
-
+
@WithProperties({
@Property(name = "compiler.stackMode", value = "emulated")
})
@@ -142,7 +142,7 @@
*/
assertJsoProperties(GWT.isScript());
}
-
+
@WithProperties({
@Property(name = "compiler.stackMode", value = "strip")
})
@@ -163,7 +163,7 @@
fail();
} catch (JavaScriptException e) {
assertEquals("null", e.getName());
- assertEquals("null", e.getDescription());
+ assertDescription(e, "null");
assertEquals(null, e.getException());
assertTrue(e.getMessage().contains("null"));
}
@@ -181,10 +181,10 @@
fail();
} catch (JavaScriptException e) {
assertEquals(o.getClass().getName(), e.getName());
- assertEquals("myLameObject", e.getDescription());
+ assertDescription(e, "myLameObject");
assertEquals(null, e.getException());
assertTrue(e.getMessage().contains(o.getClass().getName()));
- assertTrue(e.getMessage().contains("myLameObject"));
+ assertTrue(e.getMessage().contains(e.getDescription()));
}
}
@@ -194,9 +194,20 @@
fail();
} catch (JavaScriptException e) {
assertEquals("String", e.getName());
- assertEquals("foobarbaz", e.getDescription());
+ assertDescription(e, "foobarbaz");
assertEquals(null, e.getException());
- assertTrue(e.getMessage().contains("foobarbaz"));
+ assertTrue(e.getMessage().contains(e.getDescription()));
}
}
+
+ private void assertDescription(JavaScriptException e, String description) {
+ if (!GWT.isScript()) {
+ assertTrue("Should start with method name",
+ e.getDescription().startsWith(
+ "@com.google.gwt.core.client.JavaScriptExceptionTest::"
+ + "throwNative(Ljava/lang/Object;)"));
+ }
+ assertTrue("Should end with " + description,
+ e.getDescription().endsWith(description));
+ }
}