1 /* 2 * Copyright (C) 2010 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.common.collect.ImmutableSet.of; 20 import static com.google.inject.Asserts.assertContains; 21 import static com.google.inject.JitBindingsTest.GetBindingCheck.ALLOW_BINDING; 22 import static com.google.inject.JitBindingsTest.GetBindingCheck.FAIL_ALL; 23 24 import junit.framework.TestCase; 25 26 import java.util.Set; 27 28 /** 29 * Some tests for {@link Binder#requireExplicitBindings()} 30 * 31 * @author sberlin (at) gmail.com (Sam Berlin) 32 */ 33 public class JitBindingsTest extends TestCase { 34 35 private String jitFailed(Class<?> clazz) { 36 return jitFailed(TypeLiteral.get(clazz)); 37 } 38 39 private String jitFailed(TypeLiteral<?> clazz) { 40 return "Explicit bindings are required and " + clazz + " is not explicitly bound."; 41 } 42 43 private String jitInParentFailed(Class<?> clazz) { 44 return jitInParentFailed(TypeLiteral.get(clazz)); 45 } 46 47 private String jitInParentFailed(TypeLiteral<?> clazz) { 48 return "Explicit bindings are required and " + clazz + " would be bound in a parent injector."; 49 } 50 51 private String inChildMessage(Class<?> clazz) { 52 return "Unable to create binding for " 53 + clazz.getName() 54 + ". It was already configured on one or more child injectors or private modules"; 55 } 56 57 public void testLinkedBindingWorks() { 58 Injector injector = Guice.createInjector(new AbstractModule() { 59 @Override 60 protected void configure() { 61 binder().requireExplicitBindings(); 62 bind(Foo.class).to(FooImpl.class); 63 } 64 }); 65 // Foo was explicitly bound 66 ensureWorks(injector, Foo.class); 67 // FooImpl was implicitly bound, it is an error to call getInstance or getProvider, 68 // It is OK to call getBinding for introspection, but an error to get the provider 69 // of the binding 70 ensureFails(injector, ALLOW_BINDING, FooImpl.class); 71 } 72 73 public void testMoreBasicsWork() { 74 Injector injector = Guice.createInjector(new AbstractModule() { 75 @Override 76 protected void configure() { 77 binder().requireExplicitBindings(); 78 bind(Foo.class).to(FooImpl.class); 79 bind(Bar.class); 80 bind(FooBar.class); 81 } 82 }); 83 // Foo, Bar & FooBar was explicitly bound 84 ensureWorks(injector, FooBar.class, Bar.class, Foo.class); 85 // FooImpl was implicitly bound, it is an error to call getInstance or getProvider, 86 // It is OK to call getBinding for introspection, but an error to get the provider 87 // of the binding 88 ensureFails(injector, ALLOW_BINDING, FooImpl.class); 89 } 90 91 public void testLinkedEagerSingleton() { 92 Injector injector = Guice.createInjector(new AbstractModule() { 93 @Override 94 protected void configure() { 95 binder().requireExplicitBindings(); 96 bind(Foo.class).to(FooImpl.class).asEagerSingleton(); 97 } 98 }); 99 // Foo was explicitly bound 100 ensureWorks(injector, Foo.class); 101 // FooImpl was implicitly bound, it is an error to call getInstance or getProvider, 102 // It is OK to call getBinding for introspection, but an error to get the provider 103 // of the binding 104 ensureFails(injector, ALLOW_BINDING, FooImpl.class); 105 } 106 107 public void testBasicsWithEagerSingleton() { 108 Injector injector = Guice.createInjector(new AbstractModule() { 109 @Override 110 protected void configure() { 111 binder().requireExplicitBindings(); 112 bind(Foo.class).to(FooImpl.class).asEagerSingleton(); 113 bind(Bar.class); 114 bind(FooBar.class); 115 } 116 }); 117 // Foo, Bar & FooBar was explicitly bound 118 ensureWorks(injector, FooBar.class, Bar.class, Foo.class); 119 // FooImpl was implicitly bound, it is an error to call getInstance or getProvider, 120 // It is OK to call getBinding for introspection, but an error to get the provider 121 // of the binding 122 ensureFails(injector, ALLOW_BINDING, FooImpl.class); 123 } 124 125 public void testLinkedToScoped() { 126 Injector injector = Guice.createInjector(new AbstractModule() { 127 @Override 128 protected void configure() { 129 binder.requireExplicitBindings(); 130 bind(Foo.class).to(ScopedFooImpl.class); 131 } 132 }); 133 // Foo was explicitly bound 134 ensureWorks(injector, Foo.class); 135 // FooSingletonImpl was implicitly bound, it is an error to call getInstance or getProvider, 136 // It is OK to call getBinding for introspection, but an error to get the provider 137 // of the binding 138 ensureFails(injector, ALLOW_BINDING, ScopedFooImpl.class); 139 } 140 141 public void testBasicsWithScoped() { 142 Injector injector = Guice.createInjector(new AbstractModule() { 143 @Override 144 protected void configure() { 145 binder().requireExplicitBindings(); 146 bind(Foo.class).to(ScopedFooImpl.class); 147 bind(Bar.class); 148 bind(FooBar.class); 149 } 150 }); 151 // Foo, Bar & FooBar was explicitly bound 152 ensureWorks(injector, FooBar.class, Bar.class, Foo.class); 153 // FooSingletonImpl was implicitly bound, it is an error to call getInstance or getProvider, 154 // It is OK to call getBinding for introspection, but an error to get the provider 155 // of the binding 156 ensureFails(injector, ALLOW_BINDING, ScopedFooImpl.class); 157 } 158 159 public void testFailsIfInjectingScopedDirectlyWhenItIsntBound() { 160 try { 161 Guice.createInjector(new AbstractModule() { 162 @Override 163 protected void configure() { 164 binder().requireExplicitBindings(); 165 bind(Foo.class).to(ScopedFooImpl.class); 166 bind(WantsScopedFooImpl.class); 167 } 168 }); 169 fail(); 170 } catch(CreationException expected) { 171 assertContains(expected.getMessage(), jitFailed(ScopedFooImpl.class)); 172 assertEquals(1, expected.getErrorMessages().size()); 173 } 174 } 175 176 public void testLinkedProviderBindingWorks() { 177 Injector injector = Guice.createInjector(new AbstractModule() { 178 @Override 179 protected void configure() { 180 binder().requireExplicitBindings(); 181 bind(Foo.class).toProvider(FooProvider.class); 182 } 183 }); 184 // Foo was explicitly bound 185 ensureWorks(injector, Foo.class); 186 // FooImpl was not bound at all (even implicitly), it is an error 187 // to call getInstance, getProvider, or getBinding. 188 ensureFails(injector, FAIL_ALL, FooImpl.class); 189 } 190 191 public void testJitGetFails() { 192 try { 193 Guice.createInjector(new AbstractModule() { 194 @Override 195 protected void configure() { 196 binder().requireExplicitBindings(); 197 } 198 }).getInstance(Bar.class); 199 fail("should have failed"); 200 } catch(ConfigurationException expected) { 201 assertContains(expected.getMessage(), jitFailed(Bar.class)); 202 assertEquals(1, expected.getErrorMessages().size()); 203 } 204 } 205 206 public void testJitInjectionFails() { 207 try { 208 Guice.createInjector(new AbstractModule() { 209 @Override 210 protected void configure() { 211 binder().requireExplicitBindings(); 212 bind(Foo.class).to(FooImpl.class); 213 bind(FooBar.class); 214 } 215 }); 216 fail("should have failed"); 217 } catch (CreationException expected) { 218 assertContains(expected.getMessage(), jitFailed(Bar.class)); 219 assertEquals(1, expected.getErrorMessages().size()); 220 } 221 } 222 223 public void testJitProviderGetFails() { 224 try { 225 Guice.createInjector(new AbstractModule() { 226 @Override 227 protected void configure() { 228 binder().requireExplicitBindings(); 229 } 230 }).getProvider(Bar.class); 231 fail("should have failed"); 232 } catch (ConfigurationException expected) { 233 assertContains(expected.getMessage(), jitFailed(Bar.class)); 234 assertEquals(1, expected.getErrorMessages().size()); 235 } 236 } 237 238 public void testJitProviderInjectionFails() { 239 try { 240 Guice.createInjector(new AbstractModule() { 241 @Override 242 protected void configure() { 243 binder().requireExplicitBindings(); 244 bind(Foo.class).to(FooImpl.class); 245 bind(ProviderFooBar.class); 246 } 247 }); 248 fail("should have failed"); 249 } catch (CreationException expected) { 250 assertContains(expected.getMessage(), jitFailed(Bar.class)); 251 assertEquals(1, expected.getErrorMessages().size()); 252 } 253 } 254 255 public void testImplementedBy() { 256 Injector injector = Guice.createInjector(new AbstractModule() { 257 @Override 258 protected void configure() { 259 binder().requireExplicitBindings(); 260 bind(ImplBy.class); 261 } 262 }); 263 ensureWorks(injector, ImplBy.class); 264 ensureFails(injector, ALLOW_BINDING, ImplByImpl.class); 265 } 266 267 public void testImplementedBySomethingThatIsAnnotated() { 268 Injector injector = Guice.createInjector(new AbstractModule() { 269 @Override 270 protected void configure() { 271 binder().requireExplicitBindings(); 272 bind(ImplByScoped.class); 273 } 274 }); 275 ensureWorks(injector, ImplByScoped.class); 276 ensureFails(injector, ALLOW_BINDING, ImplByScopedImpl.class); 277 } 278 279 public void testProvidedBy() { 280 Injector injector = Guice.createInjector(new AbstractModule() { 281 @Override 282 protected void configure() { 283 binder().requireExplicitBindings(); 284 bind(ProvBy.class); 285 } 286 }); 287 ensureWorks(injector, ProvBy.class); 288 ensureFails(injector, ALLOW_BINDING, ProvByProvider.class); 289 } 290 291 public void testProviderMethods() { 292 Injector injector = Guice.createInjector(new AbstractModule() { 293 @Override protected void configure() { 294 binder().requireExplicitBindings(); 295 } 296 @SuppressWarnings("unused") @Provides Foo foo() { return new FooImpl(); } 297 }); 298 ensureWorks(injector, Foo.class); 299 } 300 301 public void testChildInjectorInheritsOption() { 302 Injector parent = Guice.createInjector(new AbstractModule() { 303 @Override 304 protected void configure() { 305 binder().requireExplicitBindings(); 306 bind(Bar.class); 307 } 308 }); 309 ensureWorks(parent, Bar.class); 310 ensureFails(parent, FAIL_ALL, FooImpl.class, FooBar.class, Foo.class); 311 312 try { 313 parent.createChildInjector(new AbstractModule() { 314 @Override 315 protected void configure() { 316 bind(FooBar.class); 317 } 318 }); 319 fail("should have failed"); 320 } catch(CreationException expected) { 321 assertContains(expected.getMessage(), jitFailed(Foo.class)); 322 assertEquals(1, expected.getErrorMessages().size()); 323 } 324 325 Injector child = parent.createChildInjector(new AbstractModule() { 326 @Override 327 protected void configure() { 328 bind(Foo.class).to(FooImpl.class); 329 } 330 }); 331 ensureWorks(child, Foo.class, Bar.class); 332 ensureFails(child, ALLOW_BINDING, FooImpl.class); 333 ensureInChild(parent, FooImpl.class, Foo.class); 334 // TODO(sameb): FooBar may or may not be in a child injector, depending on if GC has run. 335 // We should fix failed child injectors to remove their contents from the parent blacklist 336 // immediately, rather than waiting on GC to do it. 337 // FooBar was succesfully inserted into the child injector (and parent blacklist), but then 338 // JIT bindings it depended on failed, making the child injector invalid. 339 340 Injector grandchild = child.createChildInjector(new AbstractModule() { 341 @Override 342 protected void configure() { 343 bind(FooBar.class); 344 } 345 }); 346 ensureWorks(grandchild, FooBar.class, Foo.class, Bar.class); 347 ensureFails(grandchild, ALLOW_BINDING, FooImpl.class); 348 ensureFails(child, ALLOW_BINDING, FooImpl.class); 349 ensureInChild(parent, FooImpl.class, FooBar.class, Foo.class); 350 } 351 352 public void testChildInjectorAddsOption() { 353 Injector parent = Guice.createInjector(new AbstractModule() { 354 @Override 355 protected void configure() { 356 bind(Bar.class); 357 } 358 }); 359 int totalParentBindings = parent.getAllBindings().size(); 360 361 try { 362 parent.createChildInjector(new AbstractModule() { 363 @Override 364 protected void configure() { 365 binder().requireExplicitBindings(); 366 bind(FooBar.class); 367 } 368 }); 369 fail("should have failed"); 370 } catch(CreationException expected) { 371 assertContains(expected.getMessage(), jitFailed(Foo.class)); 372 assertEquals(1, expected.getErrorMessages().size()); 373 } 374 assertEquals(totalParentBindings, parent.getAllBindings().size()); 375 376 Injector child = parent.createChildInjector(new AbstractModule() { 377 @Override 378 protected void configure() { 379 binder().requireExplicitBindings(); 380 bind(Foo.class).to(FooImpl.class); 381 bind(FooImpl.class); 382 } 383 }); 384 assertEquals(totalParentBindings, parent.getAllBindings().size()); 385 ensureWorks(child, Foo.class, Bar.class); 386 387 Injector grandchild = child.createChildInjector(new AbstractModule() { 388 @Override 389 protected void configure() { 390 bind(FooBar.class); 391 } 392 }); 393 assertEquals(totalParentBindings, parent.getAllBindings().size()); 394 ensureWorks(grandchild, FooBar.class, Foo.class, Bar.class); 395 396 // Make sure siblings of children don't inherit each others settings... 397 // a new child should be able to get FooImpl. 398 child = parent.createChildInjector(); 399 ensureWorks(child, FooImpl.class); 400 } 401 402 public void testPrivateModulesInheritOptions() { 403 try { 404 Guice.createInjector(new AbstractModule() { 405 protected void configure() { 406 binder().requireExplicitBindings(); 407 bind(Foo.class).to(FooImpl.class); 408 409 install(new PrivateModule() { 410 public void configure() { 411 bind(FooBar.class); 412 expose(FooBar.class); 413 } 414 }); 415 } 416 }); 417 fail("should have failed"); 418 } catch(CreationException expected) { 419 assertContains(expected.getMessage(), jitFailed(Bar.class)); 420 assertEquals(1, expected.getErrorMessages().size()); 421 } 422 423 Injector injector = Guice.createInjector(new AbstractModule() { 424 protected void configure() { 425 binder().requireExplicitBindings(); 426 427 install(new PrivateModule() { 428 public void configure() { 429 bind(Foo.class).to(FooImpl.class); 430 expose(Foo.class); 431 } 432 }); 433 } 434 }); 435 ensureInChild(injector, FooImpl.class); 436 } 437 438 public void testPrivateModuleAddsOption() { 439 try { 440 Guice.createInjector(new AbstractModule() { 441 protected void configure() { 442 bind(Foo.class).to(FooImpl.class); 443 444 // Fails because FooBar is in the private module, 445 // and it wants Bar, but Bar would be JIT. 446 install(new PrivateModule() { 447 public void configure() { 448 binder().requireExplicitBindings(); 449 bind(FooBar.class); 450 expose(FooBar.class); 451 } 452 }); 453 } 454 }); 455 fail("should have failed"); 456 } catch(CreationException expected) { 457 assertContains(expected.getMessage(), jitFailed(Bar.class)); 458 assertEquals(1, expected.getErrorMessages().size()); 459 } 460 } 461 462 public void testPrivateModuleSiblingsDontShareOption() { 463 Guice.createInjector(new AbstractModule() { 464 protected void configure() { 465 bind(Foo.class).to(FooImpl.class); 466 467 install(new PrivateModule() { 468 public void configure() { 469 binder().requireExplicitBindings(); 470 } 471 }); 472 473 // This works, even though Bar is JIT, 474 // because the requireExplicitBindings isn't shared 475 // between sibling private modules. 476 install(new PrivateModule() { 477 public void configure() { 478 bind(FooBar.class); 479 expose(FooBar.class); 480 } 481 }); 482 } 483 }); 484 } 485 486 public void testTypeLiteralsCanBeInjected() { 487 Injector injector = Guice.createInjector(new AbstractModule() { 488 @Override protected void configure() { 489 binder().requireExplicitBindings(); 490 bind(new TypeLiteral<WantsTypeLiterals<String>>() {}); 491 bind(new TypeLiteral<Set<String>>() {}).toInstance(of("bar")); 492 } 493 }); 494 495 WantsTypeLiterals<String> foo = injector.getInstance(new Key<WantsTypeLiterals<String>>() {}); 496 assertEquals(foo.literal.getRawType(), String.class); 497 assertEquals(of("bar"), foo.set); 498 } 499 500 public void testMembersInjectorsCanBeInjected() { 501 Injector injector = Guice.createInjector(new AbstractModule() { 502 @Override protected void configure() { 503 binder().requireExplicitBindings(); 504 } 505 506 @Provides String data(MembersInjector<String> mi) { 507 String data = "foo"; 508 mi.injectMembers(data); 509 return data; 510 } 511 }); 512 513 String data = injector.getInstance(String.class); 514 assertEquals("foo", data); 515 } 516 517 public void testJitLinkedBindingInParentFails() { 518 try { 519 Guice.createInjector(new AbstractModule() { 520 @Override 521 protected void configure() { 522 install(new PrivateModule() { 523 @Override 524 protected void configure() { 525 binder().requireExplicitBindings(); 526 bind(Foo.class).to(FooImpl.class); 527 } 528 }); 529 } 530 }); 531 fail("should have failed"); 532 } catch (CreationException expected) { 533 assertContains(expected.getMessage(), jitInParentFailed(FooImpl.class)); 534 assertEquals(1, expected.getErrorMessages().size()); 535 } 536 } 537 538 public void testJitProviderBindingInParentFails() { 539 try { 540 Guice.createInjector(new AbstractModule() { 541 @Override 542 protected void configure() { 543 install(new PrivateModule() { 544 @Override 545 protected void configure() { 546 binder().requireExplicitBindings(); 547 bind(Foo.class).toProvider(FooProvider.class); 548 } 549 }); 550 } 551 }); 552 fail("should have failed"); 553 } catch (CreationException expected) { 554 assertContains(expected.getMessage(), jitInParentFailed(FooProvider.class)); 555 assertEquals(1, expected.getErrorMessages().size()); 556 } 557 } 558 559 public void testJitImplementedByBindingInParentFails() { 560 try { 561 Guice.createInjector(new AbstractModule() { 562 @Override 563 protected void configure() { 564 install(new PrivateModule() { 565 @Override 566 protected void configure() { 567 binder().requireExplicitBindings(); 568 bind(ImplBy.class); 569 } 570 }); 571 } 572 }); 573 fail("should have failed"); 574 } catch (CreationException expected) { 575 assertContains(expected.getMessage(), jitInParentFailed(ImplByImpl.class)); 576 assertEquals(1, expected.getErrorMessages().size()); 577 } 578 } 579 580 public void testJitProvidedByBindingInParentFails() { 581 try { 582 Guice.createInjector(new AbstractModule() { 583 @Override 584 protected void configure() { 585 install(new PrivateModule() { 586 @Override 587 protected void configure() { 588 binder().requireExplicitBindings(); 589 bind(ProvBy.class); 590 } 591 }); 592 } 593 }); 594 fail("should have failed"); 595 } catch (CreationException expected) { 596 assertContains(expected.getMessage(), jitInParentFailed(ProvByProvider.class)); 597 assertEquals(1, expected.getErrorMessages().size()); 598 } 599 } 600 601 private void ensureWorks(Injector injector, Class<?>... classes) { 602 for(int i = 0; i < classes.length; i++) { 603 injector.getInstance(classes[i]); 604 injector.getProvider(classes[i]).get(); 605 injector.getBinding(classes[i]).getProvider().get(); 606 } 607 } 608 609 enum GetBindingCheck { FAIL_ALL, ALLOW_BINDING, ALLOW_BINDING_PROVIDER } 610 private void ensureFails(Injector injector, GetBindingCheck getBinding, Class<?>... classes) { 611 for(int i = 0; i < classes.length; i++) { 612 try { 613 injector.getInstance(classes[i]); 614 fail("should have failed tring to retrieve class: " + classes[i]); 615 } catch(ConfigurationException expected) { 616 assertContains(expected.getMessage(), jitFailed(classes[i])); 617 assertEquals(1, expected.getErrorMessages().size()); 618 } 619 620 try { 621 injector.getProvider(classes[i]); 622 fail("should have failed tring to retrieve class: " + classes[i]); 623 } catch(ConfigurationException expected) { 624 assertContains(expected.getMessage(), jitFailed(classes[i])); 625 assertEquals(1, expected.getErrorMessages().size()); 626 } 627 628 if (getBinding == GetBindingCheck.ALLOW_BINDING 629 || getBinding == GetBindingCheck.ALLOW_BINDING_PROVIDER) { 630 Binding<?> binding = injector.getBinding(classes[i]); 631 try { 632 binding.getProvider(); 633 if (getBinding != GetBindingCheck.ALLOW_BINDING_PROVIDER) { 634 fail("should have failed trying to retrieve class: " + classes[i]); 635 } 636 } catch(ConfigurationException expected) { 637 if (getBinding == GetBindingCheck.ALLOW_BINDING_PROVIDER) { 638 throw expected; 639 } 640 assertContains(expected.getMessage(), jitFailed(classes[i])); 641 assertEquals(1, expected.getErrorMessages().size()); 642 } 643 } else { 644 try { 645 injector.getBinding(classes[i]); 646 fail("should have failed tring to retrieve class: " + classes[i]); 647 } catch(ConfigurationException expected) { 648 assertContains(expected.getMessage(), jitFailed(classes[i])); 649 assertEquals(1, expected.getErrorMessages().size()); 650 } 651 } 652 } 653 } 654 655 private void ensureInChild(Injector injector, Class<?>... classes) { 656 for(int i = 0; i < classes.length; i++) { 657 try { 658 injector.getInstance(classes[i]); 659 fail("should have failed tring to retrieve class: " + classes[i]); 660 } catch(ConfigurationException expected) { 661 assertContains(expected.getMessage(), inChildMessage(classes[i])); 662 assertEquals(1, expected.getErrorMessages().size()); 663 } 664 665 try { 666 injector.getProvider(classes[i]); 667 fail("should have failed tring to retrieve class: " + classes[i]); 668 } catch(ConfigurationException expected) { 669 assertContains(expected.getMessage(), inChildMessage(classes[i])); 670 assertEquals(1, expected.getErrorMessages().size()); 671 } 672 673 try { 674 injector.getBinding(classes[i]); 675 fail("should have failed tring to retrieve class: " + classes[i]); 676 } catch(ConfigurationException expected) { 677 assertContains(expected.getMessage(), inChildMessage(classes[i])); 678 assertEquals(1, expected.getErrorMessages().size()); 679 } 680 } 681 } 682 683 private static interface Foo {} 684 private static class FooImpl implements Foo {} 685 @Singleton private static class ScopedFooImpl implements Foo {} 686 private static class WantsScopedFooImpl { 687 @SuppressWarnings("unused") @Inject ScopedFooImpl scopedFoo; 688 } 689 private static class Bar {} 690 private static class FooBar { 691 @SuppressWarnings("unused") @Inject Foo foo; 692 @SuppressWarnings("unused") @Inject Bar bar; 693 } 694 private static class ProviderFooBar { 695 @SuppressWarnings("unused") @Inject Provider<Foo> foo; 696 @SuppressWarnings("unused") @Inject Provider<Bar> bar; 697 } 698 private static class FooProvider implements Provider<Foo> { 699 public Foo get() { 700 return new FooImpl(); 701 } 702 } 703 704 @ImplementedBy(ImplByImpl.class) 705 private static interface ImplBy {} 706 private static class ImplByImpl implements ImplBy {} 707 708 @ImplementedBy(ImplByScopedImpl.class) 709 private static interface ImplByScoped {} 710 @Singleton 711 private static class ImplByScopedImpl implements ImplByScoped {} 712 713 @ProvidedBy(ProvByProvider.class) 714 private static interface ProvBy {} 715 private static class ProvByProvider implements Provider<ProvBy> { 716 public ProvBy get() { 717 return new ProvBy() {}; 718 } 719 } 720 721 private static class WantsTypeLiterals<T> { 722 TypeLiteral<T> literal; 723 Set<T> set; 724 725 @Inject WantsTypeLiterals(TypeLiteral<T> literal, Set<T> set) { 726 this.literal = literal; 727 this.set = set; 728 729 } 730 } 731 } 732