/core/test/com/google/inject/BinderTest.java
Java | 634 lines | 510 code | 73 blank | 51 comment | 2 complexity | 0e313dfbfa419f3dcbe8a3dd65f6d13b MD5 | raw file
- /**
- * Copyright (C) 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.google.inject;
- import static com.google.inject.Asserts.asModuleChain;
- import static com.google.inject.Asserts.assertContains;
- import static com.google.inject.Asserts.assertNotSerializable;
- import static com.google.inject.Asserts.getDeclaringSourcePart;
- import static com.google.inject.Asserts.isIncludeStackTraceOff;
- import com.google.common.collect.Iterables;
- import com.google.common.collect.Lists;
- import com.google.inject.name.Named;
- import com.google.inject.name.Names;
- import com.google.inject.spi.Message;
- import com.google.inject.util.Providers;
- import junit.framework.TestCase;
- import java.io.IOException;
- import java.util.Comparator;
- import java.util.Date;
- import java.util.List;
- import java.util.concurrent.Callable;
- import java.util.logging.Handler;
- import java.util.logging.LogRecord;
- import java.util.logging.Logger;
- /**
- * @author crazybob@google.com (Bob Lee)
- */
- public class BinderTest extends TestCase {
- private final Logger loggerToWatch = Logger.getLogger(Guice.class.getName());
- private final List<LogRecord> logRecords = Lists.newArrayList();
- private final Handler fakeHandler = new Handler() {
- @Override
- public void publish(LogRecord logRecord) {
- logRecords.add(logRecord);
- }
- @Override
- public void flush() {}
- @Override
- public void close() throws SecurityException {}
- };
- Provider<Foo> fooProvider;
- @Override protected void setUp() throws Exception {
- super.setUp();
- loggerToWatch.addHandler(fakeHandler);
- }
- @Override protected void tearDown() throws Exception {
- loggerToWatch.removeHandler(fakeHandler);
- super.tearDown();
- }
- public void testProviderFromBinder() {
- Guice.createInjector(new Module() {
- public void configure(Binder binder) {
- fooProvider = binder.getProvider(Foo.class);
- try {
- fooProvider.get();
- } catch (IllegalStateException e) { /* expected */ }
- }
- });
- assertNotNull(fooProvider.get());
- }
- static class Foo {}
- public void testMissingBindings() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- public void configure() {
- getProvider(Runnable.class);
- bind(Comparator.class);
- requireBinding(Key.get(new TypeLiteral<Callable<String>>() {}));
- bind(Date.class).annotatedWith(Names.named("date"));
- }
- });
- } catch (CreationException e) {
- assertEquals(4, e.getErrorMessages().size());
- String segment1 = "No implementation for " + Comparator.class.getName() + " was bound.";
- String segment2 = "No implementation for java.util.Date annotated with @"
- + Named.class.getName() + "(value=date) was bound.";
- String segment3 = "No implementation for java.lang.Runnable was bound.";
- String segment4 = " No implementation for java.util.concurrent.Callable<java.lang.String> was"
- + " bound.";
- String atSegment = "at " + getClass().getName();
- String sourceFileName = getDeclaringSourcePart(getClass());
- if (isIncludeStackTraceOff()) {
- assertContains(e.getMessage(),
- segment1, atSegment, sourceFileName,
- segment2, atSegment, sourceFileName,
- segment3, atSegment, sourceFileName,
- segment4, atSegment, sourceFileName);
- } else {
- assertContains(e.getMessage(),
- segment3, atSegment, sourceFileName,
- segment1, atSegment, sourceFileName,
- segment4, atSegment, sourceFileName,
- segment2, atSegment, sourceFileName);
- }
- }
- }
- public void testMissingDependency() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- public void configure() {
- bind(NeedsRunnable.class);
- }
- });
- } catch (CreationException e) {
- assertEquals(1, e.getErrorMessages().size());
- assertContains(e.getMessage(),
- "No implementation for java.lang.Runnable was bound.",
- "for field at " + NeedsRunnable.class.getName(), ".runnable(BinderTest.java:",
- "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
- }
- }
- static class NeedsRunnable {
- @Inject Runnable runnable;
- }
- public void testDanglingConstantBinding() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override public void configure() {
- bindConstant();
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "1) Missing constant value. Please call to(...).",
- "at " + getClass().getName());
- }
- }
- public void testRecursiveBinding() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override public void configure() {
- bind(Runnable.class).to(Runnable.class);
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "1) Binding points to itself.",
- "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
- }
- }
- public void testBindingNullConstant() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override public void configure() {
- String none = null;
- bindConstant().annotatedWith(Names.named("nullOne")).to(none);
- bind(String.class).annotatedWith(Names.named("nullTwo")).toInstance(none);
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "1) Binding to null instances is not allowed. Use toProvider(Providers.of(null))",
- "2) Binding to null instances is not allowed. Use toProvider(Providers.of(null))");
- }
- }
- public void testToStringOnBinderApi() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override public void configure() {
- assertEquals("Binder", binder().toString());
- assertEquals("Provider<java.lang.Integer>", getProvider(Integer.class).toString());
- assertEquals("Provider<java.util.List<java.lang.String>>",
- getProvider(Key.get(new TypeLiteral<List<String>>() {})).toString());
- assertEquals("BindingBuilder<java.lang.Integer>",
- bind(Integer.class).toString());
- assertEquals("BindingBuilder<java.lang.Integer>",
- bind(Integer.class).annotatedWith(Names.named("a")).toString());
- assertEquals("ConstantBindingBuilder", bindConstant().toString());
- assertEquals("ConstantBindingBuilder",
- bindConstant().annotatedWith(Names.named("b")).toString());
- assertEquals("AnnotatedElementBuilder",
- binder().newPrivateBinder().expose(Integer.class).toString());
- }
- });
- fail();
- } catch (CreationException ignored) {
- }
- }
- public void testNothingIsSerializableInBinderApi() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override public void configure() {
- try {
- assertNotSerializable(binder());
- assertNotSerializable(getProvider(Integer.class));
- assertNotSerializable(getProvider(Key.get(new TypeLiteral<List<String>>() {})));
- assertNotSerializable(bind(Integer.class));
- assertNotSerializable(bind(Integer.class).annotatedWith(Names.named("a")));
- assertNotSerializable(bindConstant());
- assertNotSerializable(bindConstant().annotatedWith(Names.named("b")));
- } catch (IOException e) {
- fail(e.getMessage());
- }
- }
- });
- fail();
- } catch (CreationException ignored) {
- }
- }
- /**
- * Although {@code String[].class} isn't equal to {@code new
- * GenericArrayTypeImpl(String.class)}, Guice should treat these two types
- * interchangeably.
- */
- public void testArrayTypeCanonicalization() {
- final String[] strings = new String[] { "A" };
- final Integer[] integers = new Integer[] { 1 };
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String[].class).toInstance(strings);
- bind(new TypeLiteral<Integer[]>() {}).toInstance(integers);
- }
- });
- assertSame(integers, injector.getInstance(Key.get(new TypeLiteral<Integer[]>() {})));
- assertSame(integers, injector.getInstance(new Key<Integer[]>() {}));
- assertSame(integers, injector.getInstance(Integer[].class));
- assertSame(strings, injector.getInstance(Key.get(new TypeLiteral<String[]>() {})));
- assertSame(strings, injector.getInstance(new Key<String[]>() {}));
- assertSame(strings, injector.getInstance(String[].class));
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String[].class).toInstance(new String[] { "A" });
- bind(new TypeLiteral<String[]>() {}).toInstance(new String[] { "B" });
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "1) A binding to java.lang.String[] was already configured at " + getClass().getName(),
- "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
- assertContains(expected.getMessage(), "1 error");
- }
- // passes because duplicates are ignored
- injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String[].class).toInstance(strings);
- bind(new TypeLiteral<String[]>() {}).toInstance(strings);
- }
- });
- assertSame(strings, injector.getInstance(Key.get(new TypeLiteral<String[]>() {})));
- assertSame(strings, injector.getInstance(new Key<String[]>() {}));
- assertSame(strings, injector.getInstance(String[].class));
- }
- static class ParentModule extends AbstractModule {
- @Override protected void configure() {
- install(new FooModule());
- install(new BarModule());
- }
- }
- static class FooModule extends AbstractModule {
- @Override protected void configure() {
- install(new ConstantModule("foo"));
- }
- }
- static class BarModule extends AbstractModule {
- @Override protected void configure() {
- install(new ConstantModule("bar"));
- }
- }
- static class ConstantModule extends AbstractModule {
- private final String constant;
- ConstantModule(String constant) {
- this.constant = constant;
- }
- @Override protected void configure() {
- bind(String.class).toInstance(constant);
- }
- }
- /**
- * Binding something to two different things should give an error.
- */
- public void testSettingBindingTwice() {
- try {
- Guice.createInjector(new ParentModule());
- fail();
- } catch(CreationException expected) {
- assertContains(expected.getMessage(),
- "1) A binding to java.lang.String was already configured at " + ConstantModule.class.getName(),
- asModuleChain(ParentModule.class, FooModule.class, ConstantModule.class),
- "at " + ConstantModule.class.getName(), getDeclaringSourcePart(getClass()),
- asModuleChain(ParentModule.class, BarModule.class, ConstantModule.class));
- assertContains(expected.getMessage(), "1 error");
- }
- }
- /**
- * Binding an @ImplementedBy thing to something else should also fail.
- */
- public void testSettingAtImplementedByTwice() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(HasImplementedBy1.class);
- bind(HasImplementedBy1.class).toInstance(new HasImplementedBy1() {});
- }
- });
- fail();
- } catch(CreationException expected) {
- expected.printStackTrace();
- assertContains(expected.getMessage(),
- "1) A binding to " + HasImplementedBy1.class.getName()
- + " was already configured at " + getClass().getName(),
- "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
- assertContains(expected.getMessage(), "1 error");
- }
- }
- /**
- * See issue 614, Problem One
- * https://github.com/google/guice/issues/614
- */
- public void testJitDependencyDoesntBlockOtherExplicitBindings() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(HasImplementedByThatNeedsAnotherImplementedBy.class);
- bind(HasImplementedBy1.class).toInstance(new HasImplementedBy1() {});
- }
- });
- injector.getAllBindings(); // just validate it doesn't throw.
- // Also validate that we're using the explicit (and not @ImplementedBy) implementation
- assertFalse(injector.getInstance(HasImplementedBy1.class) instanceof ImplementsHasImplementedBy1);
- }
- /**
- * See issue 614, Problem Two
- * https://github.com/google/guice/issues/id=614
- */
- public void testJitDependencyCanUseExplicitDependencies() {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(HasImplementedByThatWantsExplicit.class);
- bind(JustAnInterface.class).toInstance(new JustAnInterface() {});
- }
- });
- }
- /**
- * Untargetted bindings should follow @ImplementedBy and @ProvidedBy
- * annotations if they exist. Otherwise the class should be constructed
- * directly.
- */
- public void testUntargettedBinding() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(HasProvidedBy1.class);
- bind(HasImplementedBy1.class);
- bind(HasProvidedBy2.class);
- bind(HasImplementedBy2.class);
- bind(JustAClass.class);
- }
- });
- assertNotNull(injector.getInstance(HasProvidedBy1.class));
- assertNotNull(injector.getInstance(HasImplementedBy1.class));
- assertNotSame(HasProvidedBy2.class,
- injector.getInstance(HasProvidedBy2.class).getClass());
- assertSame(ExtendsHasImplementedBy2.class,
- injector.getInstance(HasImplementedBy2.class).getClass());
- assertSame(JustAClass.class, injector.getInstance(JustAClass.class).getClass());
- }
- public void testPartialInjectorGetInstance() {
- Injector injector = Guice.createInjector();
- try {
- injector.getInstance(MissingParameter.class);
- fail();
- } catch (ConfigurationException expected) {
- assertContains(expected.getMessage(),
- "1) Could not find a suitable constructor in " + NoInjectConstructor.class.getName(),
- "at " + MissingParameter.class.getName() + ".<init>(BinderTest.java:");
- }
- }
- public void testUserReportedError() {
- final Message message = new Message(getClass(), "Whoops!");
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- addError(message);
- }
- });
- fail();
- } catch (CreationException expected) {
- assertSame(message, Iterables.getOnlyElement(expected.getErrorMessages()));
- }
- }
- public void testUserReportedErrorsAreAlsoLogged() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- addError(new Message("Whoops!", new IllegalArgumentException()));
- }
- });
- fail();
- } catch (CreationException expected) {
- }
- LogRecord logRecord = Iterables.getOnlyElement(this.logRecords);
- assertContains(logRecord.getMessage(),
- "An exception was caught and reported. Message: java.lang.IllegalArgumentException");
- }
- public void testBindingToProvider() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(new TypeLiteral<Provider<String>>() {}).toInstance(Providers.of("A"));
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "1) Binding to Provider is not allowed.",
- "at " + BinderTest.class.getName(), getDeclaringSourcePart(getClass()));
- }
- }
- static class OuterCoreModule extends AbstractModule {
- @Override protected void configure() {
- install(new InnerCoreModule());
- }
- }
- static class InnerCoreModule extends AbstractModule {
- final Named red = Names.named("red");
- @Override protected void configure() {
- bind(AbstractModule.class).annotatedWith(red)
- .toProvider(Providers.<AbstractModule>of(null));
- bind(Binder.class).annotatedWith(red).toProvider(Providers.<Binder>of(null));
- bind(Binding.class).annotatedWith(red).toProvider(Providers.<Binding>of(null));
- bind(Injector.class).annotatedWith(red).toProvider(Providers.<Injector>of(null));
- bind(Key.class).annotatedWith(red).toProvider(Providers.<Key>of(null));
- bind(Module.class).annotatedWith(red).toProvider(Providers.<Module>of(null));
- bind(Provider.class).annotatedWith(red).toProvider(Providers.<Provider>of(null));
- bind(Scope.class).annotatedWith(red).toProvider(Providers.<Scope>of(null));
- bind(Stage.class).annotatedWith(red).toProvider(Providers.<Stage>of(null));
- bind(TypeLiteral.class).annotatedWith(red).toProvider(Providers.<TypeLiteral>of(null));
- bind(new TypeLiteral<Key<String>>() {}).toProvider(Providers.<Key<String>>of(null));
- }
- }
- public void testCannotBindToGuiceTypes() {
- try {
- Guice.createInjector(new OuterCoreModule());
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "Binding to core guice framework type is not allowed: AbstractModule.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Binder.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Binding.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Injector.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Key.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Module.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to Provider is not allowed.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Scope.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Stage.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: TypeLiteral.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class),
- "Binding to core guice framework type is not allowed: Key.",
- "at " + InnerCoreModule.class.getName() + getDeclaringSourcePart(getClass()),
- asModuleChain(OuterCoreModule.class, InnerCoreModule.class));
- }
- }
- static class MissingParameter {
- @Inject MissingParameter(NoInjectConstructor noInjectConstructor) {}
- }
- static class NoInjectConstructor {
- private NoInjectConstructor() {}
- }
- @ProvidedBy(HasProvidedBy1Provider.class)
- interface HasProvidedBy1 {}
- static class HasProvidedBy1Provider implements Provider<HasProvidedBy1> {
- public HasProvidedBy1 get() {
- return new HasProvidedBy1() {};
- }
- }
- @ImplementedBy(ImplementsHasImplementedBy1.class)
- interface HasImplementedBy1 {}
- static class ImplementsHasImplementedBy1 implements HasImplementedBy1 {}
- @ProvidedBy(HasProvidedBy2Provider.class)
- static class HasProvidedBy2 {}
- static class HasProvidedBy2Provider implements Provider<HasProvidedBy2> {
- public HasProvidedBy2 get() {
- return new HasProvidedBy2() {};
- }
- }
- @ImplementedBy(ExtendsHasImplementedBy2.class)
- static class HasImplementedBy2 {}
- static class ExtendsHasImplementedBy2 extends HasImplementedBy2 {}
- static class JustAClass {}
- @ImplementedBy(ImplementsHasImplementedByThatNeedsAnotherImplementedBy.class)
- static interface HasImplementedByThatNeedsAnotherImplementedBy {
- }
- static class ImplementsHasImplementedByThatNeedsAnotherImplementedBy
- implements HasImplementedByThatNeedsAnotherImplementedBy {
- @Inject
- ImplementsHasImplementedByThatNeedsAnotherImplementedBy(
- HasImplementedBy1 h1n1) {}
- }
- @ImplementedBy(ImplementsHasImplementedByThatWantsExplicit.class)
- static interface HasImplementedByThatWantsExplicit {
- }
- static class ImplementsHasImplementedByThatWantsExplicit
- implements HasImplementedByThatWantsExplicit {
- @Inject ImplementsHasImplementedByThatWantsExplicit(JustAnInterface jai) {}
- }
- static interface JustAnInterface {}
- // public void testBindInterfaceWithoutImplementation() {
- // Guice.createInjector(new AbstractModule() {
- // protected void configure() {
- // bind(Runnable.class);
- // }
- // }).getInstance(Runnable.class);
- // }
- enum Roshambo { ROCK, SCISSORS, PAPER }
- public void testInjectRawProvider() {
- try {
- Guice.createInjector().getInstance(Provider.class);
- fail();
- } catch (ConfigurationException expected) {
- Asserts.assertContains(expected.getMessage(),
- "1) Cannot inject a Provider that has no type parameter",
- "while locating " + Provider.class.getName());
- }
- }
- }