Removes JavaScriptException dependency from c.g.gwt.core.shared.

Note that, this change also makes isClassMetadataEnabled public in the emulated version
of the java/lang/Class so that the logic for resolving types for the no metadata case
can be compiled out.

Change-Id: Ib610bb27cefb3d405e2126417008f4134743e723
Review-Link: https://gwt-review.googlesource.com/#/c/2840/
diff --git a/tools/api-checker/config/gwt25_26userApi.conf b/tools/api-checker/config/gwt25_26userApi.conf
index 6c2261a..23bcc69 100644
--- a/tools/api-checker/config/gwt25_26userApi.conf
+++ b/tools/api-checker/config/gwt25_26userApi.conf
@@ -96,6 +96,7 @@
 :user/src/com/google/web/bindery/autobean/shared/ValueCodexHelper.java\
 :user/src/com/google/web/bindery/autobean/**/impl/**\
 :user/src/com/google/gwt/core/client/impl/WeakMapping.java\
+:user/src/com/google/gwt/core/shared/impl/ThrowableTypeResolver.java\
 :user/src/com/google/gwt/i18n/**/impl/cldr/**\
 :user/src/com/google/gwt/junit/*.java\
 :user/src/com/google/gwt/junit/client/GWTTestCase.java\
@@ -129,6 +130,7 @@
 ##############################################
 #excluded packages colon separated list
 excludedPackages com.google.gwt.core.client.impl\
+:com.google.gwt.core.shared.impl\
 :com.google.gwt.editor.client.impl\
 :com.google.gwt.junit.client.impl\
 :com.google.gwt.benchmarks.client.impl\
diff --git a/user/src/com/google/gwt/core/shared/SerializableThrowable.java b/user/src/com/google/gwt/core/shared/SerializableThrowable.java
index a44fb04..82ccaae 100644
--- a/user/src/com/google/gwt/core/shared/SerializableThrowable.java
+++ b/user/src/com/google/gwt/core/shared/SerializableThrowable.java
@@ -15,7 +15,8 @@
  */
 package com.google.gwt.core.shared;
 
-import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.core.shared.impl.ThrowableTypeResolver;
+
 
 /**
  * A serializable copy of a {@link Throwable}, including its causes and stack trace. It overrides
@@ -64,6 +65,7 @@
   @Override
   public Throwable fillInStackTrace() {
     // This is a no-op for optimization as we don't need stack traces to be auto-filled.
+    // TODO(goktug): Java 7 let's you disable this by constructor flag
     return this;
   }
 
@@ -121,48 +123,7 @@
     SerializableThrowable throwable = new SerializableThrowable(null, t.getMessage());
     throwable.setStackTrace(t.getStackTrace());
     throwable.initCause(t.getCause());
-    if (isClassMetadataAvailable()) {
-      throwable.setDesignatedType(t.getClass().getName(), true);
-    } else {
-      resolveDesignatedType(throwable, t);
-    }
+    ThrowableTypeResolver.resolveDesignatedType(throwable, t);
     return throwable;
   }
-
-  // TODO(goktug): Replace when availability of class metadata can be checked in compile-time so
-  // that #resolveDesignatedType will be compiled out.
-  private static boolean isClassMetadataAvailable() {
-    return !GWT.isScript()
-        || SerializableThrowable.class.getName().endsWith(".SerializableThrowable");
-  }
-
-  /**
-   * Resolves best effort class name by checking against some common exception types.
-   */
-  private static void resolveDesignatedType(SerializableThrowable t, Throwable designatedType) {
-    String resolvedName;
-    Class<?> resolvedType;
-    try {
-      throw designatedType;
-    } catch (NullPointerException e) {
-      resolvedName = "java.lang.NullPointerException";
-      resolvedType = NullPointerException.class;
-    } catch (JavaScriptException e) {
-      resolvedName = "com.google.gwt.core.client.JavaScriptException";
-      resolvedType = JavaScriptException.class;
-    } catch (RuntimeException e) {
-      resolvedName = "java.lang.RuntimeException";
-      resolvedType = RuntimeException.class;
-    } catch (Exception e) {
-      resolvedName = "java.lang.Exception";
-      resolvedType = Exception.class;
-    } catch (Error e) {
-      resolvedName = "java.lang.Error";
-      resolvedType = Error.class;
-    } catch (Throwable e) {
-      resolvedName = "java.lang.Throwable";
-      resolvedType = Throwable.class;
-    }
-    t.setDesignatedType(resolvedName, resolvedType == designatedType.getClass());
-  }
 }
