1 /** 2 * Copyright (C) 2008 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package com.google.inject; 19 20 import static com.google.inject.Asserts.assertContains; 21 22 import com.google.inject.name.Named; 23 import com.google.inject.name.Names; 24 25 import junit.framework.TestCase; 26 27 /** 28 * This test verifies the ways things are injected (ie. getInstance(), 29 * injectMembers(), bind to instance, and bind to provider instance) for all 30 * states of optional bindings (fields, methods, multiple-argument methods, 31 * provider fields, provider methods, constructors). 32 * 33 * @author jessewilson (at) google.com (Jesse Wilson) 34 */ 35 public class OptionalBindingTest extends TestCase { 36 37 private static final A injectA = new A() {}; 38 private static final B injectB = new B() {}; 39 private static final C injectC = new C() {}; 40 private static final D injectD = new D() {}; 41 private static final E injectE = new E() {}; 42 private static final F injectF = new F() {}; 43 private static final G injectG = new G() {}; 44 45 private Module everythingModule = new AbstractModule() { 46 protected void configure() { 47 bind(A.class).toInstance(injectA); 48 bind(B.class).toInstance(injectB); 49 bind(C.class).toInstance(injectC); 50 bind(D.class).toInstance(injectD); 51 bind(E.class).annotatedWith(Names.named("e")).toInstance(injectE); 52 bind(F.class).toInstance(injectF); 53 bind(G.class).toInstance(injectG); 54 } 55 }; 56 57 private Module partialModule = new AbstractModule() { 58 protected void configure() { 59 bind(C.class).toInstance(new C() {}); 60 } 61 }; 62 63 private Module toInstanceModule = new AbstractModule() { 64 protected void configure() { 65 bind(HasOptionalInjections.class) 66 .toInstance(new HasOptionalInjections()); 67 } 68 }; 69 70 private Module toProviderInstanceModule = new AbstractModule() { 71 protected void configure() { 72 bind(HasOptionalInjections.class) 73 .toProvider(new HasOptionalInjectionsProvider()); 74 } 75 }; 76 77 private Module toProviderModule = new AbstractModule() { 78 protected void configure() { 79 bind(HasOptionalInjections.class) 80 .toProvider(HasOptionalInjectionsProvider.class); 81 } 82 }; 83 84 public void testEverythingInjectorGetInstance() { 85 Guice.createInjector(everythingModule) 86 .getInstance(HasOptionalInjections.class) 87 .assertEverythingInjected(); 88 } 89 90 public void testPartialInjectorGetInstance() { 91 Guice.createInjector(partialModule) 92 .getInstance(HasOptionalInjections.class) 93 .assertNothingInjected(); 94 } 95 96 public void testNothingInjectorGetInstance() { 97 Guice.createInjector() 98 .getInstance(HasOptionalInjections.class) 99 .assertNothingInjected(); 100 } 101 102 public void testEverythingInjectorInjectMembers() { 103 HasOptionalInjections instance = new HasOptionalInjections(); 104 Guice.createInjector(everythingModule).injectMembers(instance); 105 instance.assertEverythingInjected(); 106 } 107 108 public void testPartialInjectorInjectMembers() { 109 HasOptionalInjections instance = new HasOptionalInjections(); 110 Guice.createInjector(partialModule).injectMembers(instance); 111 instance.assertNothingInjected(); 112 } 113 114 public void testNothingInjectorInjectMembers() { 115 HasOptionalInjections instance = new HasOptionalInjections(); 116 Guice.createInjector().injectMembers(instance); 117 instance.assertNothingInjected(); 118 } 119 120 public void testEverythingInjectorToInstance() { 121 Guice.createInjector(everythingModule, toInstanceModule) 122 .getInstance(HasOptionalInjections.class) 123 .assertEverythingInjected(); 124 } 125 126 public void testPartialInjectorToInstance() { 127 Guice.createInjector(partialModule, toInstanceModule) 128 .getInstance(HasOptionalInjections.class) 129 .assertNothingInjected(); 130 } 131 132 public void testNothingInjectorToInstance() { 133 Guice.createInjector(toInstanceModule) 134 .getInstance(HasOptionalInjections.class) 135 .assertNothingInjected(); 136 } 137 138 public void testEverythingInjectorToProviderInstance() { 139 Guice.createInjector(everythingModule, toProviderInstanceModule) 140 .getInstance(HasOptionalInjections.class) 141 .assertEverythingInjected(); 142 } 143 144 public void testPartialInjectorToProviderInstance() { 145 Guice.createInjector(partialModule, toProviderInstanceModule) 146 .getInstance(HasOptionalInjections.class) 147 .assertNothingInjected(); 148 } 149 150 public void testNothingInjectorToProviderInstance() { 151 Guice.createInjector(toProviderInstanceModule) 152 .getInstance(HasOptionalInjections.class) 153 .assertNothingInjected(); 154 } 155 156 public void testEverythingInjectorToProvider() { 157 Guice.createInjector(everythingModule, toProviderModule) 158 .getInstance(HasOptionalInjections.class) 159 .assertEverythingInjected(); 160 } 161 162 public void testPartialInjectorToProvider() { 163 Guice.createInjector(partialModule, toProviderModule) 164 .getInstance(HasOptionalInjections.class) 165 .assertNothingInjected(); 166 } 167 168 public void testNothingInjectorToProvider() { 169 Guice.createInjector(toProviderModule) 170 .getInstance(HasOptionalInjections.class) 171 .assertNothingInjected(); 172 } 173 174 static class HasOptionalInjections { 175 A originalA = new A() {}; 176 @Inject(optional=true) A a = originalA; // field injection 177 B b; // method injection with one argument 178 C c; // method injection with two arguments 179 D d; // method injection with two arguments 180 E e; // annotated injection 181 @Inject(optional=true) Provider<F> fProvider; // provider 182 Provider<G> gProvider; // method injection of provider 183 boolean invoked0, invoked1, invoked2, invokedAnnotated, invokeProvider; 184 185 @Inject(optional=true) void methodInjectZeroArguments() { 186 invoked0 = true; 187 } 188 189 @Inject(optional=true) void methodInjectOneArgument(B b) { 190 this.b = b; 191 invoked1 = true; 192 } 193 194 @Inject(optional=true) void methodInjectTwoArguments(C c, D d) { 195 this.c = c; 196 this.d = d; 197 invoked2 = true; 198 } 199 200 @Inject(optional=true) void methodInjectAnnotated(@Named("e") E e) { 201 this.e = e; 202 invokedAnnotated = true; 203 } 204 205 @Inject(optional=true) void methodInjectProvider(Provider<G> gProvider) { 206 this.gProvider = gProvider; 207 invokeProvider = true; 208 } 209 210 void assertNothingInjected() { 211 assertSame(originalA, a); 212 assertNull(b); 213 assertNull(c); 214 assertNull(d); 215 assertNull(e); 216 assertNull(fProvider); 217 assertNull(gProvider); 218 assertTrue(invoked0); 219 assertFalse(invoked1); 220 assertFalse(invoked2); 221 assertFalse(invokedAnnotated); 222 } 223 224 public void assertEverythingInjected() { 225 assertNotSame(injectA, originalA); 226 assertSame(injectA, a); 227 assertSame(injectB, b); 228 assertSame(injectC, c); 229 assertSame(injectD, d); 230 assertSame(injectE, e); 231 assertSame(injectF, fProvider.get()); 232 assertSame(injectG, gProvider.get()); 233 assertTrue(invoked0); 234 assertTrue(invoked1); 235 assertTrue(invoked2); 236 assertTrue(invokedAnnotated); 237 } 238 } 239 240 static class HasOptionalInjectionsProvider 241 extends HasOptionalInjections implements Provider<HasOptionalInjections> { 242 public HasOptionalInjections get() { 243 return this; 244 } 245 } 246 247 public void testOptionalConstructorBlowsUp() { 248 try { 249 Guice.createInjector().getInstance(HasOptionalConstructor.class); 250 fail(); 251 } catch (ConfigurationException expected) { 252 assertContains(expected.getMessage(), "OptionalBindingTest$HasOptionalConstructor.<init>() " 253 + "is annotated @Inject(optional=true), but constructors cannot be optional."); 254 } 255 } 256 257 static class HasOptionalConstructor { 258 // Suppress compiler errors by the error-prone checker InjectedConstructorAnnotations, 259 // which catches optional injected constructors. 260 @SuppressWarnings("InjectedConstructorAnnotations") 261 @Inject(optional=true) 262 HasOptionalConstructor() {} 263 } 264 265 @Inject(optional=true) static A staticInjectA; 266 267 public void testStaticInjection() { 268 staticInjectA = injectA; 269 Guice.createInjector(new AbstractModule() { 270 protected void configure() { 271 requestStaticInjection(OptionalBindingTest.class); 272 } 273 }); 274 assertSame(staticInjectA, injectA); 275 } 276 277 /** 278 * Test for bug 107, where we weren't doing optional injection properly for 279 * indirect injections. 280 */ 281 public void testIndirectOptionalInjection() { 282 Indirect indirect = Guice.createInjector().getInstance(Indirect.class); 283 assertNotNull(indirect.hasOptionalInjections); 284 indirect.hasOptionalInjections.assertNothingInjected(); 285 } 286 287 static class Indirect { 288 @Inject HasOptionalInjections hasOptionalInjections; 289 } 290 291 interface A {} 292 interface B {} 293 interface C {} 294 interface D {} 295 interface E {} 296 interface F {} 297 interface G {} 298 } 299