/* * Copyright (C) 2008 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.inject; import static com.google.inject.Asserts.assertContains; import com.google.inject.name.Named; import com.google.inject.name.Names; import junit.framework.TestCase; /** * This test verifies the ways things are injected (ie. getInstance(), injectMembers(), bind to * instance, and bind to provider instance) for all states of optional bindings (fields, methods, * multiple-argument methods, provider fields, provider methods, constructors). * * @author jessewilson@google.com (Jesse Wilson) */ public class OptionalBindingTest extends TestCase { private static final A injectA = new A() {}; private static final B injectB = new B() {}; private static final C injectC = new C() {}; private static final D injectD = new D() {}; private static final E injectE = new E() {}; private static final F injectF = new F() {}; private static final G injectG = new G() {}; private Module everythingModule = new AbstractModule() { @Override protected void configure() { bind(A.class).toInstance(injectA); bind(B.class).toInstance(injectB); bind(C.class).toInstance(injectC); bind(D.class).toInstance(injectD); bind(E.class).annotatedWith(Names.named("e")).toInstance(injectE); bind(F.class).toInstance(injectF); bind(G.class).toInstance(injectG); } }; private Module partialModule = new AbstractModule() { @Override protected void configure() { bind(C.class).toInstance(new C() {}); } }; private Module toInstanceModule = new AbstractModule() { @Override protected void configure() { bind(HasOptionalInjections.class).toInstance(new HasOptionalInjections()); } }; private Module toProviderInstanceModule = new AbstractModule() { @Override protected void configure() { bind(HasOptionalInjections.class).toProvider(new HasOptionalInjectionsProvider()); } }; private Module toProviderModule = new AbstractModule() { @Override protected void configure() { bind(HasOptionalInjections.class).toProvider(HasOptionalInjectionsProvider.class); } }; public void testEverythingInjectorGetInstance() { Guice.createInjector(everythingModule) .getInstance(HasOptionalInjections.class) .assertEverythingInjected(); } public void testPartialInjectorGetInstance() { Guice.createInjector(partialModule) .getInstance(HasOptionalInjections.class) .assertNothingInjected(); } public void testNothingInjectorGetInstance() { Guice.createInjector().getInstance(HasOptionalInjections.class).assertNothingInjected(); } public void testEverythingInjectorInjectMembers() { HasOptionalInjections instance = new HasOptionalInjections(); Guice.createInjector(everythingModule).injectMembers(instance); instance.assertEverythingInjected(); } public void testPartialInjectorInjectMembers() { HasOptionalInjections instance = new HasOptionalInjections(); Guice.createInjector(partialModule).injectMembers(instance); instance.assertNothingInjected(); } public void testNothingInjectorInjectMembers() { HasOptionalInjections instance = new HasOptionalInjections(); Guice.createInjector().injectMembers(instance); instance.assertNothingInjected(); } public void testEverythingInjectorToInstance() { Guice.createInjector(everythingModule, toInstanceModule) .getInstance(HasOptionalInjections.class) .assertEverythingInjected(); } public void testPartialInjectorToInstance() { Guice.createInjector(partialModule, toInstanceModule) .getInstance(HasOptionalInjections.class) .assertNothingInjected(); } public void testNothingInjectorToInstance() { Guice.createInjector(toInstanceModule) .getInstance(HasOptionalInjections.class) .assertNothingInjected(); } public void testEverythingInjectorToProviderInstance() { Guice.createInjector(everythingModule, toProviderInstanceModule) .getInstance(HasOptionalInjections.class) .assertEverythingInjected(); } public void testPartialInjectorToProviderInstance() { Guice.createInjector(partialModule, toProviderInstanceModule) .getInstance(HasOptionalInjections.class) .assertNothingInjected(); } public void testNothingInjectorToProviderInstance() { Guice.createInjector(toProviderInstanceModule) .getInstance(HasOptionalInjections.class) .assertNothingInjected(); } public void testEverythingInjectorToProvider() { Guice.createInjector(everythingModule, toProviderModule) .getInstance(HasOptionalInjections.class) .assertEverythingInjected(); } public void testPartialInjectorToProvider() { Guice.createInjector(partialModule, toProviderModule) .getInstance(HasOptionalInjections.class) .assertNothingInjected(); } public void testNothingInjectorToProvider() { Guice.createInjector(toProviderModule) .getInstance(HasOptionalInjections.class) .assertNothingInjected(); } static class HasOptionalInjections { A originalA = new A() {}; @Inject(optional = true) A a = originalA; // field injection B b; // method injection with one argument C c; // method injection with two arguments D d; // method injection with two arguments E e; // annotated injection @Inject(optional = true) Provider<F> fProvider; // provider Provider<G> gProvider; // method injection of provider boolean invoked0, invoked1, invoked2, invokedAnnotated, invokeProvider; @Inject(optional = true) void methodInjectZeroArguments() { invoked0 = true; } @Inject(optional = true) void methodInjectOneArgument(B b) { this.b = b; invoked1 = true; } @Inject(optional = true) void methodInjectTwoArguments(C c, D d) { this.c = c; this.d = d; invoked2 = true; } @Inject(optional = true) void methodInjectAnnotated(@Named("e") E e) { this.e = e; invokedAnnotated = true; } @Inject(optional = true) void methodInjectProvider(Provider<G> gProvider) { this.gProvider = gProvider; invokeProvider = true; } void assertNothingInjected() { assertSame(originalA, a); assertNull(b); assertNull(c); assertNull(d); assertNull(e); assertNull(fProvider); assertNull(gProvider); assertTrue(invoked0); assertFalse(invoked1); assertFalse(invoked2); assertFalse(invokedAnnotated); } public void assertEverythingInjected() { assertNotSame(injectA, originalA); assertSame(injectA, a); assertSame(injectB, b); assertSame(injectC, c); assertSame(injectD, d); assertSame(injectE, e); assertSame(injectF, fProvider.get()); assertSame(injectG, gProvider.get()); assertTrue(invoked0); assertTrue(invoked1); assertTrue(invoked2); assertTrue(invokedAnnotated); } } static class HasOptionalInjectionsProvider extends HasOptionalInjections implements Provider<HasOptionalInjections> { @Override public HasOptionalInjections get() { return this; } } public void testOptionalConstructorBlowsUp() { try { Guice.createInjector().getInstance(HasOptionalConstructor.class); fail(); } catch (ConfigurationException expected) { assertContains( expected.getMessage(), "OptionalBindingTest$HasOptionalConstructor.<init>() " + "is annotated @Inject(optional=true), but constructors cannot be optional."); } } static class HasOptionalConstructor { // Suppress compiler errors by the error-prone checker InjectedConstructorAnnotations, // which catches optional injected constructors. @SuppressWarnings("InjectedConstructorAnnotations") @Inject(optional = true) HasOptionalConstructor() {} } @Inject(optional = true) static A staticInjectA; public void testStaticInjection() { staticInjectA = injectA; Guice.createInjector( new AbstractModule() { @Override protected void configure() { requestStaticInjection(OptionalBindingTest.class); } }); assertSame(staticInjectA, injectA); } /** * Test for bug 107, where we weren't doing optional injection properly for indirect injections. */ public void testIndirectOptionalInjection() { Indirect indirect = Guice.createInjector().getInstance(Indirect.class); assertNotNull(indirect.hasOptionalInjections); indirect.hasOptionalInjections.assertNothingInjected(); } static class Indirect { @Inject HasOptionalInjections hasOptionalInjections; } interface A {} interface B {} interface C {} interface D {} interface E {} interface F {} interface G {} }