diff --git a/user/src/com/google/gwt/core/shared/impl/ThrowableTypeResolver.java b/user/src/com/google/gwt/core/shared/impl/ThrowableTypeResolver.java
new file mode 100644
index 0000000..25b76cd
--- /dev/null
+++ b/user/src/com/google/gwt/core/shared/impl/ThrowableTypeResolver.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2013 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.core.shared.impl;
+
+import com.google.gwt.core.shared.SerializableThrowable;
+
+/**
+ * Helper to resolve the designated type for {@link SerializableThrowable}. This class has
+ * translated version to improve type information when class metadata is not available.
+ */
+public class ThrowableTypeResolver {
+
+  public static void resolveDesignatedType(SerializableThrowable throwable, Throwable designated) {
+    throwable.setDesignatedType(designated.getClass().getName(), true);
+  }
+}
diff --git a/user/super/com/google/gwt/core/translatable/com/google/gwt/core/shared/impl/ThrowableTypeResolver.java b/user/super/com/google/gwt/core/translatable/com/google/gwt/core/shared/impl/ThrowableTypeResolver.java
new file mode 100644
index 0000000..eff0ef6
--- /dev/null
+++ b/user/super/com/google/gwt/core/translatable/com/google/gwt/core/shared/impl/ThrowableTypeResolver.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2013 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.core.shared.impl;
+
+import com.google.gwt.core.client.GwtScriptOnly;
+import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.core.shared.SerializableThrowable;
+
+/**
+ * Helper to resolve the designated type for {@link SerializableThrowable}. If no class metadata
+ * available then it resolves best effort class name by checking against some common exception
+ * types.
+ */
+@GwtScriptOnly
+public class ThrowableTypeResolver {
+
+  public static void resolveDesignatedType(SerializableThrowable throwable, Throwable designated) {
+    if (Class.isClassMetadataEnabled()) {
+      throwable.setDesignatedType(designated.getClass().getName(), true);
+    } else {
+      String resolvedName;
+      Class<?> resolvedType;
+      try {
+        throw designated;
+      } catch (NullPointerException e) {
+        resolvedName = "java.lang.NullPointerException";
+        resolvedType = NullPointerException.class;
+      } catch (JavaScriptException e) {
+        resolvedName = "com.google.gwt.core.client.JavaScriptException";
+        resolvedType = JavaScriptException.class;
+      } catch (RuntimeException e) {
+        resolvedName = "java.lang.RuntimeException";
+        resolvedType = RuntimeException.class;
+      } catch (Exception e) {
+        resolvedName = "java.lang.Exception";
+        resolvedType = Exception.class;
+      } catch (Error e) {
+        resolvedName = "java.lang.Error";
+        resolvedType = Error.class;
+      } catch (Throwable e) {
+        resolvedName = "java.lang.Throwable";
+        resolvedType = Throwable.class;
+      }
+      throwable.setDesignatedType(resolvedName, resolvedType == designated.getClass());
+    }
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/lang/Class.java b/user/super/com/google/gwt/emul/java/lang/Class.java
index 9037371..54ccde5 100644
--- a/user/super/com/google/gwt/emul/java/lang/Class.java
+++ b/user/super/com/google/gwt/emul/java/lang/Class.java
@@ -119,7 +119,7 @@
      return func;
    }-*/;
 
-  static boolean isClassMetadataEnabled() {
+  public static boolean isClassMetadataEnabled() {
     // This body may be replaced by the compiler
     return true;
   }
diff --git a/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java b/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java
index 54eed8f..ff89b0e 100644
--- a/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java
+++ b/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java
@@ -22,6 +22,7 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.core.shared.SerializableThrowable;
 import com.google.gwt.junit.DoNotRunWith;
 import com.google.gwt.junit.Platform;
 
@@ -96,13 +97,26 @@
   }
 
   // We lose some type information if class meta data is not available, setting expected failure
-  // to RuntimeException will ensure this test case passes for no metadata.
+  // to RuntimeException will ensure this test case passes for no metadata. Also see the next test.
   @ExpectedFailure(withType = RuntimeException.class,
       withMessage = "testThrowsNonSerializableException")
   public void testThrowsNonSerializableException() {
     throw new SomeNonSerializableException("testThrowsNonSerializableException");
   }
 
+  @ExpectedFailure(withType = SomeNonSerializableException.class)
+  public void testThrowsNonSerializableException_hasMetaData() throws Throwable {
+    if (!Object.class.getName().equals("java.lang.Object")) {
+      // If there is no metadata lets make the test case happy
+      SerializableThrowable throwable = SerializableThrowable.fromThrowable(new Exception());
+      throwable.setDesignatedType(
+          "com.google.gwt.junit.client.GWTTestCaseTest$SomeNonSerializableException", true);
+      throw throwable;
+    }
+    testThrowsNonSerializableException();
+  }
+
+
   public void testAssertEqualsDouble() {
     assertEquals(0.0, 0.0, 0.0);
     assertEquals(1.1, 1.1, 0.0);