1 /** 2 * Copyright (C) 2006 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 import static com.google.inject.Asserts.assertNotSerializable; 21 import static java.lang.annotation.RetentionPolicy.RUNTIME; 22 23 24 import junit.framework.TestCase; 25 26 import java.io.IOException; 27 import java.lang.annotation.Retention; 28 import java.util.concurrent.Callable; 29 import java.util.concurrent.ExecutionException; 30 import java.util.concurrent.ExecutorService; 31 import java.util.concurrent.Executors; 32 import java.util.concurrent.Future; 33 import java.util.concurrent.atomic.AtomicReference; 34 35 /** 36 * @author crazybob@google.com (Bob Lee) 37 */ 38 39 public class InjectorTest extends TestCase { 40 41 @Retention(RUNTIME) 42 @BindingAnnotation @interface Other {} 43 44 @Retention(RUNTIME) 45 @BindingAnnotation @interface S {} 46 47 @Retention(RUNTIME) 48 @BindingAnnotation @interface I {} 49 testToStringDoesNotInfinitelyRecurse()50 public void testToStringDoesNotInfinitelyRecurse() { 51 Injector injector = Guice.createInjector(Stage.TOOL); 52 injector.toString(); 53 injector.getBinding(Injector.class).toString(); 54 } 55 testProviderMethods()56 public void testProviderMethods() throws CreationException { 57 final SampleSingleton singleton = new SampleSingleton(); 58 final SampleSingleton other = new SampleSingleton(); 59 60 Injector injector = Guice.createInjector(new AbstractModule() { 61 protected void configure() { 62 bind(SampleSingleton.class).toInstance(singleton); 63 bind(SampleSingleton.class) 64 .annotatedWith(Other.class) 65 .toInstance(other); 66 } 67 }); 68 69 assertSame(singleton, 70 injector.getInstance(Key.get(SampleSingleton.class))); 71 assertSame(singleton, injector.getInstance(SampleSingleton.class)); 72 73 assertSame(other, 74 injector.getInstance(Key.get(SampleSingleton.class, Other.class))); 75 } 76 77 static class SampleSingleton {} 78 testInjection()79 public void testInjection() throws CreationException { 80 Injector injector = createFooInjector(); 81 Foo foo = injector.getInstance(Foo.class); 82 83 assertEquals("test", foo.s); 84 assertEquals("test", foo.bar.getTee().getS()); 85 assertSame(foo.bar, foo.copy); 86 assertEquals(5, foo.i); 87 assertEquals(5, foo.bar.getI()); 88 89 // Test circular dependency. 90 assertSame(foo.bar, foo.bar.getTee().getBar()); 91 } 92 createFooInjector()93 private Injector createFooInjector() throws CreationException { 94 return Guice.createInjector(new AbstractModule() { 95 protected void configure() { 96 bind(Bar.class).to(BarImpl.class); 97 bind(Tee.class).to(TeeImpl.class); 98 bindConstant().annotatedWith(S.class).to("test"); 99 bindConstant().annotatedWith(I.class).to(5); 100 } 101 }); 102 } 103 104 public void testGetInstance() throws CreationException { 105 Injector injector = createFooInjector(); 106 107 Bar bar = injector.getInstance(Key.get(Bar.class)); 108 assertEquals("test", bar.getTee().getS()); 109 assertEquals(5, bar.getI()); 110 } 111 112 public void testIntAndIntegerAreInterchangeable() 113 throws CreationException { 114 Injector injector = Guice.createInjector(new AbstractModule() { 115 protected void configure() { 116 bindConstant().annotatedWith(I.class).to(5); 117 } 118 }); 119 120 IntegerWrapper iw = injector.getInstance(IntegerWrapper.class); 121 assertEquals(5, (int) iw.i); 122 } 123 124 public void testInjectorApiIsNotSerializable() throws IOException { 125 Injector injector = Guice.createInjector(); 126 assertNotSerializable(injector); 127 assertNotSerializable(injector.getProvider(String.class)); 128 assertNotSerializable(injector.getBinding(String.class)); 129 for (Binding<?> binding : injector.getBindings().values()) { 130 assertNotSerializable(binding); 131 } 132 } 133 134 static class IntegerWrapper { 135 @Inject @I Integer i; 136 } 137 138 static class Foo { 139 140 @Inject Bar bar; 141 @Inject Bar copy; 142 143 @Inject @S String s; 144 145 int i; 146 147 @Inject 148 void setI(@I int i) { 149 this.i = i; 150 } 151 } 152 153 interface Bar { 154 155 Tee getTee(); 156 int getI(); 157 } 158 159 @Singleton 160 static class BarImpl implements Bar { 161 162 @Inject @I int i; 163 164 Tee tee; 165 166 @Inject 167 void initialize(Tee tee) { 168 this.tee = tee; 169 } 170 171 public Tee getTee() { 172 return tee; 173 } 174 175 public int getI() { 176 return i; 177 } 178 } 179 180 interface Tee { 181 182 String getS(); 183 Bar getBar(); 184 } 185 186 static class TeeImpl implements Tee { 187 188 final String s; 189 @Inject Bar bar; 190 191 @Inject 192 TeeImpl(@S String s) { 193 this.s = s; 194 } 195 196 public String getS() { 197 return s; 198 } 199 200 public Bar getBar() { 201 return bar; 202 } 203 } 204 205 public void testInjectStatics() throws CreationException { 206 Guice.createInjector(new AbstractModule() { 207 protected void configure() { 208 bindConstant().annotatedWith(S.class).to("test"); 209 bindConstant().annotatedWith(I.class).to(5); 210 requestStaticInjection(Static.class); 211 } 212 }); 213 214 assertEquals("test", Static.s); 215 assertEquals(5, Static.i); 216 } 217 218 public void testInjectStaticInterface() { 219 try { 220 Guice.createInjector(new AbstractModule() { 221 protected void configure() { 222 requestStaticInjection(Interface.class); 223 } 224 }); 225 fail(); 226 } catch(CreationException ce) { 227 assertEquals(1, ce.getErrorMessages().size()); 228 Asserts.assertContains( 229 ce.getMessage(), 230 "1) " + Interface.class.getName() 231 + " is an interface, but interfaces have no static injection points.", 232 "at " + InjectorTest.class.getName(), 233 "configure"); 234 } 235 } 236 237 private static interface Interface {} 238 239 static class Static { 240 241 @Inject @I static int i; 242 243 static String s; 244 245 @Inject static void setS(@S String s) { 246 Static.s = s; 247 } 248 } 249 250 public void testPrivateInjection() throws CreationException { 251 Injector injector = Guice.createInjector(new AbstractModule() { 252 protected void configure() { 253 bind(String.class).toInstance("foo"); 254 bind(int.class).toInstance(5); 255 } 256 }); 257 258 Private p = injector.getInstance(Private.class); 259 assertEquals("foo", p.fromConstructor); 260 assertEquals(5, p.fromMethod); 261 } 262 263 static class Private { 264 String fromConstructor; 265 int fromMethod; 266 267 @Inject 268 private Private(String fromConstructor) { 269 this.fromConstructor = fromConstructor; 270 } 271 272 @Inject 273 private void setInt(int i) { 274 this.fromMethod = i; 275 } 276 } 277 278 public void testProtectedInjection() throws CreationException { 279 Injector injector = Guice.createInjector(new AbstractModule() { 280 protected void configure() { 281 bind(String.class).toInstance("foo"); 282 bind(int.class).toInstance(5); 283 } 284 }); 285 286 Protected p = injector.getInstance(Protected.class); 287 assertEquals("foo", p.fromConstructor); 288 assertEquals(5, p.fromMethod); 289 } 290 291 static class Protected { 292 String fromConstructor; 293 int fromMethod; 294 295 @Inject 296 protected Protected(String fromConstructor) { 297 this.fromConstructor = fromConstructor; 298 } 299 300 @Inject 301 protected void setInt(int i) { 302 this.fromMethod = i; 303 } 304 } 305 306 public void testInstanceInjectionHappensAfterFactoriesAreSetUp() { 307 Guice.createInjector(new AbstractModule() { 308 protected void configure() { 309 bind(Object.class).toInstance(new Object() { 310 @Inject Runnable r; 311 }); 312 313 bind(Runnable.class).to(MyRunnable.class); 314 } 315 }); 316 } 317 318 public void testSubtypeNotProvided() { 319 try { 320 Guice.createInjector().getInstance(Money.class); 321 fail(); 322 } catch (ProvisionException expected) { 323 assertContains(expected.getMessage(), 324 Tree.class.getName() + " doesn't provide instances of " + Money.class.getName(), 325 "while locating ", Tree.class.getName(), 326 "while locating ", Money.class.getName()); 327 } 328 } 329 330 public void testNotASubtype() { 331 try { 332 Guice.createInjector().getInstance(PineTree.class); 333 fail(); 334 } catch (ConfigurationException expected) { 335 assertContains(expected.getMessage(), 336 Tree.class.getName() + " doesn't extend " + PineTree.class.getName(), 337 "while locating ", PineTree.class.getName()); 338 } 339 } 340 341 public void testRecursiveImplementationType() { 342 try { 343 Guice.createInjector().getInstance(SeaHorse.class); 344 fail(); 345 } catch (ConfigurationException expected) { 346 assertContains(expected.getMessage(), 347 "@ImplementedBy points to the same class it annotates.", 348 "while locating ", SeaHorse.class.getName()); 349 } 350 } 351 352 public void testRecursiveProviderType() { 353 try { 354 Guice.createInjector().getInstance(Chicken.class); 355 fail(); 356 } catch (ConfigurationException expected) { 357 assertContains(expected.getMessage(), 358 "@ProvidedBy points to the same class it annotates", 359 "while locating ", Chicken.class.getName()); 360 } 361 } 362 363 static class MyRunnable implements Runnable { 364 public void run() {} 365 } 366 367 @ProvidedBy(Tree.class) 368 static class Money {} 369 370 static class Tree implements Provider<Object> { 371 public Object get() { 372 return "Money doesn't grow on trees"; 373 } 374 } 375 376 @ImplementedBy(Tree.class) 377 static class PineTree extends Tree {} 378 379 @ImplementedBy(SeaHorse.class) 380 static class SeaHorse {} 381 382 @ProvidedBy(Chicken.class) 383 static class Chicken implements Provider<Chicken> { 384 public Chicken get() { 385 return this; 386 } 387 } 388 389 public void testJitBindingFromAnotherThreadDuringInjection() { 390 final ExecutorService executorService = Executors.newSingleThreadExecutor(); 391 final AtomicReference<JustInTime> got = new AtomicReference<JustInTime>(); 392 393 Guice.createInjector(new AbstractModule() { 394 protected void configure() { 395 requestInjection(new Object() { 396 @Inject void initialize(final Injector injector) 397 throws ExecutionException, InterruptedException { 398 Future<JustInTime> future = executorService.submit(new Callable<JustInTime>() { 399 public JustInTime call() throws Exception { 400 return injector.getInstance(JustInTime.class); 401 } 402 }); 403 got.set(future.get()); 404 } 405 }); 406 } 407 }); 408 409 assertNotNull(got.get()); 410 } 411 412 static class JustInTime {} 413 } 414