Bug 371115 - Dependency Injection should not auto-gen an object (without
@Named annotation)
diff --git a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/di/annotations/Creatable.java b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/di/annotations/Creatable.java
new file mode 100644
index 0000000..0a85f64
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/di/annotations/Creatable.java
@@ -0,0 +1,29 @@
+/*******************************************************************************

+ * Copyright (c) 2012 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.di.annotations;

+

+import java.lang.annotation.Documented;

+import java.lang.annotation.ElementType;

+import java.lang.annotation.Retention;

+import java.lang.annotation.RetentionPolicy;

+import java.lang.annotation.Target;

+import javax.inject.Qualifier;

+

+/**

+ * Specifies that the target class that can be created by an injector as needed.

+ */

+@Qualifier

+@Documented

+@Target({ElementType.TYPE})

+@Retention(RetentionPolicy.RUNTIME)

+public @interface Creatable {

+	String value() default ""; // reserved for future use

+}

diff --git a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/InjectorImpl.java b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/InjectorImpl.java
index a4371e6..ea130ad 100644
--- a/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/InjectorImpl.java
+++ b/bundles/org.eclipse.e4.core.di/src/org/eclipse/e4/core/internal/di/InjectorImpl.java
@@ -38,6 +38,7 @@
 import org.eclipse.e4.core.di.IBinding;
 import org.eclipse.e4.core.di.IInjector;
 import org.eclipse.e4.core.di.InjectionException;
+import org.eclipse.e4.core.di.annotations.Creatable;
 import org.eclipse.e4.core.di.annotations.Optional;
 import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
 import org.eclipse.e4.core.di.suppliers.IObjectDescriptor;
@@ -447,6 +448,10 @@
 				if (descriptors[i].hasQualifier(Optional.class))
 					continue;
 				try {
+					Class<?> desiredClass = getDesiredClass(descriptors[i].getDesiredType());
+					Creatable creatableAnnotation = desiredClass.getAnnotation(Creatable.class);
+					if (creatableAnnotation == null)
+						continue;
 					actualArgs[i] = internalMake(getDesiredClass(descriptors[i].getDesiredType()), objectSupplier, tempSupplier);
 				} catch (InjectionException e) {
 					// ignore
@@ -796,6 +801,16 @@
 				if (eq(collectionBinding.getQualifierName(), desiredQualifierName))
 					return collectionBinding;
 			}
+			desiredQualifierName = desiredClass.getName();
+			for (Iterator<Binding> i = collection.iterator(); i.hasNext();) {
+				Binding collectionBinding = i.next();
+				Class<?> bindingClass = collectionBinding.getDescribedClass();
+				if (bindingClass == null)
+					continue;
+				String simpleClassName = bindingClass.getName();
+				if (eq(simpleClassName, desiredQualifierName))
+					return collectionBinding;
+			}
 		}
 		return null;
 	}
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/AtInjectTest.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/AtInjectTest.java
index f210e92..a0cc245 100644
--- a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/AtInjectTest.java
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/AtInjectTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2010 IBM Corporation and others.
+ * Copyright (c) 2009, 2012 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
@@ -19,9 +19,11 @@
 import org.atinject.tck.auto.Drivers;
 import org.atinject.tck.auto.DriversSeat;
 import org.atinject.tck.auto.Engine;
+import org.atinject.tck.auto.FuelTank;
 import org.atinject.tck.auto.Seat;
 import org.atinject.tck.auto.Tire;
 import org.atinject.tck.auto.V8Engine;
+import org.atinject.tck.auto.accessories.Cupholder;
 import org.atinject.tck.auto.accessories.SpareTire;
 import org.eclipse.e4.core.di.IInjector;
 import org.eclipse.e4.core.di.InjectorFactory;
@@ -30,6 +32,14 @@
 
 	public static Test suite() {
 		IInjector injector = InjectorFactory.getDefault();
+		
+		injector.addBinding(SpareTire.class);
+		injector.addBinding(Seat.class);
+		injector.addBinding(DriversSeat.class);
+		injector.addBinding(Cupholder.class);
+		injector.addBinding(Tire.class);
+		injector.addBinding(FuelTank.class);
+		
 		injector.addBinding(Car.class).implementedBy(Convertible.class);
 		injector.addBinding(Seat.class).named(Drivers.class.getName()).implementedBy(DriversSeat.class);
 		injector.addBinding(Engine.class).implementedBy(V8Engine.class);
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/AutoConstructTest.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/AutoConstructTest.java
new file mode 100644
index 0000000..dd88fe2
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/AutoConstructTest.java
@@ -0,0 +1,76 @@
+/*******************************************************************************

+ * Copyright (c) 2012 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 javax.inject.Inject;

+

+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;

+

+public class AutoConstructTest extends TestCase {

+

+	@Creatable

+	static class Dependent1 {

+		@Inject

+		public Dependent1() {

+			// placeholder

+		}

+	}

+

+	static class Dependent2 {

+		@Inject

+		public Dependent2() {

+			// placeholder

+		}

+	}

+

+	static class Consumer1 {

+		@Inject

+		public Consumer1(Dependent1 dep) {

+			// placeholder

+		}

+	}

+

+	static class Consumer2 {

+		@Inject

+		public Consumer2(Dependent2 dep) {

+			// placeholder

+		}

+	}

+

+	/**

+	 * Checks that only classes with @Creatable are auto-constructed

+	 */

+	public void testCreatable() {

+		IEclipseContext context = EclipseContextFactory.create();

+		Consumer1 consumer1 = ContextInjectionFactory.make(Consumer1.class,

+				context);

+		assertNotNull(consumer1);

+

+		boolean exception = false;

+		try {

+			ContextInjectionFactory.make(Consumer2.class, context);

+		} catch (InjectionException e) {

+			exception = true; // expected

+		}

+		assertTrue(exception);

+

+		context.set(Dependent2.class, new Dependent2());

+		Consumer2 consumer2 = ContextInjectionFactory.make(Consumer2.class,

+				context);

+		assertNotNull(consumer2);

+	}

+}

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 6d3f3d3..ddaada0 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
@@ -40,6 +40,7 @@
 import org.eclipse.e4.core.internal.tests.contexts.inject.ServiceContextTest;
 import org.eclipse.e4.core.internal.tests.contexts.inject.TestConstructorInjection;
 import org.eclipse.e4.core.internal.tests.di.AtInjectTest;
+import org.eclipse.e4.core.internal.tests.di.AutoConstructTest;
 import org.eclipse.e4.core.internal.tests.di.DisposeClassLinkTest;
 import org.eclipse.e4.core.internal.tests.di.InjectArraysTest;
 import org.eclipse.e4.core.internal.tests.di.InjectBaseTypeTest;
@@ -67,6 +68,7 @@
 		addTestSuite(InjectBaseTypeTest.class);
 		addTestSuite(InjectionResultLeakTest.class);
 		addTest(AtInjectTest.suite());
+		addTestSuite(AutoConstructTest.class);
 
 		// Contexts
 		addTestSuite(EclipseContextTest.class);