1 /* 2 * Copyright (C) 2009 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.googlecode.guice; 18 19 import static com.google.inject.Asserts.assertContains; 20 import static java.lang.annotation.RetentionPolicy.RUNTIME; 21 22 import com.google.inject.AbstractModule; 23 import com.google.inject.Binding; 24 import com.google.inject.CreationException; 25 import com.google.inject.Guice; 26 import com.google.inject.Injector; 27 import com.google.inject.Key; 28 import com.google.inject.Scope; 29 import com.google.inject.Scopes; 30 import com.google.inject.Stage; 31 import com.google.inject.TypeLiteral; 32 import com.google.inject.name.Names; 33 import com.google.inject.spi.Dependency; 34 import com.google.inject.spi.HasDependencies; 35 import com.google.inject.util.Providers; 36 import java.lang.annotation.Annotation; 37 import java.lang.annotation.Retention; 38 import java.util.Set; 39 import javax.inject.Inject; 40 import javax.inject.Named; 41 import javax.inject.Provider; 42 import javax.inject.Qualifier; 43 import javax.inject.Singleton; 44 import junit.framework.TestCase; 45 46 public class Jsr330Test extends TestCase { 47 48 private final B b = new B(); 49 private final C c = new C(); 50 private final D d = new D(); 51 private final E e = new E(); 52 53 @Override setUp()54 protected void setUp() throws Exception { 55 J.nextInstanceId = 0; 56 K.nextInstanceId = 0; 57 } 58 testInject()59 public void testInject() { 60 Injector injector = 61 Guice.createInjector( 62 new AbstractModule() { 63 @Override 64 protected void configure() { 65 bind(B.class).toInstance(b); 66 bind(C.class).toInstance(c); 67 bind(D.class).toInstance(d); 68 bind(E.class).toInstance(e); 69 bind(A.class); 70 } 71 }); 72 73 A a = injector.getInstance(A.class); 74 assertSame(b, a.b); 75 assertSame(c, a.c); 76 assertSame(d, a.d); 77 assertSame(e, a.e); 78 } 79 testQualifiedInject()80 public void testQualifiedInject() { 81 Injector injector = 82 Guice.createInjector( 83 new AbstractModule() { 84 @Override 85 protected void configure() { 86 bind(B.class).annotatedWith(Names.named("jodie")).toInstance(b); 87 bind(C.class).annotatedWith(Red.class).toInstance(c); 88 bind(D.class).annotatedWith(RED).toInstance(d); 89 bind(E.class).annotatedWith(Names.named("jesse")).toInstance(e); 90 bind(F.class); 91 } 92 }); 93 94 F f = injector.getInstance(F.class); 95 assertSame(b, f.b); 96 assertSame(c, f.c); 97 assertSame(d, f.d); 98 assertSame(e, f.e); 99 } 100 testProviderInject()101 public void testProviderInject() { 102 Injector injector = 103 Guice.createInjector( 104 new AbstractModule() { 105 @Override 106 protected void configure() { 107 bind(B.class).annotatedWith(Names.named("jodie")).toInstance(b); 108 bind(C.class).toInstance(c); 109 bind(D.class).annotatedWith(RED).toInstance(d); 110 bind(E.class).toInstance(e); 111 bind(G.class); 112 } 113 }); 114 115 G g = injector.getInstance(G.class); 116 assertSame(b, g.bProvider.get()); 117 assertSame(c, g.cProvider.get()); 118 assertSame(d, g.dProvider.get()); 119 assertSame(e, g.eProvider.get()); 120 } 121 testScopeAnnotation()122 public void testScopeAnnotation() { 123 final TestScope scope = new TestScope(); 124 125 Injector injector = 126 Guice.createInjector( 127 new AbstractModule() { 128 @Override 129 protected void configure() { 130 bind(B.class).in(scope); 131 bind(C.class).in(TestScoped.class); 132 bindScope(TestScoped.class, scope); 133 } 134 }); 135 136 B b = injector.getInstance(B.class); 137 assertSame(b, injector.getInstance(B.class)); 138 assertSame(b, injector.getInstance(B.class)); 139 140 C c = injector.getInstance(C.class); 141 assertSame(c, injector.getInstance(C.class)); 142 assertSame(c, injector.getInstance(C.class)); 143 144 H h = injector.getInstance(H.class); 145 assertSame(h, injector.getInstance(H.class)); 146 assertSame(h, injector.getInstance(H.class)); 147 148 scope.reset(); 149 150 assertNotSame(b, injector.getInstance(B.class)); 151 assertNotSame(c, injector.getInstance(C.class)); 152 assertNotSame(h, injector.getInstance(H.class)); 153 } 154 testSingleton()155 public void testSingleton() { 156 Injector injector = 157 Guice.createInjector( 158 new AbstractModule() { 159 @Override 160 protected void configure() { 161 bind(B.class).in(Singleton.class); 162 } 163 }); 164 165 B b = injector.getInstance(B.class); 166 assertSame(b, injector.getInstance(B.class)); 167 assertSame(b, injector.getInstance(B.class)); 168 169 J j = injector.getInstance(J.class); 170 assertSame(j, injector.getInstance(J.class)); 171 assertSame(j, injector.getInstance(J.class)); 172 } 173 testEagerSingleton()174 public void testEagerSingleton() { 175 Guice.createInjector( 176 Stage.PRODUCTION, 177 new AbstractModule() { 178 @Override 179 protected void configure() { 180 bind(J.class); 181 bind(K.class).in(Singleton.class); 182 } 183 }); 184 185 assertEquals(1, J.nextInstanceId); 186 assertEquals(1, K.nextInstanceId); 187 } 188 testScopesIsSingleton()189 public void testScopesIsSingleton() { 190 Injector injector = 191 Guice.createInjector( 192 new AbstractModule() { 193 @Override 194 protected void configure() { 195 bind(J.class); 196 bind(K.class).in(Singleton.class); 197 } 198 }); 199 200 assertTrue(Scopes.isSingleton(injector.getBinding(J.class))); 201 assertTrue(Scopes.isSingleton(injector.getBinding(K.class))); 202 } 203 testInjectingFinalFieldsIsForbidden()204 public void testInjectingFinalFieldsIsForbidden() { 205 try { 206 Guice.createInjector( 207 new AbstractModule() { 208 @Override 209 protected void configure() { 210 bind(L.class); 211 } 212 }); 213 fail(); 214 } catch (CreationException expected) { 215 assertContains( 216 expected.getMessage(), "1) Injected field " + L.class.getName() + ".b cannot be final."); 217 } 218 } 219 testInjectingAbstractMethodsIsForbidden()220 public void testInjectingAbstractMethodsIsForbidden() { 221 try { 222 Guice.createInjector( 223 new AbstractModule() { 224 @Override 225 protected void configure() { 226 bind(M.class); 227 } 228 }); 229 fail(); 230 } catch (CreationException expected) { 231 assertContains( 232 expected.getMessage(), 233 "1) Injected method " + AbstractM.class.getName() + ".setB() cannot be abstract."); 234 } 235 } 236 testInjectingMethodsWithTypeParametersIsForbidden()237 public void testInjectingMethodsWithTypeParametersIsForbidden() { 238 try { 239 Guice.createInjector( 240 new AbstractModule() { 241 @Override 242 protected void configure() { 243 bind(N.class); 244 } 245 }); 246 fail(); 247 } catch (CreationException expected) { 248 assertContains( 249 expected.getMessage(), 250 "1) Injected method " 251 + N.class.getName() 252 + ".setB() cannot declare type parameters of its own."); 253 } 254 } 255 testInjectingMethodsWithNonVoidReturnTypes()256 public void testInjectingMethodsWithNonVoidReturnTypes() { 257 Guice.createInjector( 258 new AbstractModule() { 259 @Override 260 protected void configure() { 261 bind(P.class); 262 } 263 }); 264 } 265 266 /** 267 * This test verifies that we can compile bindings to provider instances whose compile-time type 268 * implements javax.inject.Provider but not com.google.inject.Provider. For binary compatibility, 269 * we don't (and won't) support binding to instances of javax.inject.Provider. 270 */ testBindProviderClass()271 public void testBindProviderClass() { 272 Injector injector = 273 Guice.createInjector( 274 new AbstractModule() { 275 @Override 276 protected void configure() { 277 bind(B.class).toProvider(BProvider.class); 278 bind(B.class).annotatedWith(Names.named("1")).toProvider(BProvider.class); 279 bind(B.class).annotatedWith(Names.named("2")).toProvider(Key.get(BProvider.class)); 280 bind(B.class) 281 .annotatedWith(Names.named("3")) 282 .toProvider(TypeLiteral.get(BProvider.class)); 283 } 284 }); 285 286 injector.getInstance(Key.get(B.class)); 287 injector.getInstance(Key.get(B.class, Names.named("1"))); 288 injector.getInstance(Key.get(B.class, Names.named("2"))); 289 injector.getInstance(Key.get(B.class, Names.named("3"))); 290 } 291 testGuicify330Provider()292 public void testGuicify330Provider() { 293 Provider<String> jsr330Provider = 294 new Provider<String>() { 295 @Override 296 public String get() { 297 return "A"; 298 } 299 300 @Override 301 public String toString() { 302 return "jsr330Provider"; 303 } 304 }; 305 306 com.google.inject.Provider<String> guicified = Providers.guicify(jsr330Provider); 307 assertEquals("guicified(jsr330Provider)", guicified.toString()); 308 assertEquals("A", guicified.get()); 309 310 // when you guicify the Guice-friendly, it's a no-op 311 assertSame(guicified, Providers.guicify(guicified)); 312 313 assertFalse(guicified instanceof HasDependencies); 314 } 315 testGuicifyWithDependencies()316 public void testGuicifyWithDependencies() { 317 Provider<String> jsr330Provider = 318 new Provider<String>() { 319 @Inject double d; 320 int i; 321 322 @Inject 323 void injectMe(int i) { 324 this.i = i; 325 } 326 327 @Override 328 public String get() { 329 return d + "-" + i; 330 } 331 }; 332 333 final com.google.inject.Provider<String> guicified = Providers.guicify(jsr330Provider); 334 assertTrue(guicified instanceof HasDependencies); 335 Set<Dependency<?>> actual = ((HasDependencies) guicified).getDependencies(); 336 validateDependencies(actual, jsr330Provider.getClass()); 337 338 Injector injector = 339 Guice.createInjector( 340 new AbstractModule() { 341 @Override 342 protected void configure() { 343 bind(String.class).toProvider(guicified); 344 bind(int.class).toInstance(1); 345 bind(double.class).toInstance(2.0d); 346 } 347 }); 348 349 Binding<String> binding = injector.getBinding(String.class); 350 assertEquals("2.0-1", binding.getProvider().get()); 351 validateDependencies(actual, jsr330Provider.getClass()); 352 } 353 validateDependencies(Set<Dependency<?>> actual, Class<?> owner)354 private void validateDependencies(Set<Dependency<?>> actual, Class<?> owner) { 355 assertEquals(actual.toString(), 2, actual.size()); 356 Dependency<?> dDep = null; 357 Dependency<?> iDep = null; 358 for (Dependency<?> dep : actual) { 359 if (dep.getKey().equals(Key.get(Double.class))) { 360 dDep = dep; 361 } else if (dep.getKey().equals(Key.get(Integer.class))) { 362 iDep = dep; 363 } 364 } 365 assertNotNull(dDep); 366 assertNotNull(iDep); 367 assertEquals(TypeLiteral.get(owner), dDep.getInjectionPoint().getDeclaringType()); 368 assertEquals("d", dDep.getInjectionPoint().getMember().getName()); 369 assertEquals(-1, dDep.getParameterIndex()); 370 371 assertEquals(TypeLiteral.get(owner), iDep.getInjectionPoint().getDeclaringType()); 372 assertEquals("injectMe", iDep.getInjectionPoint().getMember().getName()); 373 assertEquals(0, iDep.getParameterIndex()); 374 } 375 376 static class A { 377 final B b; 378 @Inject C c; 379 D d; 380 E e; 381 382 @Inject A(B b)383 A(B b) { 384 this.b = b; 385 } 386 387 @Inject injectD(D d, E e)388 void injectD(D d, E e) { 389 this.d = d; 390 this.e = e; 391 } 392 } 393 394 static class B {} 395 396 static class C {} 397 398 static class D {} 399 400 static class E {} 401 402 static class F { 403 final B b; 404 @Inject @Red C c; 405 D d; 406 E e; 407 408 @Inject F(@amed"jodie") B b)409 F(@Named("jodie") B b) { 410 this.b = b; 411 } 412 413 @Inject injectD(@ed D d, @Named("jesse") E e)414 void injectD(@Red D d, @Named("jesse") E e) { 415 this.d = d; 416 this.e = e; 417 } 418 } 419 420 @Qualifier 421 @Retention(RUNTIME) 422 @interface Red {} 423 424 public static final Red RED = 425 new Red() { 426 @Override 427 public Class<? extends Annotation> annotationType() { 428 return Red.class; 429 } 430 431 @Override 432 public boolean equals(Object obj) { 433 return obj instanceof Red; 434 } 435 436 @Override 437 public int hashCode() { 438 return 0; 439 } 440 }; 441 442 static class G { 443 final Provider<B> bProvider; 444 @Inject Provider<C> cProvider; 445 Provider<D> dProvider; 446 Provider<E> eProvider; 447 448 @Inject G(@amed"jodie") Provider<B> bProvider)449 G(@Named("jodie") Provider<B> bProvider) { 450 this.bProvider = bProvider; 451 } 452 453 @Inject injectD(@ed Provider<D> dProvider, Provider<E> eProvider)454 void injectD(@Red Provider<D> dProvider, Provider<E> eProvider) { 455 this.dProvider = dProvider; 456 this.eProvider = eProvider; 457 } 458 } 459 460 @javax.inject.Scope 461 @Retention(RUNTIME) 462 @interface TestScoped {} 463 464 static class TestScope implements Scope { 465 private int now = 0; 466 467 @Override scope( Key<T> key, final com.google.inject.Provider<T> unscoped)468 public <T> com.google.inject.Provider<T> scope( 469 Key<T> key, final com.google.inject.Provider<T> unscoped) { 470 return new com.google.inject.Provider<T>() { 471 private T value; 472 private int snapshotTime = -1; 473 474 @Override 475 public T get() { 476 if (snapshotTime != now) { 477 value = unscoped.get(); 478 snapshotTime = now; 479 } 480 return value; 481 } 482 }; 483 } 484 reset()485 public void reset() { 486 now++; 487 } 488 } 489 490 @TestScoped 491 static class H {} 492 493 @Singleton 494 static class J { 495 static int nextInstanceId = 0; 496 int instanceId = nextInstanceId++; 497 } 498 499 static class K { 500 static int nextInstanceId = 0; 501 int instanceId = nextInstanceId++; 502 } 503 504 static class L { 505 @SuppressWarnings("InjectJavaxInjectOnFinalField") 506 @Inject 507 final B b = null; 508 } 509 510 abstract static class AbstractM { 511 @SuppressWarnings("JavaxInjectOnAbstractMethod") 512 @Inject setB(B b)513 abstract void setB(B b); 514 } 515 516 static class M extends AbstractM { 517 @Override 518 @SuppressWarnings("OverridesJavaxInjectableMethod") setB(B b)519 void setB(B b) {} 520 } 521 522 static class N { 523 @Inject setB(B b)524 <T> void setB(B b) {} 525 } 526 527 static class P { 528 @Inject setB(B b)529 B setB(B b) { 530 return b; 531 } 532 } 533 534 static class BProvider implements Provider<B> { 535 @Override get()536 public B get() { 537 return new B(); 538 } 539 } 540 } 541