• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /**
2   * Copyright (C) 2007 Google Inc.
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   * http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.inject;
18  
19  import static com.google.inject.Asserts.asModuleChain;
20  import static com.google.inject.Asserts.assertContains;
21  import static com.google.inject.Asserts.assertNotSerializable;
22  import static com.google.inject.Asserts.getDeclaringSourcePart;
23  import static com.google.inject.Asserts.isIncludeStackTraceOff;
24  
25  import com.google.common.collect.Iterables;
26  import com.google.common.collect.Lists;
27  import com.google.inject.name.Named;
28  import com.google.inject.name.Names;
29  import com.google.inject.spi.Message;
30  import com.google.inject.util.Providers;
31  
32  import junit.framework.TestCase;
33  
34  import java.io.IOException;
35  import java.util.Comparator;
36  import java.util.Date;
37  import java.util.List;
38  import java.util.concurrent.Callable;
39  import java.util.logging.Handler;
40  import java.util.logging.LogRecord;
41  import java.util.logging.Logger;
42  
43  /**
44   * @author crazybob@google.com (Bob Lee)
45   */
46  public class BinderTest extends TestCase {
47  
48    private final Logger loggerToWatch = Logger.getLogger(Guice.class.getName());
49  
50    private final List<LogRecord> logRecords = Lists.newArrayList();
51    private final Handler fakeHandler = new Handler() {
52      @Override
53      public void publish(LogRecord logRecord) {
54        logRecords.add(logRecord);
55      }
56      @Override
57      public void flush() {}
58      @Override
59      public void close() throws SecurityException {}
60    };
61  
62    Provider<Foo> fooProvider;
63  
setUp()64    @Override protected void setUp() throws Exception {
65      super.setUp();
66      loggerToWatch.addHandler(fakeHandler);
67    }
68  
tearDown()69    @Override protected void tearDown() throws Exception {
70      loggerToWatch.removeHandler(fakeHandler);
71      super.tearDown();
72    }
73  
testProviderFromBinder()74    public void testProviderFromBinder() {
75      Guice.createInjector(new Module() {
76        public void configure(Binder binder) {
77          fooProvider = binder.getProvider(Foo.class);
78  
79          try {
80            fooProvider.get();
81          } catch (IllegalStateException e) { /* expected */ }
82        }
83      });
84  
85      assertNotNull(fooProvider.get());
86    }
87  
88    static class Foo {}
89  
testMissingBindings()90    public void testMissingBindings() {
91      try {
92        Guice.createInjector(new AbstractModule() {
93          @Override
94          public void configure() {
95            getProvider(Runnable.class);
96            bind(Comparator.class);
97            requireBinding(Key.get(new TypeLiteral<Callable<String>>() {}));
98            bind(Date.class).annotatedWith(Names.named("date"));
99          }
100        });
101      } catch (CreationException e) {
102        assertEquals(4, e.getErrorMessages().size());
103        String segment1 = "No implementation for " + Comparator.class.getName() + " was bound.";
104        String segment2 = "No implementation for java.util.Date annotated with @"
105            + Named.class.getName() + "(value=date) was bound.";
106        String segment3 = "No implementation for java.lang.Runnable was bound.";
107        String segment4 = " No implementation for java.util.concurrent.Callable<java.lang.String> was"
108            + " bound.";
109        String atSegment = "at " + getClass().getName();
110        String sourceFileName = getDeclaringSourcePart(getClass());
111        if (isIncludeStackTraceOff()) {
112          assertContains(e.getMessage(),
113              segment1, atSegment, sourceFileName,
114              segment2, atSegment, sourceFileName,
115              segment3, atSegment, sourceFileName,
116              segment4, atSegment, sourceFileName);
117        } else {
118          assertContains(e.getMessage(),
119              segment3, atSegment, sourceFileName,
120              segment1, atSegment, sourceFileName,
121              segment4, atSegment, sourceFileName,
122              segment2, atSegment, sourceFileName);
123        }
124      }
125    }
126  
testMissingDependency()127    public void testMissingDependency() {
128      try {
129        Guice.createInjector(new AbstractModule() {
130          @Override
131          public void configure() {
132            bind(NeedsRunnable.class);
133          }
134        });
135      } catch (CreationException e) {
136        assertEquals(1, e.getErrorMessages().size());
137        assertContains(e.getMessage(),
138            "No implementation for java.lang.Runnable was bound.",
139            "for field at " + NeedsRunnable.class.getName(), ".runnable(BinderTest.java:",
140            "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
141      }
142    }
143  
144    static class NeedsRunnable {
145      @Inject Runnable runnable;
146    }
147  
testDanglingConstantBinding()148    public void testDanglingConstantBinding() {
149      try {
150        Guice.createInjector(new AbstractModule() {
151          @Override public void configure() {
152            bindConstant();
153          }
154        });
155        fail();
156      } catch (CreationException expected) {
157        assertContains(expected.getMessage(),
158            "1) Missing constant value. Please call to(...).",
159            "at " + getClass().getName());
160      }
161    }
162  
testRecursiveBinding()163    public void testRecursiveBinding() {
164      try {
165        Guice.createInjector(new AbstractModule() {
166          @Override public void configure() {
167            bind(Runnable.class).to(Runnable.class);
168          }
169        });
170        fail();
171      } catch (CreationException expected) {
172        assertContains(expected.getMessage(),
173            "1) Binding points to itself.",
174            "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
175      }
176    }
177  
testBindingNullConstant()178    public void testBindingNullConstant() {
179      try {
180        Guice.createInjector(new AbstractModule() {
181          @Override public void configure() {
182            String none = null;
183            bindConstant().annotatedWith(Names.named("nullOne")).to(none);
184            bind(String.class).annotatedWith(Names.named("nullTwo")).toInstance(none);
185          }
186        });
187        fail();
188      } catch (CreationException expected) {
189        assertContains(expected.getMessage(),
190            "1) Binding to null instances is not allowed. Use toProvider(Providers.of(null))",
191            "2) Binding to null instances is not allowed. Use toProvider(Providers.of(null))");
192      }
193    }
194  
testToStringOnBinderApi()195    public void testToStringOnBinderApi() {
196      try {
197        Guice.createInjector(new AbstractModule() {
198          @Override public void configure() {
199            assertEquals("Binder", binder().toString());
200            assertEquals("Provider<java.lang.Integer>", getProvider(Integer.class).toString());
201            assertEquals("Provider<java.util.List<java.lang.String>>",
202                getProvider(Key.get(new TypeLiteral<List<String>>() {})).toString());
203  
204            assertEquals("BindingBuilder<java.lang.Integer>",
205                bind(Integer.class).toString());
206            assertEquals("BindingBuilder<java.lang.Integer>",
207                bind(Integer.class).annotatedWith(Names.named("a")).toString());
208            assertEquals("ConstantBindingBuilder", bindConstant().toString());
209            assertEquals("ConstantBindingBuilder",
210                bindConstant().annotatedWith(Names.named("b")).toString());
211            assertEquals("AnnotatedElementBuilder",
212                binder().newPrivateBinder().expose(Integer.class).toString());
213          }
214        });
215        fail();
216      } catch (CreationException ignored) {
217      }
218    }
219  
testNothingIsSerializableInBinderApi()220    public void testNothingIsSerializableInBinderApi() {
221      try {
222        Guice.createInjector(new AbstractModule() {
223          @Override public void configure() {
224            try {
225              assertNotSerializable(binder());
226              assertNotSerializable(getProvider(Integer.class));
227              assertNotSerializable(getProvider(Key.get(new TypeLiteral<List<String>>() {})));
228              assertNotSerializable(bind(Integer.class));
229              assertNotSerializable(bind(Integer.class).annotatedWith(Names.named("a")));
230              assertNotSerializable(bindConstant());
231              assertNotSerializable(bindConstant().annotatedWith(Names.named("b")));
232            } catch (IOException e) {
233              fail(e.getMessage());
234            }
235          }
236        });
237        fail();
238      } catch (CreationException ignored) {
239      }
240    }
241  
242    /**
243     * Although {@code String[].class} isn't equal to {@code new
244     * GenericArrayTypeImpl(String.class)}, Guice should treat these two types
245     * interchangeably.
246     */
testArrayTypeCanonicalization()247    public void testArrayTypeCanonicalization() {
248      final String[] strings = new String[] { "A" };
249      final Integer[] integers = new Integer[] { 1 };
250  
251      Injector injector = Guice.createInjector(new AbstractModule() {
252        @Override
253        protected void configure() {
254          bind(String[].class).toInstance(strings);
255          bind(new TypeLiteral<Integer[]>() {}).toInstance(integers);
256        }
257      });
258  
259      assertSame(integers, injector.getInstance(Key.get(new TypeLiteral<Integer[]>() {})));
260      assertSame(integers, injector.getInstance(new Key<Integer[]>() {}));
261      assertSame(integers, injector.getInstance(Integer[].class));
262      assertSame(strings, injector.getInstance(Key.get(new TypeLiteral<String[]>() {})));
263      assertSame(strings, injector.getInstance(new Key<String[]>() {}));
264      assertSame(strings, injector.getInstance(String[].class));
265  
266      try {
267        Guice.createInjector(new AbstractModule() {
268          @Override
269          protected void configure() {
270            bind(String[].class).toInstance(new String[] { "A" });
271            bind(new TypeLiteral<String[]>() {}).toInstance(new String[] { "B" });
272          }
273        });
274        fail();
275      } catch (CreationException expected) {
276        assertContains(expected.getMessage(),
277            "1) A binding to java.lang.String[] was already configured at " + getClass().getName(),
278            "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
279        assertContains(expected.getMessage(), "1 error");
280      }
281  
282      // passes because duplicates are ignored
283      injector = Guice.createInjector(new AbstractModule() {
284        @Override
285        protected void configure() {
286          bind(String[].class).toInstance(strings);
287          bind(new TypeLiteral<String[]>() {}).toInstance(strings);
288        }
289      });
290      assertSame(strings, injector.getInstance(Key.get(new TypeLiteral<String[]>() {})));
291      assertSame(strings, injector.getInstance(new Key<String[]>() {}));
292      assertSame(strings, injector.getInstance(String[].class));
293    }
294  
295    static class ParentModule extends AbstractModule {
configure()296      @Override protected void configure() {
297        install(new FooModule());
298        install(new BarModule());
299      }
300    }
301    static class FooModule extends AbstractModule {
configure()302      @Override protected void configure() {
303        install(new ConstantModule("foo"));
304      }
305    }
306    static class BarModule extends AbstractModule {
configure()307      @Override protected void configure() {
308        install(new ConstantModule("bar"));
309      }
310    }
311    static class ConstantModule extends AbstractModule {
312      private final String constant;
ConstantModule(String constant)313      ConstantModule(String constant) {
314        this.constant = constant;
315      }
configure()316      @Override protected void configure() {
317        bind(String.class).toInstance(constant);
318      }
319    }
320  
321    /**
322     * Binding something to two different things should give an error.
323     */
testSettingBindingTwice()324    public void testSettingBindingTwice() {
325      try {
326        Guice.createInjector(new ParentModule());
327        fail();
328      } catch(CreationException expected) {
329        assertContains(expected.getMessage(),
330          "1) A binding to java.lang.String was already configured at " + ConstantModule.class.getName(),
331          asModuleChain(ParentModule.class, FooModule.class, ConstantModule.class),
332          "at " + ConstantModule.class.getName(), getDeclaringSourcePart(getClass()),
333          asModuleChain(ParentModule.class, BarModule.class, ConstantModule.class));
334        assertContains(expected.getMessage(), "1 error");
335      }
336    }
337  
338    /**
339     * Binding an @ImplementedBy thing to something else should also fail.
340     */
testSettingAtImplementedByTwice()341    public void testSettingAtImplementedByTwice() {
342      try {
343        Guice.createInjector(new AbstractModule() {
344          @Override
345          protected void configure() {
346            bind(HasImplementedBy1.class);
347            bind(HasImplementedBy1.class).toInstance(new HasImplementedBy1() {});
348          }
349        });
350        fail();
351      } catch(CreationException expected) {
352        expected.printStackTrace();
353        assertContains(expected.getMessage(),
354          "1) A binding to " + HasImplementedBy1.class.getName()
355          + " was already configured at " + getClass().getName(),
356          "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
357        assertContains(expected.getMessage(), "1 error");
358      }
359    }
360  
361    /**
362     * See issue 614, Problem One
363     * https://github.com/google/guice/issues/614
364     */
testJitDependencyDoesntBlockOtherExplicitBindings()365    public void testJitDependencyDoesntBlockOtherExplicitBindings() {
366      Injector injector = Guice.createInjector(new AbstractModule() {
367        @Override
368        protected void configure() {
369          bind(HasImplementedByThatNeedsAnotherImplementedBy.class);
370          bind(HasImplementedBy1.class).toInstance(new HasImplementedBy1() {});
371        }
372      });
373      injector.getAllBindings(); // just validate it doesn't throw.
374      // Also validate that we're using the explicit (and not @ImplementedBy) implementation
375      assertFalse(injector.getInstance(HasImplementedBy1.class) instanceof ImplementsHasImplementedBy1);
376    }
377  
378    /**
379     * See issue 614, Problem Two
380     * https://github.com/google/guice/issues/id=614
381     */
testJitDependencyCanUseExplicitDependencies()382    public void testJitDependencyCanUseExplicitDependencies() {
383      Guice.createInjector(new AbstractModule() {
384        @Override
385        protected void configure() {
386          bind(HasImplementedByThatWantsExplicit.class);
387          bind(JustAnInterface.class).toInstance(new JustAnInterface() {});
388        }
389      });
390    }
391  
392    /**
393     * Untargetted bindings should follow @ImplementedBy and @ProvidedBy
394     * annotations if they exist. Otherwise the class should be constructed
395     * directly.
396     */
testUntargettedBinding()397    public void testUntargettedBinding() {
398      Injector injector = Guice.createInjector(new AbstractModule() {
399        @Override
400        protected void configure() {
401          bind(HasProvidedBy1.class);
402          bind(HasImplementedBy1.class);
403          bind(HasProvidedBy2.class);
404          bind(HasImplementedBy2.class);
405          bind(JustAClass.class);
406        }
407      });
408  
409      assertNotNull(injector.getInstance(HasProvidedBy1.class));
410      assertNotNull(injector.getInstance(HasImplementedBy1.class));
411      assertNotSame(HasProvidedBy2.class,
412          injector.getInstance(HasProvidedBy2.class).getClass());
413      assertSame(ExtendsHasImplementedBy2.class,
414          injector.getInstance(HasImplementedBy2.class).getClass());
415      assertSame(JustAClass.class, injector.getInstance(JustAClass.class).getClass());
416    }
417  
testPartialInjectorGetInstance()418    public void testPartialInjectorGetInstance() {
419      Injector injector = Guice.createInjector();
420      try {
421        injector.getInstance(MissingParameter.class);
422        fail();
423      } catch (ConfigurationException expected) {
424        assertContains(expected.getMessage(),
425            "1) Could not find a suitable constructor in " + NoInjectConstructor.class.getName(),
426            "at " + MissingParameter.class.getName() + ".<init>(BinderTest.java:");
427      }
428    }
429  
testUserReportedError()430    public void testUserReportedError() {
431      final Message message = new Message(getClass(), "Whoops!");
432      try {
433        Guice.createInjector(new AbstractModule() {
434          @Override
435          protected void configure() {
436            addError(message);
437          }
438        });
439        fail();
440      } catch (CreationException expected) {
441        assertSame(message, Iterables.getOnlyElement(expected.getErrorMessages()));
442      }
443    }
444  
testUserReportedErrorsAreAlsoLogged()445    public void testUserReportedErrorsAreAlsoLogged() {
446      try {
447        Guice.createInjector(new AbstractModule() {
448          @Override
449          protected void configure() {
450            addError(new Message("Whoops!", new IllegalArgumentException()));
451          }
452        });
453        fail();
454      } catch (CreationException expected) {
455      }
456  
457      LogRecord logRecord = Iterables.getOnlyElement(this.logRecords);
458      assertContains(logRecord.getMessage(),
459          "An exception was caught and reported. Message: java.lang.IllegalArgumentException");
460    }
461  
testBindingToProvider()462    public void testBindingToProvider() {
463      try {
464        Guice.createInjector(new AbstractModule() {
465          @Override
466          protected void configure() {
467            bind(new TypeLiteral<Provider<String>>() {}).toInstance(Providers.of("A"));
468          }
469        });
470        fail();
471      } catch (CreationException expected) {
472        assertContains(expected.getMessage(),
473            "1) Binding to Provider is not allowed.",
474            "at " + BinderTest.class.getName(), getDeclaringSourcePart(getClass()));
475      }
476    }
477  
478    static class OuterCoreModule extends AbstractModule {
configure()479      @Override protected void configure() {
480        install(new InnerCoreModule());
481      }
482    }
483    static class InnerCoreModule extends AbstractModule {
484      final Named red = Names.named("red");
485  
configure()486      @Override protected void configure() {
487        bind(AbstractModule.class).annotatedWith(red)
488        .toProvider(Providers.<AbstractModule>of(null));
489        bind(Binder.class).annotatedWith(red).toProvider(Providers.<Binder>of(null));
490        bind(Binding.class).annotatedWith(red).toProvider(Providers.<Binding>of(null));
491        bind(Injector.class).annotatedWith(red).toProvider(Providers.<Injector>of(null));
492        bind(Key.class).annotatedWith(red).toProvider(Providers.<Key>of(null));
493        bind(Module.class).annotatedWith(red).toProvider(Providers.<Module>of(null));
494        bind(Provider.class).annotatedWith(red).toProvider(Providers.<Provider>of(null));
495        bind(Scope.class).annotatedWith(red).toProvider(Providers.<Scope>of(null));
496        bind(Stage.class).annotatedWith(red).toProvider(Providers.<Stage>of(null));
497        bind(TypeLiteral.class).annotatedWith(red).toProvider(Providers.<TypeLiteral>of(null));
498        bind(new TypeLiteral<Key<String>>() {}).toProvider(Providers.<Key<String>>of(null));
499      }
500    }
testCannotBindToGuiceTypes()501    public void testCannotBindToGuiceTypes() {
502      try {
503        Guice.createInjector(new OuterCoreModule());
504        fail();
505      } catch (CreationException expected) {
506        assertContains(expected.getMessage(),
507            "Binding to core guice framework type is not allowed: AbstractModule.",
508            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
509            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
510  
511            "Binding to core guice framework type is not allowed: Binder.",
512            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
513            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
514  
515            "Binding to core guice framework type is not allowed: Binding.",
516            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
517            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
518  
519            "Binding to core guice framework type is not allowed: Injector.",
520            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
521            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
522  
523            "Binding to core guice framework type is not allowed: Key.",
524            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
525            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
526  
527            "Binding to core guice framework type is not allowed: Module.",
528            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
529            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
530  
531            "Binding to Provider is not allowed.",
532            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
533            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
534  
535            "Binding to core guice framework type is not allowed: Scope.",
536            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
537            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
538  
539            "Binding to core guice framework type is not allowed: Stage.",
540            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
541            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
542  
543            "Binding to core guice framework type is not allowed: TypeLiteral.",
544            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
545            asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
546  
547            "Binding to core guice framework type is not allowed: Key.",
548            "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
549            asModuleChain(OuterCoreModule.class, InnerCoreModule.class));
550      }
551    }
552  
553    static class MissingParameter {
MissingParameter(NoInjectConstructor noInjectConstructor)554      @Inject MissingParameter(NoInjectConstructor noInjectConstructor) {}
555    }
556  
557    static class NoInjectConstructor {
NoInjectConstructor()558      private NoInjectConstructor() {}
559    }
560  
561    @ProvidedBy(HasProvidedBy1Provider.class)
562    interface HasProvidedBy1 {}
563  
564    static class HasProvidedBy1Provider implements Provider<HasProvidedBy1> {
get()565      public HasProvidedBy1 get() {
566        return new HasProvidedBy1() {};
567      }
568    }
569  
570    @ImplementedBy(ImplementsHasImplementedBy1.class)
571    interface HasImplementedBy1 {}
572  
573    static class ImplementsHasImplementedBy1 implements HasImplementedBy1 {}
574  
575    @ProvidedBy(HasProvidedBy2Provider.class)
576    static class HasProvidedBy2 {}
577  
578    static class HasProvidedBy2Provider implements Provider<HasProvidedBy2> {
get()579      public HasProvidedBy2 get() {
580        return new HasProvidedBy2() {};
581      }
582    }
583  
584    @ImplementedBy(ExtendsHasImplementedBy2.class)
585    static class HasImplementedBy2 {}
586  
587    static class ExtendsHasImplementedBy2 extends HasImplementedBy2 {}
588  
589    static class JustAClass {}
590  
591    @ImplementedBy(ImplementsHasImplementedByThatNeedsAnotherImplementedBy.class)
592    static interface HasImplementedByThatNeedsAnotherImplementedBy {
593    }
594  
595    static class ImplementsHasImplementedByThatNeedsAnotherImplementedBy
596      implements HasImplementedByThatNeedsAnotherImplementedBy {
597      @Inject
ImplementsHasImplementedByThatNeedsAnotherImplementedBy( HasImplementedBy1 h1n1)598      ImplementsHasImplementedByThatNeedsAnotherImplementedBy(
599          HasImplementedBy1 h1n1) {}
600    }
601  
602    @ImplementedBy(ImplementsHasImplementedByThatWantsExplicit.class)
603    static interface HasImplementedByThatWantsExplicit {
604    }
605  
606    static class ImplementsHasImplementedByThatWantsExplicit
607        implements HasImplementedByThatWantsExplicit {
ImplementsHasImplementedByThatWantsExplicit(JustAnInterface jai)608      @Inject ImplementsHasImplementedByThatWantsExplicit(JustAnInterface jai) {}
609    }
610  
611    static interface JustAnInterface {}
612  
613  
614  //  public void testBindInterfaceWithoutImplementation() {
615  //    Guice.createInjector(new AbstractModule() {
616  //      protected void configure() {
617  //        bind(Runnable.class);
618  //      }
619  //    }).getInstance(Runnable.class);
620  //  }
621  
622    enum Roshambo { ROCK, SCISSORS, PAPER }
623  
testInjectRawProvider()624    public void testInjectRawProvider() {
625      try {
626        Guice.createInjector().getInstance(Provider.class);
627        fail();
628      } catch (ConfigurationException expected) {
629        Asserts.assertContains(expected.getMessage(),
630            "1) Cannot inject a Provider that has no type parameter",
631            "while locating " + Provider.class.getName());
632      }
633    }
634  }
635