Bug 336948 - Potential leak of ContextInjectionListener
diff --git a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ClassRequestor.java b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ClassRequestor.java
index 60bbf2b..f8b32a8 100644
--- a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ClassRequestor.java
+++ b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/ClassRequestor.java
@@ -38,7 +38,7 @@
 	}
 
 	public Object execute() throws InjectionException {
-		// do nothing
+		clearResolvedArgs();
 		return null;
 	}
 
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 1000ee4..d36abb2 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
@@ -56,6 +56,7 @@
 				constructor.setAccessible(false);
 			if (pausedRecording)
 				primarySupplier.resumeRecoding();
+			clearResolvedArgs();
 		}
 		return result;
 	}
diff --git a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/FieldRequestor.java b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/FieldRequestor.java
index 6110270..d6a7a2b 100644
--- a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/FieldRequestor.java
+++ b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/FieldRequestor.java
@@ -26,7 +26,10 @@
 	}
 
 	public Object execute() throws InjectionException {
+		if (actualArgs == null)
+			return null; // optional field
 		setField(field, actualArgs[0]);
+		clearResolvedArgs();
 		return null;
 	}
 
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 f3fea0d..89346d7 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
@@ -34,6 +34,10 @@
 	}
 
 	public Object execute() throws InjectionException {
+		if (actualArgs == null) {
+			if (method.getParameterTypes().length > 0)
+				return null; // optional method call
+		}
 		Object userObject = getRequestingObject();
 		if (userObject == null)
 			return null;
@@ -62,6 +66,7 @@
 				method.setAccessible(false);
 			if (pausedRecording)
 				primarySupplier.resumeRecoding();
+			clearResolvedArgs();
 		}
 		return result;
 	}
diff --git a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/Requestor.java b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/Requestor.java
index 1ec1e6c..f5f8bce 100644
--- a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/Requestor.java
+++ b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/Requestor.java
@@ -128,4 +128,18 @@
 			objectDescriptors = calcDependentObjects();
 		return objectDescriptors;
 	}
+
+	/**
+	 * Don't hold on to the resolved results as it will prevent 
+	 * them from being garbage collected. 
+	 */
+	protected void clearResolvedArgs() {
+		if (actualArgs == null)
+			return;
+		for (int i = 0; i < actualArgs.length; i++) {
+			actualArgs[i] = null;
+		}
+		actualArgs = null;
+		return;
+	}
 }
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/InjectionResultLeakTest.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/InjectionResultLeakTest.java
new file mode 100644
index 0000000..7933b52
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/InjectionResultLeakTest.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.internal.tests.di;
+
+import java.lang.ref.WeakReference;
+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.annotations.Optional;
+
+/**
+ * Test that we don't hold on to the values calculated during injection.
+ * This test relies on VM performing garbage collection in System.gc().
+ * The actual VM processing of GC requests is up to the implementation
+ * so this test might not work on all VMs or might become invalid on 
+ * future VMs. 
+ */
+public class InjectionResultLeakTest extends TestCase {
+
+	static class PartConsumer {
+		Object part;
+
+		@Inject
+		void setPart(@Optional @Named("testGC") Object part) {
+			this.part = part;
+		}
+	}
+
+	public void testLeaks() {
+		IEclipseContext context = EclipseContextFactory.create();
+		WeakReference<?> ref;
+
+		{ // scope the "part" object to help GC
+			Object part = new Object();
+			ref = new WeakReference<Object>(part);
+			assertEquals(part, ref.get());
+
+			context.set("testGC", part);
+
+			PartConsumer consumer = ContextInjectionFactory.make(
+					PartConsumer.class, context);
+			assertEquals(part, consumer.part);
+
+			part = null; // another "let's help GC" statement
+			context.remove("testGC");
+
+			assertNull(consumer.part);
+		}
+
+		// gc a few times
+		System.runFinalization();
+		System.gc();
+		System.runFinalization();
+		System.gc();
+		System.runFinalization();
+		System.gc();
+		System.runFinalization();
+		System.gc();
+
+		// partA should have been gc'd
+		assertNull("The object should have been garbage collected", ref.get());
+	}
+
+}
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java
index 3d6b29e..4b6dbca 100644
--- a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java
@@ -44,6 +44,7 @@
 import org.eclipse.e4.core.internal.tests.di.InjectArraysTest;
 import org.eclipse.e4.core.internal.tests.di.InjectBaseTypeTest;
 import org.eclipse.e4.core.internal.tests.di.InjectionOrderTest;
+import org.eclipse.e4.core.internal.tests.di.InjectionResultLeakTest;
 import org.eclipse.e4.core.internal.tests.di.InvokeTest;
 import org.eclipse.e4.core.internal.tests.di.extensions.InjectionEventTest;
 import org.eclipse.e4.core.internal.tests.di.extensions.InjectionMixedSuppliersTest;
@@ -63,6 +64,7 @@
 		addTestSuite(InjectionOrderTest.class);
 		addTestSuite(InvokeTest.class);
 		addTestSuite(InjectBaseTypeTest.class);
+		addTestSuite(InjectionResultLeakTest.class);
 		addTest(AtInjectTest.suite());
 
 		// Contexts