/core/test/com/google/inject/util/OverrideModuleTest.java
Java | 731 lines | 609 code | 99 blank | 23 comment | 17 complexity | af3d4fd1c09632988c7ce302bb46e519 MD5 | raw file
- /**
- * Copyright (C) 2008 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.util;
- import static com.google.inject.Asserts.asModuleChain;
- import static com.google.inject.Asserts.assertContains;
- import static com.google.inject.Guice.createInjector;
- import static com.google.inject.name.Names.named;
- import static java.lang.annotation.ElementType.METHOD;
- import static java.lang.annotation.ElementType.TYPE;
- import static java.lang.annotation.RetentionPolicy.RUNTIME;
- import com.google.common.base.Objects;
- import com.google.common.collect.ImmutableSet;
- import com.google.inject.AbstractModule;
- import com.google.inject.Binder;
- import com.google.inject.Binding;
- import com.google.inject.CreationException;
- import com.google.inject.Exposed;
- import com.google.inject.Guice;
- import com.google.inject.Injector;
- import com.google.inject.Key;
- import com.google.inject.Module;
- import com.google.inject.PrivateModule;
- import com.google.inject.Provider;
- import com.google.inject.Provides;
- import com.google.inject.Scope;
- import com.google.inject.ScopeAnnotation;
- import com.google.inject.Stage;
- import com.google.inject.name.Named;
- import com.google.inject.name.Names;
- import com.google.inject.spi.InjectionPoint;
- import com.google.inject.spi.ModuleAnnotatedMethodScanner;
- import junit.framework.TestCase;
- import java.lang.annotation.Annotation;
- import java.lang.annotation.Documented;
- import java.lang.annotation.Retention;
- import java.lang.annotation.Target;
- import java.util.Date;
- import java.util.Set;
- import java.util.concurrent.atomic.AtomicReference;
- /**
- * @author sberlin@gmail.com (Sam Berlin)
- */
- public class OverrideModuleTest extends TestCase {
- private static final Key<String> key2 = Key.get(String.class, named("2"));
- private static final Key<String> key3 = Key.get(String.class, named("3"));
- private static final Module EMPTY_MODULE = new Module() {
- public void configure(Binder binder) {}
- };
- public void testOverride() {
- Injector injector = createInjector(Modules.override(newModule("A")).with(newModule("B")));
- assertEquals("B", injector.getInstance(String.class));
- }
- public void testOverrideMultiple() {
- Module module = Modules.override(newModule("A"), newModule(1), newModule(0.5f))
- .with(newModule("B"), newModule(2), newModule(1.5d));
- Injector injector = createInjector(module);
- assertEquals("B", injector.getInstance(String.class));
- assertEquals(2, injector.getInstance(Integer.class).intValue());
- assertEquals(0.5f, injector.getInstance(Float.class));
- assertEquals(1.5d, injector.getInstance(Double.class));
- }
- public void testOverrideUnmatchedTolerated() {
- Injector injector = createInjector(Modules.override(EMPTY_MODULE).with(newModule("B")));
- assertEquals("B", injector.getInstance(String.class));
- }
- public void testOverrideConstant() {
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bindConstant().annotatedWith(named("Test")).to("A");
- }
- };
- Module replacements = new AbstractModule() {
- @Override protected void configure() {
- bindConstant().annotatedWith(named("Test")).to("B");
- }
- };
- Injector injector = createInjector(Modules.override(original).with(replacements));
- assertEquals("B", injector.getInstance(Key.get(String.class, named("Test"))));
- }
- public void testGetProviderInModule() {
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("A");
- bind(key2).toProvider(getProvider(String.class));
- }
- };
- Injector injector = createInjector(Modules.override(original).with(EMPTY_MODULE));
- assertEquals("A", injector.getInstance(String.class));
- assertEquals("A", injector.getInstance(key2));
- }
- public void testOverrideWhatGetProviderProvided() {
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("A");
- bind(key2).toProvider(getProvider(String.class));
- }
- };
- Module replacements = newModule("B");
- Injector injector = createInjector(Modules.override(original).with(replacements));
- assertEquals("B", injector.getInstance(String.class));
- assertEquals("B", injector.getInstance(key2));
- }
- public void testOverrideUsingOriginalsGetProvider() {
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("A");
- bind(key2).toInstance("B");
- }
- };
- Module replacements = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toProvider(getProvider(key2));
- }
- };
- Injector injector = createInjector(Modules.override(original).with(replacements));
- assertEquals("B", injector.getInstance(String.class));
- assertEquals("B", injector.getInstance(key2));
- }
- public void testOverrideOfOverride() {
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("A1");
- bind(key2).toInstance("A2");
- bind(key3).toInstance("A3");
- }
- };
- Module replacements1 = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("B1");
- bind(key2).toInstance("B2");
- }
- };
- Module overrides = Modules.override(original).with(replacements1);
- Module replacements2 = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("C1");
- bind(key3).toInstance("C3");
- }
- };
- Injector injector = createInjector(Modules.override(overrides).with(replacements2));
- assertEquals("C1", injector.getInstance(String.class));
- assertEquals("B2", injector.getInstance(key2));
- assertEquals("C3", injector.getInstance(key3));
- }
- static class OuterReplacementsModule extends AbstractModule {
- @Override protected void configure() {
- install(new InnerReplacementsModule());
- }
- }
- static class InnerReplacementsModule extends AbstractModule {
- @Override protected void configure() {
- bind(String.class).toInstance("B");
- bind(String.class).toInstance("C");
- }
- }
- public void testOverridesTwiceFails() {
- Module original = newModule("A");
- Module replacements = new OuterReplacementsModule();
- Module module = Modules.override(original).with(replacements);
- try {
- createInjector(module);
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "A binding to java.lang.String was already configured at "
- + InnerReplacementsModule.class.getName(),
- asModuleChain(Modules.OverrideModule.class,
- OuterReplacementsModule.class, InnerReplacementsModule.class),
- "at " + InnerReplacementsModule.class.getName(),
- asModuleChain(Modules.OverrideModule.class,
- OuterReplacementsModule.class, InnerReplacementsModule.class));
- }
- }
- public void testOverridesDoesntFixTwiceBoundInOriginal() {
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("A");
- bind(String.class).toInstance("B");
- }
- };
- Module replacements = new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).toInstance("C");
- }
- };
- Module module = Modules.override(original).with(replacements);
- try {
- createInjector(module);
- fail();
- } catch (CreationException expected) {
- // The replacement comes first because we replace A with C,
- // then we encounter B and freak out.
- assertContains(expected.getMessage(),
- "1) A binding to java.lang.String was already configured at "
- + replacements.getClass().getName(),
- asModuleChain(Modules.OverrideModule.class, replacements.getClass()),
- "at " + original.getClass().getName(),
- asModuleChain(Modules.OverrideModule.class, original.getClass()));
- }
- }
- public void testStandardScopeAnnotation() {
- final SingleUseScope scope = new SingleUseScope();
- Module module = new AbstractModule() {
- @Override protected void configure() {
- bindScope(TestScopeAnnotation.class, scope);
- bind(String.class).in(TestScopeAnnotation.class);
- }
- };
- assertFalse(scope.used);
- Guice.createInjector(module);
- assertTrue(scope.used);
- }
- public void testOverrideUntargettedBinding() {
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bind(Date.class);
- }
- };
- Module replacements = new AbstractModule() {
- @Override protected void configure() {
- bind(Date.class).toInstance(new Date(0));
- }
- };
- Injector injector = createInjector(Modules.override(original).with(replacements));
- assertEquals(0, injector.getInstance(Date.class).getTime());
- }
- public void testOverrideScopeAnnotation() {
- final Scope scope = new Scope() {
- public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
- throw new AssertionError("Should not be called");
- }
- };
- final SingleUseScope replacementScope = new SingleUseScope();
- Module original = new AbstractModule() {
- @Override protected void configure() {
- bindScope(TestScopeAnnotation.class, scope);
- bind(Date.class).in(TestScopeAnnotation.class);
- }
- };
- Module replacements = new AbstractModule() {
- @Override protected void configure() {
- bindScope(TestScopeAnnotation.class, replacementScope);
- }
- };
- Injector injector = createInjector(Modules.override(original).with(replacements));
- injector.getInstance(Date.class);
- assertTrue(replacementScope.used);
- }
- public void testFailsIfOverridenScopeInstanceHasBeenUsed() {
- final Scope scope = new Scope() {
- public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
- return unscoped;
- }
- @Override public String toString() {
- return "ORIGINAL SCOPE";
- }
- };
- final Module original = new AbstractModule() {
- @Override protected void configure() {
- bindScope(TestScopeAnnotation.class, scope);
- bind(Date.class).in(scope);
- bind(String.class).in(scope);
- }
- };
- Module originalWrapper = new AbstractModule() {
- @Override protected void configure() {
- install(original);
- }
- };
- Module replacements = new AbstractModule() {
- @Override protected void configure() {
- bindScope(TestScopeAnnotation.class, new SingleUseScope());
- }
- };
- try {
- createInjector(Modules.override(originalWrapper).with(replacements));
- fail("Exception expected");
- } catch (CreationException e) {
- assertContains(e.getMessage(),
- "1) The scope for @TestScopeAnnotation is bound directly and cannot be overridden.",
- "original binding at " + original.getClass().getName() + ".configure(",
- asModuleChain(originalWrapper.getClass(), original.getClass()),
- "bound directly at " + original.getClass().getName() + ".configure(",
- asModuleChain(originalWrapper.getClass(), original.getClass()),
- "bound directly at " + original.getClass().getName() + ".configure(",
- asModuleChain(originalWrapper.getClass(), original.getClass()),
- "at ", replacements.getClass().getName() + ".configure(",
- asModuleChain(Modules.OverrideModule.class, replacements.getClass()));
- }
- }
- public void testOverrideIsLazy() {
- final AtomicReference<String> value = new AtomicReference<String>("A");
- Module overridden = Modules.override(new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).annotatedWith(named("original")).toInstance(value.get());
- }
- }).with(new AbstractModule() {
- @Override protected void configure() {
- bind(String.class).annotatedWith(named("override")).toInstance(value.get());
- }
- });
- // the value.get() call should be deferred until Guice.createInjector
- value.set("B");
- Injector injector = Guice.createInjector(overridden);
- assertEquals("B", injector.getInstance(Key.get(String.class, named("original"))));
- assertEquals("B", injector.getInstance(Key.get(String.class, named("override"))));
- }
- public void testOverridePrivateModuleOverPrivateModule() {
- Module exposes5and6 = new AbstractModule() {
- @Override protected void configure() {
- install(new PrivateModule() {
- @Override protected void configure() {
- bind(Integer.class).toInstance(5);
- expose(Integer.class);
- bind(Character.class).toInstance('E');
- }
- });
- install(new PrivateModule() {
- @Override protected void configure() {
- bind(Long.class).toInstance(6L);
- expose(Long.class);
- bind(Character.class).toInstance('F');
- }
- });
- }
- };
- AbstractModule exposes15 = new AbstractModule() {
- @Override protected void configure() {
- install(new PrivateModule() {
- @Override protected void configure() {
- bind(Integer.class).toInstance(15);
- expose(Integer.class);
- bind(Character.class).toInstance('G');
- }
- });
- install(new PrivateModule() {
- @Override protected void configure() {
- bind(Character.class).toInstance('H');
- }
- });
- }
- };
- // override forwards
- Injector injector = Guice.createInjector(Modules.override(exposes5and6).with(exposes15));
- assertEquals(15, injector.getInstance(Integer.class).intValue());
- assertEquals(6L, injector.getInstance(Long.class).longValue());
- // and in reverse order
- Injector reverse = Guice.createInjector(Modules.override(exposes15).with(exposes5and6));
- assertEquals(5, reverse.getInstance(Integer.class).intValue());
- assertEquals(6L, reverse.getInstance(Long.class).longValue());
- }
- public void testOverrideModuleAndPrivateModule() {
- Module exposes5 = new PrivateModule() {
- @Override protected void configure() {
- bind(Integer.class).toInstance(5);
- expose(Integer.class);
- }
- };
- Module binds15 = new AbstractModule() {
- @Override protected void configure() {
- bind(Integer.class).toInstance(15);
- }
- };
- Injector injector = Guice.createInjector(Modules.override(exposes5).with(binds15));
- assertEquals(15, injector.getInstance(Integer.class).intValue());
- Injector reverse = Guice.createInjector(Modules.override(binds15).with(exposes5));
- assertEquals(5, reverse.getInstance(Integer.class).intValue());
- }
- public void testOverrideDeepExpose() {
- final AtomicReference<Provider<Character>> charAProvider
- = new AtomicReference<Provider<Character>>();
- Module exposes5 = new PrivateModule() {
- @Override protected void configure() {
- install(new PrivateModule() {
- @Override protected void configure() {
- bind(Integer.class).toInstance(5);
- expose(Integer.class);
- charAProvider.set(getProvider(Character.class));
- bind(Character.class).toInstance('A');
- }
- });
- expose(Integer.class);
- }
- };
- Injector injector = Guice.createInjector(Modules.override(exposes5).with(EMPTY_MODULE));
- assertEquals(5, injector.getInstance(Integer.class).intValue());
- assertEquals('A', charAProvider.getAndSet(null).get().charValue());
- injector = Guice.createInjector(Modules.override(EMPTY_MODULE).with(exposes5));
- assertEquals(5, injector.getInstance(Integer.class).intValue());
- assertEquals('A', charAProvider.getAndSet(null).get().charValue());
- final AtomicReference<Provider<Character>> charBProvider
- = new AtomicReference<Provider<Character>>();
- Module binds15 = new AbstractModule() {
- @Override protected void configure() {
- bind(Integer.class).toInstance(15);
- install(new PrivateModule() {
- @Override protected void configure() {
- charBProvider.set(getProvider(Character.class));
- bind(Character.class).toInstance('B');
- }
- });
- }
- };
- injector = Guice.createInjector(Modules.override(binds15).with(exposes5));
- assertEquals(5, injector.getInstance(Integer.class).intValue());
- assertEquals('A', charAProvider.getAndSet(null).get().charValue());
- assertEquals('B', charBProvider.getAndSet(null).get().charValue());
- injector = Guice.createInjector(Modules.override(exposes5).with(binds15));
- assertEquals(15, injector.getInstance(Integer.class).intValue());
- assertEquals('A', charAProvider.getAndSet(null).get().charValue());
- assertEquals('B', charBProvider.getAndSet(null).get().charValue());
- }
- @Retention(RUNTIME)
- @Target(TYPE)
- @ScopeAnnotation
- private static @interface TestScopeAnnotation {}
- private static class SingleUseScope implements Scope {
- boolean used = false;
- public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
- assertFalse(used);
- used = true;
- return unscoped;
- }
- }
-
- static class NewModule<T> extends AbstractModule {
- private final T bound;
- NewModule(T bound) {
- this.bound = bound;
- }
- @Override protected void configure() {
- @SuppressWarnings("unchecked")
- Class<T> type = (Class<T>)bound.getClass();
- bind(type).toInstance(bound);
- }
- }
- private static <T> Module newModule(final T bound) {
- return new NewModule<T>(bound);
- }
-
- private static final String RESULT = "RESULT";
- private static final String PRIVATE_INPUT = "PRIVATE_INPUT";
- private static final String OVERRIDDEN_INPUT = "FOO";
- private static final String OVERRIDDEN_RESULT = "Size: 3";
- private static final Key<String> RESULT_KEY = Key.get(String.class, named(RESULT));
- private static final Key<String> INPUT_KEY = Key.get(String.class, named(PRIVATE_INPUT));
- public void testExposedBindingOverride() throws Exception {
- Injector inj = Guice.createInjector(
- Modules.override(new ExampleModule()).with(
- new AbstractModule() {
- @Override protected void configure() {
- bind(RESULT_KEY).toInstance(OVERRIDDEN_RESULT);
- }
- }));
- assertEquals(inj.getInstance(RESULT_KEY), OVERRIDDEN_RESULT);
- }
- public void testPrivateBindingOverride() throws Exception {
- Injector inj = Guice.createInjector(
- Modules.override(new ExampleModule()).with(
- new AbstractModule() {
- @Override protected void configure() {
- bind(INPUT_KEY).toInstance(OVERRIDDEN_INPUT);
- }
- }));
- assertEquals(inj.getInstance(RESULT_KEY), OVERRIDDEN_RESULT);
- }
- public static class ExampleModule extends PrivateModule {
- @Provides @Exposed @Named(RESULT)
- public String provideResult(@Named(PRIVATE_INPUT) String input) {
- return "Size: " + input.length();
- }
- @Provides @Named(PRIVATE_INPUT)
- public String provideInput() {
- return "Hello World";
- }
- @Override protected void configure() {
- }
- }
-
- public void testEqualsNotCalledByDefaultOnInstance() {
- final HashEqualsTester a = new HashEqualsTester();
- a.throwOnEquals = true;
- Guice.createInjector(Modules.override(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(HashEqualsTester.class).toInstance(a);
- }
- }).with());
- }
-
- public void testEqualsNotCalledByDefaultOnProvider() {
- final HashEqualsTester a = new HashEqualsTester();
- a.throwOnEquals = true;
- Guice.createInjector(Modules.override(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(Object.class).toProvider(a);
- }
- }).with());
- }
-
- 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(Modules.override(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(HashEqualsTester.class).toInstance(a);
- bind(HashEqualsTester.class).toInstance(b);
- }
- }).with());
- }
-
- 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(Modules.override(new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class);
- bind(Object.class).toProvider(a);
- bind(Object.class).toProvider(b);
- }
- }).with());
- }
-
- 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();
- }
- }
- public void testCorrectStage() {
- final Stage stage = Stage.PRODUCTION;
- Module module = Modules.override(new AbstractModule() {
- @Override
- protected void configure() {
- if (currentStage() != Stage.PRODUCTION) {
- addError("Wronge stage in overridden module:" + currentStage());
- }
- }
- }).with(new AbstractModule() {
- @Override
- protected void configure() {
- if (currentStage() != Stage.PRODUCTION) {
- addError("Wronge stage in overriding module:" + currentStage());
- }
- }
- });
- Guice.createInjector(stage, module);
- }
- public void testOverridesApplyOriginalScanners() {
- Injector injector =
- Guice.createInjector(Modules.override(NamedMunger.module()).with(new AbstractModule() {
- @Override protected void configure() {}
- @TestProvides @Named("test") String provideString() { return "foo"; }
- }));
- assertNull(injector.getExistingBinding(Key.get(String.class, named("test"))));
- Binding<String> binding = injector.getBinding(Key.get(String.class, named("test-munged")));
- assertEquals("foo", binding.getProvider().get());
- }
- @Documented @Target(METHOD) @Retention(RUNTIME)
- private @interface TestProvides {}
- private static class NamedMunger extends ModuleAnnotatedMethodScanner {
- static Module module() {
- return new AbstractModule() {
- @Override protected void configure() {
- binder().scanModulesForAnnotatedMethods(new NamedMunger());
- }
- };
- }
- @Override
- public String toString() {
- return "NamedMunger";
- }
- @Override
- public Set<? extends Class<? extends Annotation>> annotationClasses() {
- return ImmutableSet.of(TestProvides.class);
- }
- @Override
- public <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key,
- InjectionPoint injectionPoint) {
- return Key.get(key.getTypeLiteral(),
- Names.named(((Named) key.getAnnotation()).value() + "-munged"));
- }
- }
- }