Bug 457687 - Dependency Injection should not catch Errors

According to the JavaDoc, an Error is "a subclass of Throwable that
indicates serious problems that a reasonable application should not try
to catch". Re-throw Errors that are raised by methods invoked by DI.

The underlying issue is that the Reflection API wraps Errors in an ITE.
It has been admitted in a JDK bug [1] that this is a bad practice but
cannot be changed for compatibility reasons. The recommended workaround
is to re-throw Errors wrapped in ITEs.

[1] http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4386935

Change-Id: I109b64cc98b63e9852043fd232eb0664f3156ea4
Signed-off-by: Ralf Sternberg <rsternberg@eclipsesource.com>
diff --git a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ConstructorRequestor.java b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ConstructorRequestor.java
index 791a033..f4d9b9d 100644
--- a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ConstructorRequestor.java
+++ b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ConstructorRequestor.java
@@ -47,6 +47,11 @@
 			throw new InjectionException(e);
 		} catch (InvocationTargetException e) {
 			Throwable originalException = e.getCause();
+			// Errors such as ThreadDeath or OutOfMemoryError should not be trapped
+			// http://bugs.eclipse.org/bugs/show_bug.cgi?id=457687
+			if (originalException instanceof Error) {
+				throw (Error) originalException;
+			}
 			throw new InjectionException((originalException != null) ? originalException : e);
 		} finally {
 			if (!wasAccessible)
diff --git a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/MethodRequestor.java b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/MethodRequestor.java
index 670ae42..6c29d21 100644
--- a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/MethodRequestor.java
+++ b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/MethodRequestor.java
@@ -59,6 +59,11 @@
 			throw new InjectionException(e);
 		} catch (InvocationTargetException e) {
 			Throwable originalException = e.getCause();
+			// Errors such as ThreadDeath or OutOfMemoryError should not be trapped
+			// http://bugs.eclipse.org/bugs/show_bug.cgi?id=457687
+			if (originalException instanceof Error) {
+				throw (Error) originalException;
+			}
 			throw new InjectionException((originalException != null) ? originalException : e);
 		} finally {
 			if (!wasAccessible)
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/manual/InjectionErrorReportingTest.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/manual/InjectionErrorReportingTest.java
index f073132..1baf1f5 100644
--- a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/manual/InjectionErrorReportingTest.java
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/manual/InjectionErrorReportingTest.java
@@ -15,14 +15,13 @@
 import javax.inject.Inject;
 import javax.inject.Named;
 
-import junit.framework.TestCase;
-
 import org.eclipse.e4.core.contexts.ContextInjectionFactory;
 import org.eclipse.e4.core.contexts.EclipseContextFactory;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.InjectionException;
 import org.eclipse.e4.core.di.annotations.Creatable;
-import org.junit.Ignore;
+
+import junit.framework.TestCase;
 
 /**
  * Manual test to observe error reporting. The JUnits in this
@@ -243,15 +242,17 @@
 	}
 
 	/**
-	 * Manual test to check error message for recursive object creation
+	 * Manual test to check error message for recursive object creation Although
+	 * bug 377343 disabled throwing InjectionExceptions on recursive creation,
+	 * the fix for bug 457687 now exposes java.lang.Errors (such as
+	 * StackOverflowError) rather than wrapping them in an InjectionException.
 	 */
-	@Ignore("Exception on recursive creations removed with bug 377343")
 	public void testRecursionError() {
 		IEclipseContext context = EclipseContextFactory.create();
 		boolean exception = false;
 		try {
 			ContextInjectionFactory.make(InjectedRecursive.class, context);
-		} catch (InjectionException e) {
+		} catch (StackOverflowError e) {
 			basicLog(e);
 			exception = true;
 		}
@@ -261,14 +262,14 @@
 		exception = false;
 		try {
 			ContextInjectionFactory.make(InjectedRecursive.class, context);
-		} catch (InjectionException e) {
+		} catch (StackOverflowError e) {
 			basicLog(e);
 			exception = true;
 		}
 		assertFalse(exception);
 	}
 
-	private void basicLog(InjectionException e) {
+	private void basicLog(Throwable e) {
 		e.printStackTrace(System.out);
 	}
 }