Home | History | Annotate | Download | only in inject
      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