1 /* 2 * Copyright (C) 2014 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.internal; 18 19 import static com.google.inject.Asserts.assertContains; 20 import static com.google.inject.internal.SpiUtils.assertOptionalVisitor; 21 import static com.google.inject.internal.SpiUtils.instance; 22 import static com.google.inject.internal.SpiUtils.linked; 23 import static com.google.inject.internal.SpiUtils.providerInstance; 24 import static com.google.inject.internal.SpiUtils.providerKey; 25 import static com.google.inject.name.Names.named; 26 27 import com.google.common.base.Optional; 28 import com.google.common.collect.ImmutableSet; 29 import com.google.common.collect.Iterables; 30 import com.google.common.collect.Lists; 31 import com.google.common.collect.Sets; 32 import com.google.inject.AbstractModule; 33 import com.google.inject.Asserts; 34 import com.google.inject.Binding; 35 import com.google.inject.BindingAnnotation; 36 import com.google.inject.CreationException; 37 import com.google.inject.Guice; 38 import com.google.inject.Inject; 39 import com.google.inject.Injector; 40 import com.google.inject.Key; 41 import com.google.inject.Module; 42 import com.google.inject.Provider; 43 import com.google.inject.Provides; 44 import com.google.inject.Scopes; 45 import com.google.inject.TypeLiteral; 46 import com.google.inject.internal.SpiUtils.VisitType; 47 import com.google.inject.multibindings.OptionalBinder; 48 import com.google.inject.name.Named; 49 import com.google.inject.name.Names; 50 import com.google.inject.spi.Dependency; 51 import com.google.inject.spi.Elements; 52 import com.google.inject.spi.HasDependencies; 53 import com.google.inject.spi.InstanceBinding; 54 import com.google.inject.util.Modules; 55 import com.google.inject.util.Providers; 56 import java.lang.annotation.Annotation; 57 import java.lang.annotation.ElementType; 58 import java.lang.annotation.Retention; 59 import java.lang.annotation.RetentionPolicy; 60 import java.lang.annotation.Target; 61 import java.lang.ref.WeakReference; 62 import java.lang.reflect.Method; 63 import java.util.List; 64 import java.util.Map.Entry; 65 import java.util.Set; 66 import junit.framework.TestCase; 67 68 /** @author sameb@google.com (Sam Berlin) */ 69 public class OptionalBinderTest extends TestCase { 70 71 private static final boolean HAS_JAVA_OPTIONAL; 72 private static final Class<?> JAVA_OPTIONAL_CLASS; 73 private static final Method JAVA_OPTIONAL_OR_ELSE; 74 75 static { 76 Class<?> optional = null; 77 Method orElse = null; 78 try { 79 optional = Class.forName("java.util.Optional"); 80 orElse = optional.getDeclaredMethod("orElse", Object.class); 81 } catch (ClassNotFoundException ignored) { 82 } catch (NoSuchMethodException ignored) { 83 } catch (SecurityException ignored) { 84 } 85 HAS_JAVA_OPTIONAL = optional != null; 86 JAVA_OPTIONAL_CLASS = optional; 87 JAVA_OPTIONAL_OR_ELSE = orElse; 88 } 89 90 final Key<String> stringKey = Key.get(String.class); 91 final TypeLiteral<Optional<String>> optionalOfString = new TypeLiteral<Optional<String>>() {}; 92 final TypeLiteral<?> javaOptionalOfString = 93 HAS_JAVA_OPTIONAL ? RealOptionalBinder.javaOptionalOf(stringKey.getTypeLiteral()) : null; 94 final TypeLiteral<Optional<Provider<String>>> optionalOfProviderString = 95 new TypeLiteral<Optional<Provider<String>>>() {}; 96 final TypeLiteral<?> javaOptionalOfProviderString = 97 HAS_JAVA_OPTIONAL 98 ? RealOptionalBinder.javaOptionalOfProvider(stringKey.getTypeLiteral()) 99 : null; 100 final TypeLiteral<Optional<javax.inject.Provider<String>>> optionalOfJavaxProviderString = 101 new TypeLiteral<Optional<javax.inject.Provider<String>>>() {}; 102 final TypeLiteral<?> javaOptionalOfJavaxProviderString = 103 HAS_JAVA_OPTIONAL 104 ? RealOptionalBinder.javaOptionalOfJavaxProvider(stringKey.getTypeLiteral()) 105 : null; 106 107 final Key<Integer> intKey = Key.get(Integer.class); 108 final TypeLiteral<Optional<Integer>> optionalOfInteger = new TypeLiteral<Optional<Integer>>() {}; 109 final TypeLiteral<?> javaOptionalOfInteger = 110 HAS_JAVA_OPTIONAL ? RealOptionalBinder.javaOptionalOf(intKey.getTypeLiteral()) : null; 111 final TypeLiteral<Optional<Provider<Integer>>> optionalOfProviderInteger = 112 new TypeLiteral<Optional<Provider<Integer>>>() {}; 113 final TypeLiteral<?> javaOptionalOfProviderInteger = 114 HAS_JAVA_OPTIONAL ? RealOptionalBinder.javaOptionalOfProvider(intKey.getTypeLiteral()) : null; 115 final TypeLiteral<Optional<javax.inject.Provider<Integer>>> optionalOfJavaxProviderInteger = 116 new TypeLiteral<Optional<javax.inject.Provider<Integer>>>() {}; 117 final TypeLiteral<?> javaOptionalOfJavaxProviderInteger = 118 HAS_JAVA_OPTIONAL 119 ? RealOptionalBinder.javaOptionalOfJavaxProvider(intKey.getTypeLiteral()) 120 : null; 121 122 final TypeLiteral<List<String>> listOfStrings = new TypeLiteral<List<String>>() {}; 123 testTypeNotBoundByDefault()124 public void testTypeNotBoundByDefault() { 125 Module module = 126 new AbstractModule() { 127 @Override 128 protected void configure() { 129 OptionalBinder.newOptionalBinder(binder(), String.class); 130 requireBinding(new Key<Optional<String>>() {}); // the above specifies this. 131 requireBinding(String.class); // but it doesn't specify this. 132 binder().requireExplicitBindings(); // need to do this, otherwise String will JIT 133 134 if (HAS_JAVA_OPTIONAL) { 135 requireBinding(Key.get(javaOptionalOfString)); 136 } 137 } 138 }; 139 140 try { 141 Guice.createInjector(module); 142 fail(); 143 } catch (CreationException ce) { 144 assertContains( 145 ce.getMessage(), 146 "1) Explicit bindings are required and java.lang.String is not explicitly bound."); 147 assertEquals(1, ce.getErrorMessages().size()); 148 } 149 } 150 testOptionalIsAbsentByDefault()151 public void testOptionalIsAbsentByDefault() throws Exception { 152 Module module = 153 new AbstractModule() { 154 @Override 155 protected void configure() { 156 OptionalBinder.newOptionalBinder(binder(), String.class); 157 } 158 }; 159 160 Injector injector = Guice.createInjector(module); 161 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 162 assertFalse(optional.isPresent()); 163 164 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 165 assertFalse(optionalP.isPresent()); 166 167 Optional<javax.inject.Provider<String>> optionalJxP = 168 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 169 assertFalse(optionalJxP.isPresent()); 170 171 assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, null, null, null); 172 173 if (HAS_JAVA_OPTIONAL) { 174 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 175 assertFalse(optional.isPresent()); 176 177 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 178 assertFalse(optionalP.isPresent()); 179 180 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 181 assertFalse(optionalJxP.isPresent()); 182 } 183 } 184 testUsesUserBoundValue()185 public void testUsesUserBoundValue() throws Exception { 186 Module module = 187 new AbstractModule() { 188 @Override 189 protected void configure() { 190 OptionalBinder.newOptionalBinder(binder(), String.class); 191 } 192 193 @Provides 194 String provideString() { 195 return "foo"; 196 } 197 }; 198 199 Injector injector = Guice.createInjector(module); 200 assertEquals("foo", injector.getInstance(String.class)); 201 202 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 203 assertEquals("foo", optional.get()); 204 205 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 206 assertEquals("foo", optionalP.get().get()); 207 208 Optional<javax.inject.Provider<String>> optionalJxP = 209 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 210 assertEquals("foo", optionalJxP.get().get()); 211 212 assertOptionalVisitor( 213 stringKey, setOf(module), VisitType.BOTH, 0, null, null, providerInstance("foo")); 214 215 if (HAS_JAVA_OPTIONAL) { 216 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 217 assertEquals("foo", optional.get()); 218 219 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 220 assertEquals("foo", optionalP.get().get()); 221 222 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 223 assertEquals("foo", optionalJxP.get().get()); 224 } 225 } 226 testUsesUserBoundValueNullProvidersMakeAbsent()227 public void testUsesUserBoundValueNullProvidersMakeAbsent() throws Exception { 228 Module module = 229 new AbstractModule() { 230 @Override 231 protected void configure() { 232 OptionalBinder.newOptionalBinder(binder(), String.class); 233 } 234 235 @Provides 236 String provideString() { 237 return null; 238 } 239 }; 240 241 Injector injector = Guice.createInjector(module); 242 assertEquals(null, injector.getInstance(String.class)); 243 244 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 245 assertFalse(optional.isPresent()); 246 247 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 248 assertEquals(null, optionalP.get().get()); 249 250 Optional<javax.inject.Provider<String>> optionalJxP = 251 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 252 assertEquals(null, optionalJxP.get().get()); 253 254 assertOptionalVisitor( 255 stringKey, setOf(module), VisitType.BOTH, 0, null, null, providerInstance(null)); 256 257 if (HAS_JAVA_OPTIONAL) { 258 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 259 assertFalse(optional.isPresent()); 260 261 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 262 assertEquals(null, optionalP.get().get()); 263 264 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 265 assertEquals(null, optionalJxP.get().get()); 266 } 267 } 268 269 private static class JitBinding { 270 @Inject JitBinding()271 JitBinding() {} 272 } 273 274 private static class DependsOnJitBinding { 275 @Inject DependsOnJitBinding(JitBinding jitBinding)276 DependsOnJitBinding(JitBinding jitBinding) {} 277 } 278 279 // A previous version of OptionalBinder would fail to find jit dependendencies that were created 280 // by other bindings testOptionalBinderDependsOnJitBinding()281 public void testOptionalBinderDependsOnJitBinding() { 282 Module module = 283 new AbstractModule() { 284 @Override 285 protected void configure() { 286 OptionalBinder.newOptionalBinder(binder(), JitBinding.class); 287 } 288 }; 289 290 // Everything should be absent since nothing triggered discovery of the jit binding 291 Injector injector = Guice.createInjector(module); 292 assertFalse(injector.getInstance(optionalKey(JitBinding.class)).isPresent()); 293 assertNull(injector.getExistingBinding(Key.get(JitBinding.class))); 294 295 // in this case, because jit bindings are allowed in this injector, the DependsOnJitBinding 296 // binding will get initialized and create jit bindings for its dependency. The optionalbinder 297 // should then pick it up 298 module = 299 new AbstractModule() { 300 @Override 301 protected void configure() { 302 OptionalBinder.newOptionalBinder(binder(), JitBinding.class); 303 bind(DependsOnJitBinding.class); 304 } 305 }; 306 injector = Guice.createInjector(module); 307 assertTrue(injector.getInstance(optionalKey(JitBinding.class)).isPresent()); 308 assertNotNull(injector.getExistingBinding(Key.get(JitBinding.class))); 309 310 // in this case, because the jit binding is discovered dynamically, the optionalbinder won't 311 // find it. In prior implementations of OptionalBinder this would depend on the exact 312 // sequencing of the installation of OptionalBinder vs. these injection points that trigger 313 // dynamic injection. In the current implementation it will consistently not find it. 314 module = 315 new AbstractModule() { 316 @Override 317 protected void configure() { 318 bind(Object.class) 319 .toProvider( 320 new Provider<Object>() { 321 @Inject 322 void setter(Injector injector) { 323 injector.getInstance(JitBinding.class); 324 } 325 326 @Override 327 public Object get() { 328 return null; 329 } 330 }); 331 OptionalBinder.newOptionalBinder(binder(), JitBinding.class); 332 } 333 }; 334 injector = Guice.createInjector(module); 335 assertFalse(injector.getInstance(optionalKey(JitBinding.class)).isPresent()); 336 assertNotNull(injector.getExistingBinding(Key.get(JitBinding.class))); 337 } 338 optionalKey(Class<T> type)339 public <T> Key<Optional<T>> optionalKey(Class<T> type) { 340 return Key.get(RealOptionalBinder.optionalOf(TypeLiteral.get(type))); 341 } 342 testSetDefault()343 public void testSetDefault() throws Exception { 344 Module module = 345 new AbstractModule() { 346 @Override 347 protected void configure() { 348 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a"); 349 } 350 }; 351 Injector injector = Guice.createInjector(module); 352 assertEquals("a", injector.getInstance(String.class)); 353 354 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 355 assertTrue(optional.isPresent()); 356 assertEquals("a", optional.get()); 357 358 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 359 assertTrue(optionalP.isPresent()); 360 assertEquals("a", optionalP.get().get()); 361 362 Optional<javax.inject.Provider<String>> optionalJxP = 363 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 364 assertTrue(optionalJxP.isPresent()); 365 assertEquals("a", optionalJxP.get().get()); 366 367 assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, instance("a"), null, null); 368 369 if (HAS_JAVA_OPTIONAL) { 370 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 371 assertTrue(optional.isPresent()); 372 assertEquals("a", optional.get()); 373 374 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 375 assertTrue(optionalP.isPresent()); 376 assertEquals("a", optionalP.get().get()); 377 378 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 379 assertTrue(optionalJxP.isPresent()); 380 assertEquals("a", optionalJxP.get().get()); 381 } 382 } 383 testSetBinding()384 public void testSetBinding() throws Exception { 385 Module module = 386 new AbstractModule() { 387 @Override 388 protected void configure() { 389 OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("a"); 390 } 391 }; 392 Injector injector = Guice.createInjector(module); 393 assertEquals("a", injector.getInstance(String.class)); 394 395 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 396 assertTrue(optional.isPresent()); 397 assertEquals("a", optional.get()); 398 399 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 400 assertTrue(optionalP.isPresent()); 401 assertEquals("a", optionalP.get().get()); 402 403 Optional<javax.inject.Provider<String>> optionalJxP = 404 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 405 assertTrue(optionalJxP.isPresent()); 406 assertEquals("a", optionalJxP.get().get()); 407 408 assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, null, instance("a"), null); 409 410 if (HAS_JAVA_OPTIONAL) { 411 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 412 assertTrue(optional.isPresent()); 413 assertEquals("a", optional.get()); 414 415 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 416 assertTrue(optionalP.isPresent()); 417 assertEquals("a", optionalP.get().get()); 418 419 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 420 assertTrue(optionalJxP.isPresent()); 421 assertEquals("a", optionalJxP.get().get()); 422 } 423 } 424 testSetBindingOverridesDefault()425 public void testSetBindingOverridesDefault() throws Exception { 426 Module module = 427 new AbstractModule() { 428 @Override 429 protected void configure() { 430 OptionalBinder<String> optionalBinder = 431 OptionalBinder.newOptionalBinder(binder(), String.class); 432 optionalBinder.setDefault().toInstance("a"); 433 optionalBinder.setBinding().toInstance("b"); 434 } 435 }; 436 Injector injector = Guice.createInjector(module); 437 assertEquals("b", injector.getInstance(String.class)); 438 439 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 440 assertTrue(optional.isPresent()); 441 assertEquals("b", optional.get()); 442 443 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 444 assertTrue(optionalP.isPresent()); 445 assertEquals("b", optionalP.get().get()); 446 447 Optional<javax.inject.Provider<String>> optionalJxP = 448 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 449 assertTrue(optionalJxP.isPresent()); 450 assertEquals("b", optionalJxP.get().get()); 451 452 assertOptionalVisitor( 453 stringKey, setOf(module), VisitType.BOTH, 0, instance("a"), instance("b"), null); 454 455 if (HAS_JAVA_OPTIONAL) { 456 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 457 assertTrue(optional.isPresent()); 458 assertEquals("b", optional.get()); 459 460 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 461 assertTrue(optionalP.isPresent()); 462 assertEquals("b", optionalP.get().get()); 463 464 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 465 assertTrue(optionalJxP.isPresent()); 466 assertEquals("b", optionalJxP.get().get()); 467 } 468 } 469 testSpreadAcrossModules()470 public void testSpreadAcrossModules() throws Exception { 471 Module module1 = 472 new AbstractModule() { 473 @Override 474 protected void configure() { 475 OptionalBinder.newOptionalBinder(binder(), String.class); 476 } 477 }; 478 Module module2 = 479 new AbstractModule() { 480 @Override 481 protected void configure() { 482 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a"); 483 } 484 }; 485 Module module3 = 486 new AbstractModule() { 487 @Override 488 protected void configure() { 489 OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("b"); 490 } 491 }; 492 493 Injector injector = Guice.createInjector(module1, module2, module3); 494 assertEquals("b", injector.getInstance(String.class)); 495 496 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 497 assertTrue(optional.isPresent()); 498 assertEquals("b", optional.get()); 499 500 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 501 assertTrue(optionalP.isPresent()); 502 assertEquals("b", optionalP.get().get()); 503 504 Optional<javax.inject.Provider<String>> optionalJxP = 505 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 506 assertTrue(optionalJxP.isPresent()); 507 assertEquals("b", optionalJxP.get().get()); 508 509 assertOptionalVisitor( 510 stringKey, 511 setOf(module1, module2, module3), 512 VisitType.BOTH, 513 0, 514 instance("a"), 515 instance("b"), 516 null); 517 518 if (HAS_JAVA_OPTIONAL) { 519 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 520 assertTrue(optional.isPresent()); 521 assertEquals("b", optional.get()); 522 523 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 524 assertTrue(optionalP.isPresent()); 525 assertEquals("b", optionalP.get().get()); 526 527 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 528 assertTrue(optionalJxP.isPresent()); 529 assertEquals("b", optionalJxP.get().get()); 530 } 531 } 532 testExactSameBindingCollapses_defaults()533 public void testExactSameBindingCollapses_defaults() throws Exception { 534 Module module = 535 new AbstractModule() { 536 @Override 537 protected void configure() { 538 OptionalBinder.newOptionalBinder(binder(), String.class) 539 .setDefault() 540 .toInstance(new String("a")); // using new String to ensure .equals is checked. 541 OptionalBinder.newOptionalBinder(binder(), String.class) 542 .setDefault() 543 .toInstance(new String("a")); 544 } 545 }; 546 Injector injector = Guice.createInjector(module); 547 assertEquals("a", injector.getInstance(String.class)); 548 549 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 550 assertTrue(optional.isPresent()); 551 assertEquals("a", optional.get()); 552 553 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 554 assertTrue(optionalP.isPresent()); 555 assertEquals("a", optionalP.get().get()); 556 557 Optional<javax.inject.Provider<String>> optionalJxP = 558 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 559 assertTrue(optionalJxP.isPresent()); 560 assertEquals("a", optionalJxP.get().get()); 561 562 assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, instance("a"), null, null); 563 564 if (HAS_JAVA_OPTIONAL) { 565 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 566 assertTrue(optional.isPresent()); 567 assertEquals("a", optional.get()); 568 569 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 570 assertTrue(optionalP.isPresent()); 571 assertEquals("a", optionalP.get().get()); 572 573 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 574 assertTrue(optionalJxP.isPresent()); 575 assertEquals("a", optionalJxP.get().get()); 576 } 577 } 578 testExactSameBindingCollapses_actual()579 public void testExactSameBindingCollapses_actual() throws Exception { 580 Module module = 581 new AbstractModule() { 582 @Override 583 protected void configure() { 584 OptionalBinder.newOptionalBinder(binder(), String.class) 585 .setBinding() 586 .toInstance(new String("a")); // using new String to ensure .equals is checked. 587 OptionalBinder.newOptionalBinder(binder(), String.class) 588 .setBinding() 589 .toInstance(new String("a")); 590 } 591 }; 592 Injector injector = Guice.createInjector(module); 593 assertEquals("a", injector.getInstance(String.class)); 594 595 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 596 assertTrue(optional.isPresent()); 597 assertEquals("a", optional.get()); 598 599 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 600 assertTrue(optionalP.isPresent()); 601 assertEquals("a", optionalP.get().get()); 602 603 Optional<javax.inject.Provider<String>> optionalJxP = 604 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 605 assertTrue(optionalJxP.isPresent()); 606 assertEquals("a", optionalJxP.get().get()); 607 608 assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, null, instance("a"), null); 609 610 if (HAS_JAVA_OPTIONAL) { 611 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 612 assertTrue(optional.isPresent()); 613 assertEquals("a", optional.get()); 614 615 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 616 assertTrue(optionalP.isPresent()); 617 assertEquals("a", optionalP.get().get()); 618 619 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 620 assertTrue(optionalJxP.isPresent()); 621 assertEquals("a", optionalJxP.get().get()); 622 } 623 } 624 testDifferentBindingsFail_defaults()625 public void testDifferentBindingsFail_defaults() { 626 Module module = 627 new AbstractModule() { 628 @Override 629 protected void configure() { 630 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a"); 631 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("b"); 632 } 633 }; 634 try { 635 Guice.createInjector(module); 636 fail(); 637 } catch (CreationException ce) { 638 assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size()); 639 assertContains( 640 ce.getMessage(), 641 "1) A binding to java.lang.String annotated with @" 642 + RealOptionalBinder.Default.class.getName() 643 + " was already configured at " 644 + module.getClass().getName() 645 + ".configure(", 646 "at " + module.getClass().getName() + ".configure("); 647 } 648 } 649 testDifferentBindingsFail_actual()650 public void testDifferentBindingsFail_actual() { 651 Module module = 652 new AbstractModule() { 653 @Override 654 protected void configure() { 655 OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("a"); 656 OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("b"); 657 } 658 }; 659 try { 660 Guice.createInjector(module); 661 fail(); 662 } catch (CreationException ce) { 663 assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size()); 664 assertContains( 665 ce.getMessage(), 666 "1) A binding to java.lang.String annotated with @" 667 + RealOptionalBinder.Actual.class.getName() 668 + " was already configured at " 669 + module.getClass().getName() 670 + ".configure(", 671 "at " + module.getClass().getName() + ".configure("); 672 } 673 } 674 testDifferentBindingsFail_both()675 public void testDifferentBindingsFail_both() { 676 Module module = 677 new AbstractModule() { 678 @Override 679 protected void configure() { 680 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a"); 681 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("b"); 682 OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("b"); 683 OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("c"); 684 } 685 }; 686 try { 687 Guice.createInjector(module); 688 fail(); 689 } catch (CreationException ce) { 690 assertEquals(ce.getMessage(), 2, ce.getErrorMessages().size()); 691 assertContains( 692 ce.getMessage(), 693 "1) A binding to java.lang.String annotated with @" 694 + RealOptionalBinder.Default.class.getName() 695 + " was already configured at " 696 + module.getClass().getName() 697 + ".configure(", 698 "at " + module.getClass().getName() + ".configure(", 699 "2) A binding to java.lang.String annotated with @" 700 + RealOptionalBinder.Actual.class.getName() 701 + " was already configured at " 702 + module.getClass().getName() 703 + ".configure(", 704 "at " + module.getClass().getName() + ".configure("); 705 } 706 } 707 testQualifiedAggregatesTogether()708 public void testQualifiedAggregatesTogether() throws Exception { 709 Module module1 = 710 new AbstractModule() { 711 @Override 712 protected void configure() { 713 OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("foo"))); 714 } 715 }; 716 Module module2 = 717 new AbstractModule() { 718 @Override 719 protected void configure() { 720 OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("foo"))) 721 .setDefault() 722 .toInstance("a"); 723 } 724 }; 725 Module module3 = 726 new AbstractModule() { 727 @Override 728 protected void configure() { 729 OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("foo"))) 730 .setBinding() 731 .toInstance("b"); 732 } 733 }; 734 735 Injector injector = Guice.createInjector(module1, module2, module3); 736 assertEquals("b", injector.getInstance(Key.get(String.class, Names.named("foo")))); 737 738 Optional<String> optional = injector.getInstance(Key.get(optionalOfString, Names.named("foo"))); 739 assertTrue(optional.isPresent()); 740 assertEquals("b", optional.get()); 741 742 Optional<Provider<String>> optionalP = 743 injector.getInstance(Key.get(optionalOfProviderString, Names.named("foo"))); 744 assertTrue(optionalP.isPresent()); 745 assertEquals("b", optionalP.get().get()); 746 747 Optional<javax.inject.Provider<String>> optionalJxP = 748 injector.getInstance(Key.get(optionalOfJavaxProviderString, Names.named("foo"))); 749 assertTrue(optionalJxP.isPresent()); 750 assertEquals("b", optionalJxP.get().get()); 751 752 assertOptionalVisitor( 753 Key.get(String.class, Names.named("foo")), 754 setOf(module1, module2, module3), 755 VisitType.BOTH, 756 0, 757 instance("a"), 758 instance("b"), 759 null); 760 761 if (HAS_JAVA_OPTIONAL) { 762 optional = 763 toOptional(injector.getInstance(Key.get(javaOptionalOfString, Names.named("foo")))); 764 assertTrue(optional.isPresent()); 765 assertEquals("b", optional.get()); 766 767 optionalP = 768 toOptional( 769 injector.getInstance(Key.get(javaOptionalOfProviderString, Names.named("foo")))); 770 assertTrue(optionalP.isPresent()); 771 assertEquals("b", optionalP.get().get()); 772 773 optionalJxP = 774 toOptional( 775 injector.getInstance(Key.get(javaOptionalOfJavaxProviderString, Names.named("foo")))); 776 assertTrue(optionalJxP.isPresent()); 777 assertEquals("b", optionalJxP.get().get()); 778 } 779 } 780 testMultipleDifferentOptionals()781 public void testMultipleDifferentOptionals() { 782 final Key<String> bKey = Key.get(String.class, named("b")); 783 final Key<String> cKey = Key.get(String.class, named("c")); 784 Module module = 785 new AbstractModule() { 786 @Override 787 protected void configure() { 788 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a"); 789 OptionalBinder.newOptionalBinder(binder(), Integer.class).setDefault().toInstance(1); 790 791 OptionalBinder.newOptionalBinder(binder(), bKey).setDefault().toInstance("b"); 792 OptionalBinder.newOptionalBinder(binder(), cKey).setDefault().toInstance("c"); 793 } 794 }; 795 Injector injector = Guice.createInjector(module); 796 assertEquals("a", injector.getInstance(String.class)); 797 assertEquals(1, injector.getInstance(Integer.class).intValue()); 798 assertEquals("b", injector.getInstance(bKey)); 799 assertEquals("c", injector.getInstance(cKey)); 800 801 assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 3, instance("a"), null, null); 802 assertOptionalVisitor(intKey, setOf(module), VisitType.BOTH, 3, instance(1), null, null); 803 assertOptionalVisitor(bKey, setOf(module), VisitType.BOTH, 3, instance("b"), null, null); 804 assertOptionalVisitor(cKey, setOf(module), VisitType.BOTH, 3, instance("c"), null, null); 805 } 806 testOptionalIsAppropriatelyLazy()807 public void testOptionalIsAppropriatelyLazy() throws Exception { 808 Module module = 809 new AbstractModule() { 810 int nextValue = 1; 811 812 @Override 813 protected void configure() { 814 OptionalBinder.newOptionalBinder(binder(), Integer.class) 815 .setDefault() 816 .to(Key.get(Integer.class, Names.named("foo"))); 817 } 818 819 @Provides 820 @Named("foo") 821 int provideInt() { 822 return nextValue++; 823 } 824 }; 825 Injector injector = Guice.createInjector(module); 826 827 Optional<Provider<Integer>> optionalP = 828 injector.getInstance(Key.get(optionalOfProviderInteger)); 829 Optional<javax.inject.Provider<Integer>> optionalJxP = 830 injector.getInstance(Key.get(optionalOfJavaxProviderInteger)); 831 832 assertEquals(1, injector.getInstance(Integer.class).intValue()); 833 assertEquals(2, injector.getInstance(Integer.class).intValue()); 834 835 // Calling .get() on an Optional<Integer> multiple times will keep giving the same thing 836 Optional<Integer> optional = injector.getInstance(Key.get(optionalOfInteger)); 837 assertEquals(3, optional.get().intValue()); 838 assertEquals(3, optional.get().intValue()); 839 // But getting another Optional<Integer> will give a new one. 840 assertEquals(4, injector.getInstance(Key.get(optionalOfInteger)).get().intValue()); 841 842 // And the Optional<Provider> will return a provider that gives a new value each time. 843 assertEquals(5, optionalP.get().get().intValue()); 844 assertEquals(6, optionalP.get().get().intValue()); 845 846 assertEquals(7, optionalJxP.get().get().intValue()); 847 assertEquals(8, optionalJxP.get().get().intValue()); 848 849 // and same rules with java.util.Optional 850 if (HAS_JAVA_OPTIONAL) { 851 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfInteger))); 852 assertEquals(9, optional.get().intValue()); 853 assertEquals(9, optional.get().intValue()); 854 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfInteger))); 855 assertEquals(10, optional.get().intValue()); 856 857 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderInteger))); 858 assertEquals(11, optionalP.get().get().intValue()); 859 assertEquals(12, optionalP.get().get().intValue()); 860 861 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderInteger))); 862 assertEquals(13, optionalJxP.get().get().intValue()); 863 assertEquals(14, optionalJxP.get().get().intValue()); 864 } 865 } 866 testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_default()867 public void testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_default() 868 throws Exception { 869 Module module = 870 new AbstractModule() { 871 @Override 872 protected void configure() { 873 OptionalBinder.newOptionalBinder(binder(), String.class) 874 .setDefault() 875 .toProvider(Providers.<String>of(null)); 876 } 877 }; 878 Injector injector = Guice.createInjector(module); 879 assertNull(injector.getInstance(String.class)); 880 881 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 882 assertFalse(optional.isPresent()); 883 884 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 885 assertTrue(optionalP.isPresent()); 886 assertNull(optionalP.get().get()); 887 888 Optional<javax.inject.Provider<String>> optionalJxP = 889 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 890 assertTrue(optionalJxP.isPresent()); 891 assertNull(optionalJxP.get().get()); 892 893 assertOptionalVisitor( 894 stringKey, 895 setOf(module), 896 VisitType.BOTH, 897 0, 898 SpiUtils.<String>providerInstance(null), 899 null, 900 null); 901 902 if (HAS_JAVA_OPTIONAL) { 903 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 904 assertFalse(optional.isPresent()); 905 906 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 907 assertTrue(optionalP.isPresent()); 908 assertNull(optionalP.get().get()); 909 910 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 911 assertTrue(optionalJxP.isPresent()); 912 assertNull(optionalJxP.get().get()); 913 } 914 } 915 testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_actual()916 public void testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_actual() 917 throws Exception { 918 Module module = 919 new AbstractModule() { 920 @Override 921 protected void configure() { 922 OptionalBinder.newOptionalBinder(binder(), String.class) 923 .setBinding() 924 .toProvider(Providers.<String>of(null)); 925 } 926 }; 927 Injector injector = Guice.createInjector(module); 928 assertNull(injector.getInstance(String.class)); 929 930 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 931 assertFalse(optional.isPresent()); 932 933 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 934 assertTrue(optionalP.isPresent()); 935 assertNull(optionalP.get().get()); 936 937 Optional<javax.inject.Provider<String>> optionalJxP = 938 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 939 assertTrue(optionalJxP.isPresent()); 940 assertNull(optionalJxP.get().get()); 941 942 assertOptionalVisitor( 943 stringKey, 944 setOf(module), 945 VisitType.BOTH, 946 0, 947 null, 948 SpiUtils.<String>providerInstance(null), 949 null); 950 951 if (HAS_JAVA_OPTIONAL) { 952 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 953 assertFalse(optional.isPresent()); 954 955 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 956 assertTrue(optionalP.isPresent()); 957 assertNull(optionalP.get().get()); 958 959 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 960 assertTrue(optionalJxP.isPresent()); 961 assertNull(optionalJxP.get().get()); 962 } 963 } 964 965 // TODO(sameb): Maybe change this? testLinkedToNullActualDoesntFallbackToDefault()966 public void testLinkedToNullActualDoesntFallbackToDefault() throws Exception { 967 Module module = 968 new AbstractModule() { 969 @Override 970 protected void configure() { 971 OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a"); 972 OptionalBinder.newOptionalBinder(binder(), String.class) 973 .setBinding() 974 .toProvider(Providers.<String>of(null)); 975 } 976 }; 977 Injector injector = Guice.createInjector(module); 978 assertNull(injector.getInstance(String.class)); 979 980 Optional<String> optional = injector.getInstance(Key.get(optionalOfString)); 981 assertFalse(optional.isPresent()); 982 983 Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString)); 984 assertTrue(optionalP.isPresent()); 985 assertNull(optionalP.get().get()); 986 987 Optional<javax.inject.Provider<String>> optionalJxP = 988 injector.getInstance(Key.get(optionalOfJavaxProviderString)); 989 assertTrue(optionalJxP.isPresent()); 990 assertNull(optionalP.get().get()); 991 992 assertOptionalVisitor( 993 stringKey, 994 setOf(module), 995 VisitType.BOTH, 996 0, 997 instance("a"), 998 SpiUtils.<String>providerInstance(null), 999 null); 1000 1001 if (HAS_JAVA_OPTIONAL) { 1002 optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString))); 1003 assertFalse(optional.isPresent()); 1004 1005 optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString))); 1006 assertTrue(optionalP.isPresent()); 1007 assertNull(optionalP.get().get()); 1008 1009 optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString))); 1010 assertTrue(optionalJxP.isPresent()); 1011 assertNull(optionalJxP.get().get()); 1012 } 1013 } 1014 testSourceLinesInException()1015 public void testSourceLinesInException() { 1016 try { 1017 Guice.createInjector( 1018 new AbstractModule() { 1019 @Override 1020 protected void configure() { 1021 OptionalBinder.newOptionalBinder(binder(), Integer.class).setDefault(); 1022 } 1023 }); 1024 fail(); 1025 } catch (CreationException expected) { 1026 assertContains( 1027 expected.getMessage(), 1028 "No implementation for java.lang.Integer", 1029 "at " + getClass().getName()); 1030 } 1031 } 1032 testDependencies_both()1033 public void testDependencies_both() { 1034 Injector injector = 1035 Guice.createInjector( 1036 new AbstractModule() { 1037 @Override 1038 protected void configure() { 1039 OptionalBinder<String> optionalbinder = 1040 OptionalBinder.newOptionalBinder(binder(), String.class); 1041 optionalbinder.setDefault().toInstance("A"); 1042 optionalbinder.setBinding().to(Key.get(String.class, Names.named("b"))); 1043 bindConstant().annotatedWith(Names.named("b")).to("B"); 1044 } 1045 }); 1046 1047 Binding<String> binding = injector.getBinding(Key.get(String.class)); 1048 HasDependencies withDependencies = (HasDependencies) binding; 1049 Set<String> elements = Sets.newHashSet(); 1050 elements.addAll(recurseForDependencies(injector, withDependencies)); 1051 assertEquals(ImmutableSet.of("B"), elements); 1052 } 1053 testDependencies_actual()1054 public void testDependencies_actual() { 1055 Injector injector = 1056 Guice.createInjector( 1057 new AbstractModule() { 1058 @Override 1059 protected void configure() { 1060 OptionalBinder<String> optionalbinder = 1061 OptionalBinder.newOptionalBinder(binder(), String.class); 1062 optionalbinder.setBinding().to(Key.get(String.class, Names.named("b"))); 1063 bindConstant().annotatedWith(Names.named("b")).to("B"); 1064 } 1065 }); 1066 1067 Binding<String> binding = injector.getBinding(Key.get(String.class)); 1068 HasDependencies withDependencies = (HasDependencies) binding; 1069 Set<String> elements = Sets.newHashSet(); 1070 elements.addAll(recurseForDependencies(injector, withDependencies)); 1071 assertEquals(ImmutableSet.of("B"), elements); 1072 } 1073 testDependencies_default()1074 public void testDependencies_default() { 1075 Injector injector = 1076 Guice.createInjector( 1077 new AbstractModule() { 1078 @Override 1079 protected void configure() { 1080 OptionalBinder<String> optionalbinder = 1081 OptionalBinder.newOptionalBinder(binder(), String.class); 1082 optionalbinder.setDefault().toInstance("A"); 1083 } 1084 }); 1085 1086 Binding<String> binding = injector.getBinding(Key.get(String.class)); 1087 HasDependencies withDependencies = (HasDependencies) binding; 1088 Set<String> elements = Sets.newHashSet(); 1089 elements.addAll(recurseForDependencies(injector, withDependencies)); 1090 assertEquals(ImmutableSet.of("A"), elements); 1091 } 1092 1093 @SuppressWarnings("rawtypes") recurseForDependencies(Injector injector, HasDependencies hasDependencies)1094 private Set<String> recurseForDependencies(Injector injector, HasDependencies hasDependencies) { 1095 Set<String> elements = Sets.newHashSet(); 1096 for (Dependency<?> dependency : hasDependencies.getDependencies()) { 1097 Binding<?> binding = injector.getBinding(dependency.getKey()); 1098 HasDependencies deps = (HasDependencies) binding; 1099 if (binding instanceof InstanceBinding) { 1100 elements.add((String) ((InstanceBinding) binding).getInstance()); 1101 } else { 1102 elements.addAll(recurseForDependencies(injector, deps)); 1103 } 1104 } 1105 return elements; 1106 } 1107 1108 /** Doubly-installed modules should not conflict, even when one is overridden. */ testModuleOverrideRepeatedInstalls_toInstance()1109 public void testModuleOverrideRepeatedInstalls_toInstance() { 1110 Module m = 1111 new AbstractModule() { 1112 @Override 1113 protected void configure() { 1114 OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class); 1115 b.setDefault().toInstance("A"); 1116 b.setBinding().toInstance("B"); 1117 } 1118 }; 1119 1120 assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class))); 1121 1122 Injector injector = Guice.createInjector(m, Modules.override(m).with(m)); 1123 assertEquals("B", injector.getInstance(Key.get(String.class))); 1124 1125 assertOptionalVisitor( 1126 stringKey, 1127 setOf(m, Modules.override(m).with(m)), 1128 VisitType.BOTH, 1129 0, 1130 instance("A"), 1131 instance("B"), 1132 null); 1133 } 1134 testModuleOverrideRepeatedInstalls_toKey()1135 public void testModuleOverrideRepeatedInstalls_toKey() { 1136 final Key<String> aKey = Key.get(String.class, Names.named("A_string")); 1137 final Key<String> bKey = Key.get(String.class, Names.named("B_string")); 1138 Module m = 1139 new AbstractModule() { 1140 @Override 1141 protected void configure() { 1142 bind(aKey).toInstance("A"); 1143 bind(bKey).toInstance("B"); 1144 1145 OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class); 1146 b.setDefault().to(aKey); 1147 b.setBinding().to(bKey); 1148 } 1149 }; 1150 1151 assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class))); 1152 1153 Injector injector = Guice.createInjector(m, Modules.override(m).with(m)); 1154 assertEquals("B", injector.getInstance(Key.get(String.class))); 1155 1156 assertOptionalVisitor( 1157 stringKey, 1158 setOf(m, Modules.override(m).with(m)), 1159 VisitType.BOTH, 1160 0, 1161 linked(aKey), 1162 linked(bKey), 1163 null); 1164 } 1165 testModuleOverrideRepeatedInstalls_toProviderInstance()1166 public void testModuleOverrideRepeatedInstalls_toProviderInstance() { 1167 // Providers#of() does not redefine equals/hashCode, so use the same one both times. 1168 final Provider<String> aProvider = Providers.of("A"); 1169 final Provider<String> bProvider = Providers.of("B"); 1170 Module m = 1171 new AbstractModule() { 1172 @Override 1173 protected void configure() { 1174 OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class); 1175 b.setDefault().toProvider(aProvider); 1176 b.setBinding().toProvider(bProvider); 1177 } 1178 }; 1179 1180 assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class))); 1181 1182 Injector injector = Guice.createInjector(m, Modules.override(m).with(m)); 1183 assertEquals("B", injector.getInstance(Key.get(String.class))); 1184 1185 assertOptionalVisitor( 1186 stringKey, 1187 setOf(m, Modules.override(m).with(m)), 1188 VisitType.BOTH, 1189 0, 1190 providerInstance("A"), 1191 providerInstance("B"), 1192 null); 1193 } 1194 1195 private static class AStringProvider implements Provider<String> { 1196 @Override get()1197 public String get() { 1198 return "A"; 1199 } 1200 } 1201 1202 private static class BStringProvider implements Provider<String> { 1203 @Override get()1204 public String get() { 1205 return "B"; 1206 } 1207 } 1208 testModuleOverrideRepeatedInstalls_toProviderKey()1209 public void testModuleOverrideRepeatedInstalls_toProviderKey() { 1210 Module m = 1211 new AbstractModule() { 1212 @Override 1213 protected void configure() { 1214 OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class); 1215 b.setDefault().toProvider(Key.get(AStringProvider.class)); 1216 b.setBinding().toProvider(Key.get(BStringProvider.class)); 1217 } 1218 }; 1219 1220 assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class))); 1221 1222 Injector injector = Guice.createInjector(m, Modules.override(m).with(m)); 1223 assertEquals("B", injector.getInstance(Key.get(String.class))); 1224 1225 assertOptionalVisitor( 1226 stringKey, 1227 setOf(m, Modules.override(m).with(m)), 1228 VisitType.BOTH, 1229 0, 1230 providerKey(Key.get(AStringProvider.class)), 1231 providerKey(Key.get(BStringProvider.class)), 1232 null); 1233 } 1234 1235 private static class StringGrabber { 1236 private final String string; 1237 1238 @SuppressWarnings("unused") // Found by reflection StringGrabber(@amed"A_string") String string)1239 public StringGrabber(@Named("A_string") String string) { 1240 this.string = string; 1241 } 1242 1243 @SuppressWarnings("unused") // Found by reflection StringGrabber(@amed"B_string") String string, int unused)1244 public StringGrabber(@Named("B_string") String string, int unused) { 1245 this.string = string; 1246 } 1247 1248 @Override hashCode()1249 public int hashCode() { 1250 return string.hashCode(); 1251 } 1252 1253 @Override equals(Object obj)1254 public boolean equals(Object obj) { 1255 return (obj instanceof StringGrabber) && ((StringGrabber) obj).string.equals(string); 1256 } 1257 1258 @Override toString()1259 public String toString() { 1260 return "StringGrabber(" + string + ")"; 1261 } 1262 } 1263 testModuleOverrideRepeatedInstalls_toConstructor()1264 public void testModuleOverrideRepeatedInstalls_toConstructor() { 1265 Module m = 1266 new AbstractModule() { 1267 @Override 1268 protected void configure() { 1269 Key<String> aKey = Key.get(String.class, Names.named("A_string")); 1270 Key<String> bKey = Key.get(String.class, Names.named("B_string")); 1271 bind(aKey).toInstance("A"); 1272 bind(bKey).toInstance("B"); 1273 bind(Integer.class).toInstance(0); // used to disambiguate constructors 1274 1275 OptionalBinder<StringGrabber> b = 1276 OptionalBinder.newOptionalBinder(binder(), StringGrabber.class); 1277 try { 1278 b.setDefault().toConstructor(StringGrabber.class.getConstructor(String.class)); 1279 b.setBinding() 1280 .toConstructor(StringGrabber.class.getConstructor(String.class, int.class)); 1281 } catch (NoSuchMethodException e) { 1282 fail("No such method: " + e.getMessage()); 1283 } 1284 } 1285 }; 1286 1287 assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(StringGrabber.class)).string); 1288 1289 Injector injector = Guice.createInjector(m, Modules.override(m).with(m)); 1290 assertEquals("B", injector.getInstance(Key.get(StringGrabber.class)).string); 1291 } 1292 1293 /** 1294 * Unscoped bindings should not conflict, whether they were bound with no explicit scope, or 1295 * explicitly bound in {@link Scopes#NO_SCOPE}. 1296 */ testDuplicateUnscopedBindings()1297 public void testDuplicateUnscopedBindings() { 1298 Module m = 1299 new AbstractModule() { 1300 @Override 1301 protected void configure() { 1302 OptionalBinder<Integer> b = OptionalBinder.newOptionalBinder(binder(), Integer.class); 1303 b.setDefault().to(Key.get(Integer.class, named("foo"))); 1304 b.setDefault().to(Key.get(Integer.class, named("foo"))).in(Scopes.NO_SCOPE); 1305 b.setBinding().to(Key.get(Integer.class, named("foo"))); 1306 b.setBinding().to(Key.get(Integer.class, named("foo"))).in(Scopes.NO_SCOPE); 1307 } 1308 1309 @Provides 1310 @Named("foo") 1311 int provideInt() { 1312 return 5; 1313 } 1314 }; 1315 assertEquals(5, Guice.createInjector(m).getInstance(Integer.class).intValue()); 1316 } 1317 1318 /** Ensure key hash codes are fixed at injection time, not binding time. */ testKeyHashCodesFixedAtInjectionTime()1319 public void testKeyHashCodesFixedAtInjectionTime() { 1320 Module m = 1321 new AbstractModule() { 1322 @Override 1323 protected void configure() { 1324 OptionalBinder<List<String>> b = 1325 OptionalBinder.newOptionalBinder(binder(), listOfStrings); 1326 List<String> list = Lists.newArrayList(); 1327 b.setDefault().toInstance(list); 1328 b.setBinding().toInstance(list); 1329 list.add("A"); 1330 list.add("B"); 1331 } 1332 }; 1333 1334 Injector injector = Guice.createInjector(m); 1335 for (Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) { 1336 Key<?> bindingKey = entry.getKey(); 1337 Key<?> clonedKey; 1338 if (bindingKey.getAnnotation() != null) { 1339 clonedKey = Key.get(bindingKey.getTypeLiteral(), bindingKey.getAnnotation()); 1340 } else if (bindingKey.getAnnotationType() != null) { 1341 clonedKey = Key.get(bindingKey.getTypeLiteral(), bindingKey.getAnnotationType()); 1342 } else { 1343 clonedKey = Key.get(bindingKey.getTypeLiteral()); 1344 } 1345 assertEquals(bindingKey, clonedKey); 1346 assertEquals( 1347 "Incorrect hashcode for " + bindingKey + " -> " + entry.getValue(), 1348 bindingKey.hashCode(), 1349 clonedKey.hashCode()); 1350 } 1351 } 1352 1353 /** Ensure bindings do not rehash their keys once returned from {@link Elements#getElements}. */ testBindingKeysFixedOnReturnFromGetElements()1354 public void testBindingKeysFixedOnReturnFromGetElements() { 1355 final List<String> list = Lists.newArrayList(); 1356 Module m = 1357 new AbstractModule() { 1358 @Override 1359 protected void configure() { 1360 OptionalBinder<List<String>> b = 1361 OptionalBinder.newOptionalBinder(binder(), listOfStrings); 1362 b.setDefault().toInstance(list); 1363 list.add("A"); 1364 list.add("B"); 1365 } 1366 }; 1367 1368 InstanceBinding<?> binding = 1369 Iterables.getOnlyElement(Iterables.filter(Elements.getElements(m), InstanceBinding.class)); 1370 Key<?> keyBefore = binding.getKey(); 1371 assertEquals(listOfStrings, keyBefore.getTypeLiteral()); 1372 1373 list.add("C"); 1374 Key<?> keyAfter = binding.getKey(); 1375 assertSame(keyBefore, keyAfter); 1376 } 1377 1378 @BindingAnnotation 1379 @Retention(RetentionPolicy.RUNTIME) 1380 @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) 1381 private static @interface Marker {} 1382 1383 @Marker testMatchingMarkerAnnotations()1384 public void testMatchingMarkerAnnotations() throws Exception { 1385 Method m = OptionalBinderTest.class.getDeclaredMethod("testMatchingMarkerAnnotations"); 1386 assertNotNull(m); 1387 final Annotation marker = m.getAnnotation(Marker.class); 1388 Injector injector = 1389 Guice.createInjector( 1390 new AbstractModule() { 1391 @Override 1392 public void configure() { 1393 OptionalBinder<Integer> mb1 = 1394 OptionalBinder.newOptionalBinder( 1395 binder(), Key.get(Integer.class, Marker.class)); 1396 OptionalBinder<Integer> mb2 = 1397 OptionalBinder.newOptionalBinder(binder(), Key.get(Integer.class, marker)); 1398 mb1.setDefault().toInstance(1); 1399 mb2.setBinding().toInstance(2); 1400 1401 // This assures us that the two binders are equivalent, so we expect the instance added to 1402 // each to have been added to one set. 1403 assertEquals(mb1, mb2); 1404 } 1405 }); 1406 Integer i1 = injector.getInstance(Key.get(Integer.class, Marker.class)); 1407 Integer i2 = injector.getInstance(Key.get(Integer.class, marker)); 1408 1409 // These must be identical, because the marker annotations collapsed to the same thing. 1410 assertSame(i1, i2); 1411 assertEquals(2, i2.intValue()); 1412 } 1413 1414 // Tests for com.google.inject.internal.WeakKeySet not leaking memory. testWeakKeySet_integration()1415 public void testWeakKeySet_integration() { 1416 Injector parentInjector = 1417 Guice.createInjector( 1418 new AbstractModule() { 1419 @Override 1420 protected void configure() { 1421 bind(String.class).toInstance("hi"); 1422 } 1423 }); 1424 WeakKeySetUtils.assertNotBlacklisted(parentInjector, Key.get(Integer.class)); 1425 1426 Injector childInjector = 1427 parentInjector.createChildInjector( 1428 new AbstractModule() { 1429 @Override 1430 protected void configure() { 1431 OptionalBinder.newOptionalBinder(binder(), Integer.class) 1432 .setDefault() 1433 .toInstance(4); 1434 } 1435 }); 1436 WeakReference<Injector> weakRef = new WeakReference<>(childInjector); 1437 WeakKeySetUtils.assertBlacklisted(parentInjector, Key.get(Integer.class)); 1438 1439 // Clear the ref, GC, and ensure that we are no longer blacklisting. 1440 childInjector = null; 1441 1442 Asserts.awaitClear(weakRef); 1443 WeakKeySetUtils.assertNotBlacklisted(parentInjector, Key.get(Integer.class)); 1444 } 1445 testCompareEqualsAgainstOtherAnnotation()1446 public void testCompareEqualsAgainstOtherAnnotation() { 1447 RealOptionalBinder.Actual impl1 = new RealOptionalBinder.ActualImpl("foo"); 1448 RealOptionalBinder.Actual other1 = Dummy.class.getAnnotation(RealOptionalBinder.Actual.class); 1449 assertEquals(impl1, other1); 1450 1451 RealOptionalBinder.Default impl2 = new RealOptionalBinder.DefaultImpl("foo"); 1452 RealOptionalBinder.Default other2 = Dummy.class.getAnnotation(RealOptionalBinder.Default.class); 1453 assertEquals(impl2, other2); 1454 1455 assertFalse(impl1.equals(impl2)); 1456 assertFalse(impl1.equals(other2)); 1457 assertFalse(impl2.equals(other1)); 1458 assertFalse(other1.equals(other2)); 1459 } 1460 1461 @RealOptionalBinder.Actual("foo") 1462 @RealOptionalBinder.Default("foo") 1463 static class Dummy {} 1464 1465 @SuppressWarnings("unchecked") setOf(V... elements)1466 private <V> Set<V> setOf(V... elements) { 1467 return ImmutableSet.copyOf(elements); 1468 } 1469 1470 @SuppressWarnings("unchecked") toOptional(Object object)1471 private <T> Optional<T> toOptional(Object object) throws Exception { 1472 assertTrue( 1473 "not a java.util.Optional: " + object.getClass(), JAVA_OPTIONAL_CLASS.isInstance(object)); 1474 return Optional.fromNullable((T) JAVA_OPTIONAL_OR_ELSE.invoke(object, (Void) null)); 1475 } 1476 } 1477