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