/core/test/com/google/inject/DuplicateBindingsTest.java
Java | 576 lines | 445 code | 83 blank | 48 comment | 23 complexity | 62621c91772c58b264f75716bd796a7b MD5 | raw file
- /**
- * Copyright (C) 2010 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.*;
- import static com.google.inject.name.Names.named;
- import com.google.common.base.Objects;
- import com.google.common.collect.Lists;
- import com.google.inject.name.Named;
- import com.google.inject.spi.Element;
- import com.google.inject.spi.Elements;
- import com.google.inject.util.Providers;
- import junit.framework.TestCase;
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Constructor;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.logging.Logger;
- /**
- * A suite of tests for duplicate bindings.
- *
- * @author sameb@google.com (Sam Berlin)
- */
- public class DuplicateBindingsTest extends TestCase {
-
- private FooImpl foo = new FooImpl();
- private Provider<Foo> pFoo = Providers.<Foo>of(new FooImpl());
- private Class<? extends Provider<? extends Foo>> pclFoo = FooProvider.class;
- private Class<? extends Foo> clFoo = FooImpl.class;
- private Constructor<FooImpl> cFoo = FooImpl.cxtor();
- public void testDuplicateBindingsAreIgnored() {
- Injector injector = Guice.createInjector(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
- );
- List<Key<?>> bindings = Lists.newArrayList(injector.getAllBindings().keySet());
- removeBasicBindings(bindings);
-
- // Ensure only one binding existed for each type.
- assertTrue(bindings.remove(Key.get(Foo.class, named("instance"))));
- assertTrue(bindings.remove(Key.get(Foo.class, named("pInstance"))));
- assertTrue(bindings.remove(Key.get(Foo.class, named("pKey"))));
- assertTrue(bindings.remove(Key.get(Foo.class, named("linkedKey"))));
- assertTrue(bindings.remove(Key.get(FooImpl.class)));
- assertTrue(bindings.remove(Key.get(Foo.class, named("constructor"))));
- assertTrue(bindings.remove(Key.get(FooProvider.class))); // JIT binding
- assertTrue(bindings.remove(Key.get(Foo.class, named("providerMethod"))));
-
- assertEquals(bindings.toString(), 0, bindings.size());
- }
-
- public void testElementsDeduplicate() {
- List<Element> elements = Elements.getElements(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
- );
- assertEquals(14, elements.size());
- assertEquals(7, new LinkedHashSet<Element>(elements).size());
- }
-
- public void testProviderMethodsFailIfInstancesDiffer() {
- try {
- Guice.createInjector(new FailingProviderModule(), new FailingProviderModule());
- fail("should have failed");
- } catch(CreationException ce) {
- assertContains(ce.getMessage(),
- "A binding to " + Foo.class.getName() + " was already configured " +
- "at " + FailingProviderModule.class.getName(),
- "at " + FailingProviderModule.class.getName()
- );
- }
- }
-
- public void testSameScopeInstanceIgnored() {
- Guice.createInjector(
- new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo),
- new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo)
- );
-
- Guice.createInjector(
- new ScopedModule(Scopes.NO_SCOPE, foo, pFoo, pclFoo, clFoo, cFoo),
- new ScopedModule(Scopes.NO_SCOPE, foo, pFoo, pclFoo, clFoo, cFoo)
- );
- }
-
- public void testSameScopeAnnotationIgnored() {
- Guice.createInjector(
- new AnnotatedScopeModule(Singleton.class, foo, pFoo, pclFoo, clFoo, cFoo),
- new AnnotatedScopeModule(Singleton.class, foo, pFoo, pclFoo, clFoo, cFoo)
- );
- }
-
- public void testMixedAnnotationAndScopeForSingletonIgnored() {
- Guice.createInjector(
- new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo),
- new AnnotatedScopeModule(Singleton.class, foo, pFoo, pclFoo, clFoo, cFoo)
- );
- }
-
- public void testMixedScopeAndUnscopedIgnored() {
- Guice.createInjector(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
- new ScopedModule(Scopes.NO_SCOPE, foo, pFoo, pclFoo, clFoo, cFoo)
- );
- }
- public void testMixedScopeFails() {
- try {
- Guice.createInjector(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
- new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo)
- );
- fail("expected exception");
- } catch(CreationException ce) {
- String segment1 = "A binding to " + Foo.class.getName() + " annotated with "
- + named("pInstance") + " was already configured at " + SimpleModule.class.getName();
- String segment2 = "A binding to " + Foo.class.getName() + " annotated with " + named("pKey")
- + " was already configured at " + SimpleModule.class.getName();
- String segment3 = "A binding to " + Foo.class.getName() + " annotated with "
- + named("constructor") + " was already configured at " + SimpleModule.class.getName();
- String segment4 = "A binding to " + FooImpl.class.getName() + " was already configured at "
- + SimpleModule.class.getName();
- String atSegment = "at " + ScopedModule.class.getName();
- if (isIncludeStackTraceOff()) {
- assertContains(ce.getMessage(), segment1 , atSegment, segment2, atSegment, segment3,
- atSegment, segment4, atSegment);
- } else {
- assertContains(ce.getMessage(), segment1 , atSegment, segment2, atSegment, segment4,
- atSegment, segment3, atSegment);
- }
- }
- }
- @SuppressWarnings("unchecked")
- public void testMixedTargetsFails() {
- try {
- Guice.createInjector(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
- new SimpleModule(new FooImpl(), Providers.<Foo>of(new FooImpl()),
- (Class)BarProvider.class, (Class)Bar.class, (Constructor)Bar.cxtor())
- );
- fail("expected exception");
- } catch(CreationException ce) {
- assertContains(ce.getMessage(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("pInstance") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("pKey") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("linkedKey") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("constructor") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName());
- }
- }
-
- public void testExceptionInEqualsThrowsCreationException() {
- try {
- Guice.createInjector(new ThrowingModule(), new ThrowingModule());
- fail("expected exception");
- } catch(CreationException ce) {
- assertContains(ce.getMessage(),
- "A binding to " + Foo.class.getName() + " was already configured at " + ThrowingModule.class.getName(),
- "and an error was thrown while checking duplicate bindings. Error: java.lang.RuntimeException: Boo!",
- "at " + ThrowingModule.class.getName());
- }
- }
-
- public void testChildInjectorDuplicateParentFail() {
- Injector injector = Guice.createInjector(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
- );
-
- try {
- injector.createChildInjector(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
- );
- fail("expected exception");
- } catch(CreationException ce) {
- assertContains(ce.getMessage(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("pInstance") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("pKey") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("linkedKey") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("constructor") + " was already configured at " + SimpleModule.class.getName(),
- "at " + SimpleModule.class.getName(),
- "A binding to " + Foo.class.getName() + " annotated with " + named("providerMethod") + " was already configured at " + SimpleProviderModule.class.getName(),
- "at " + SimpleProviderModule.class.getName()
- );
- }
-
-
- }
-
- public void testDuplicatesSolelyInChildIgnored() {
- Injector injector = Guice.createInjector();
- injector.createChildInjector(
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
- new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
- );
- }
-
- public void testDifferentBindingTypesFail() {
- List<Element> elements = Elements.getElements(
- new FailedModule(foo, pFoo, pclFoo, clFoo, cFoo)
- );
-
- // Make sure every combination of the elements with another element fails.
- // This ensures that duplication checks the kind of binding also.
- for(Element e1 : elements) {
- for(Element e2: elements) {
- // if they're the same, this shouldn't fail.
- try {
- Guice.createInjector(Elements.getModule(Arrays.asList(e1, e2)));
- if(e1 != e2) {
- fail("must fail!");
- }
- } catch(CreationException expected) {
- if(e1 != e2) {
- assertContains(expected.getMessage(),
- "A binding to " + Foo.class.getName() + " was already configured at " + FailedModule.class.getName(),
- "at " + FailedModule.class.getName());
- } else {
- throw expected;
- }
- }
- }
- }
- }
-
- public void testJitBindingsAreCheckedAfterConversions() {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(A.class);
- bind(A.class).to(RealA.class);
- }
- });
- }
-
- public void testEqualsNotCalledByDefaultOnInstance() {
- final HashEqualsTester a = new HashEqualsTester();
- a.throwOnEquals = true;
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(HashEqualsTester.class).toInstance(a);
- }
- });
- }
-
- public void testEqualsNotCalledByDefaultOnProvider() {
- final HashEqualsTester a = new HashEqualsTester();
- a.throwOnEquals = true;
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(Object.class).toProvider(a);
- }
- });
- }
-
- public void testHashcodeNeverCalledOnInstance() {
- final HashEqualsTester a = new HashEqualsTester();
- a.throwOnHashcode = true;
- a.equality = "test";
-
- final HashEqualsTester b = new HashEqualsTester();
- b.throwOnHashcode = true;
- b.equality = "test";
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(HashEqualsTester.class).toInstance(a);
- bind(HashEqualsTester.class).toInstance(b);
- }
- });
- }
-
- public void testHashcodeNeverCalledOnProviderInstance() {
- final HashEqualsTester a = new HashEqualsTester();
- a.throwOnHashcode = true;
- a.equality = "test";
-
- final HashEqualsTester b = new HashEqualsTester();
- b.throwOnHashcode = true;
- b.equality = "test";
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(Object.class).toProvider(a);
- bind(Object.class).toProvider(b);
- }
- });
- }
- private static class RealA extends A {}
- @ImplementedBy(RealA.class) private static class A {}
-
- private void removeBasicBindings(Collection<Key<?>> bindings) {
- bindings.remove(Key.get(Injector.class));
- bindings.remove(Key.get(Logger.class));
- bindings.remove(Key.get(Stage.class));
- }
-
- private static class ThrowingModule extends AbstractModule {
- @Override
- protected void configure() {
- bind(Foo.class).toInstance(new Foo() {
- @Override
- public boolean equals(Object obj) {
- throw new RuntimeException("Boo!");
- }
- });
- }
- }
-
- private static abstract class FooModule extends AbstractModule {
- protected final FooImpl foo;
- protected final Provider<Foo> pFoo;
- protected final Class<? extends Provider<? extends Foo>> pclFoo;
- protected final Class<? extends Foo> clFoo;
- protected final Constructor<FooImpl> cFoo;
-
- FooModule(FooImpl foo, Provider<Foo> pFoo, Class<? extends Provider<? extends Foo>> pclFoo,
- Class<? extends Foo> clFoo, Constructor<FooImpl> cFoo) {
- this.foo = foo;
- this.pFoo = pFoo;
- this.pclFoo = pclFoo;
- this.clFoo = clFoo;
- this.cFoo = cFoo;
- }
- }
-
- private static class FailedModule extends FooModule {
- FailedModule(FooImpl foo, Provider<Foo> pFoo, Class<? extends Provider<? extends Foo>> pclFoo,
- Class<? extends Foo> clFoo, Constructor<FooImpl> cFoo) {
- super(foo, pFoo, pclFoo, clFoo, cFoo);
- }
-
- protected void configure() {
- // InstanceBinding
- bind(Foo.class).toInstance(foo);
-
- // ProviderInstanceBinding
- bind(Foo.class).toProvider(pFoo);
-
- // ProviderKeyBinding
- bind(Foo.class).toProvider(pclFoo);
-
- // LinkedKeyBinding
- bind(Foo.class).to(clFoo);
-
- // ConstructorBinding
- bind(Foo.class).toConstructor(cFoo);
- }
-
- @Provides Foo foo() {
- return null;
- }
- }
-
- private static class FailingProviderModule extends AbstractModule {
- @Override protected void configure() {}
- @Provides Foo foo() {
- return null;
- }
- }
- private static class SimpleProviderModule extends AbstractModule {
- @Override protected void configure() {}
- @Provides @Named("providerMethod") Foo foo() {
- return null;
- }
- @Override
- public boolean equals(Object obj) {
- return obj.getClass() == getClass();
- }
- }
-
- private static class SimpleModule extends FooModule {
- SimpleModule(FooImpl foo, Provider<Foo> pFoo, Class<? extends Provider<? extends Foo>> pclFoo,
- Class<? extends Foo> clFoo, Constructor<FooImpl> cFoo) {
- super(foo, pFoo, pclFoo, clFoo, cFoo);
- }
-
- protected void configure() {
- // InstanceBinding
- bind(Foo.class).annotatedWith(named("instance")).toInstance(foo);
-
- // ProviderInstanceBinding
- bind(Foo.class).annotatedWith(named("pInstance")).toProvider(pFoo);
-
- // ProviderKeyBinding
- bind(Foo.class).annotatedWith(named("pKey")).toProvider(pclFoo);
-
- // LinkedKeyBinding
- bind(Foo.class).annotatedWith(named("linkedKey")).to(clFoo);
-
- // UntargettedBinding / ConstructorBinding
- bind(FooImpl.class);
-
- // ConstructorBinding
- bind(Foo.class).annotatedWith(named("constructor")).toConstructor(cFoo);
- // ProviderMethod
- // (reconstructed from an Element to ensure it doesn't get filtered out
- // by deduplicating Modules)
- install(Elements.getModule(Elements.getElements(new SimpleProviderModule())));
- }
- }
-
- private static class ScopedModule extends FooModule {
- private final Scope scope;
- ScopedModule(Scope scope, FooImpl foo, Provider<Foo> pFoo,
- Class<? extends Provider<? extends Foo>> pclFoo, Class<? extends Foo> clFoo,
- Constructor<FooImpl> cFoo) {
- super(foo, pFoo, pclFoo, clFoo, cFoo);
- this.scope = scope;
- }
-
- protected void configure() {
- // ProviderInstanceBinding
- bind(Foo.class).annotatedWith(named("pInstance")).toProvider(pFoo).in(scope);
-
- // ProviderKeyBinding
- bind(Foo.class).annotatedWith(named("pKey")).toProvider(pclFoo).in(scope);
-
- // LinkedKeyBinding
- bind(Foo.class).annotatedWith(named("linkedKey")).to(clFoo).in(scope);
-
- // UntargettedBinding / ConstructorBinding
- bind(FooImpl.class).in(scope);
-
- // ConstructorBinding
- bind(Foo.class).annotatedWith(named("constructor")).toConstructor(cFoo).in(scope);
- }
- }
-
- private static class AnnotatedScopeModule extends FooModule {
- private final Class<? extends Annotation> scope;
- AnnotatedScopeModule(Class<? extends Annotation> scope, FooImpl foo, Provider<Foo> pFoo,
- Class<? extends Provider<? extends Foo>> pclFoo, Class<? extends Foo> clFoo,
- Constructor<FooImpl> cFoo) {
- super(foo, pFoo, pclFoo, clFoo, cFoo);
- this.scope = scope;
- }
-
-
- protected void configure() {
- // ProviderInstanceBinding
- bind(Foo.class).annotatedWith(named("pInstance")).toProvider(pFoo).in(scope);
-
- // ProviderKeyBinding
- bind(Foo.class).annotatedWith(named("pKey")).toProvider(pclFoo).in(scope);
-
- // LinkedKeyBinding
- bind(Foo.class).annotatedWith(named("linkedKey")).to(clFoo).in(scope);
-
- // UntargettedBinding / ConstructorBinding
- bind(FooImpl.class).in(scope);
-
- // ConstructorBinding
- bind(Foo.class).annotatedWith(named("constructor")).toConstructor(cFoo).in(scope);
- }
- }
-
- private static interface Foo {}
- private static class FooImpl implements Foo {
- @Inject public FooImpl() {}
-
- private static Constructor<FooImpl> cxtor() {
- try {
- return FooImpl.class.getConstructor();
- } catch (SecurityException e) {
- throw new RuntimeException(e);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
- }
- }
- private static class FooProvider implements Provider<Foo> {
- public Foo get() {
- return new FooImpl();
- }
- }
-
- private static class Bar implements Foo {
- @Inject public Bar() {}
-
- private static Constructor<Bar> cxtor() {
- try {
- return Bar.class.getConstructor();
- } catch (SecurityException e) {
- throw new RuntimeException(e);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
- }
- }
- private static class BarProvider implements Provider<Foo> {
- public Foo get() {
- return new Bar();
- }
- }
-
- private static class HashEqualsTester implements Provider<Object> {
- private String equality;
- private boolean throwOnEquals;
- private boolean throwOnHashcode;
-
- @Override
- public boolean equals(Object obj) {
- if (throwOnEquals) {
- throw new RuntimeException();
- } else if (obj instanceof HashEqualsTester) {
- HashEqualsTester o = (HashEqualsTester)obj;
- if(o.throwOnEquals) {
- throw new RuntimeException();
- }
- if(equality == null && o.equality == null) {
- return this == o;
- } else {
- return Objects.equal(equality, o.equality);
- }
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- if(throwOnHashcode) {
- throw new RuntimeException();
- } else {
- return super.hashCode();
- }
- }
-
- public Object get() {
- return new Object();
- }
- }
-
- }