/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryModuleBuilderTest.java
Java | 540 lines | 458 code | 63 blank | 19 comment | 4 complexity | 23fc2c0fda33ed401ed50770770718df MD5 | raw file
- /**
- * Copyright (C) 2009 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.assistedinject;
- import static com.google.inject.Asserts.assertContains;
- import static com.google.inject.name.Names.named;
- import com.google.common.collect.ImmutableSet;
- import com.google.common.collect.Iterables;
- import com.google.inject.AbstractModule;
- import com.google.inject.Binding;
- import com.google.inject.CreationException;
- import com.google.inject.Guice;
- import com.google.inject.Inject;
- import com.google.inject.Injector;
- import com.google.inject.Key;
- import com.google.inject.Module;
- import com.google.inject.Provides;
- import com.google.inject.Singleton;
- import com.google.inject.Stage;
- import com.google.inject.TypeLiteral;
- import com.google.inject.name.Named;
- import com.google.inject.name.Names;
- import com.google.inject.spi.Dependency;
- import com.google.inject.spi.Element;
- import com.google.inject.spi.Elements;
- import com.google.inject.spi.HasDependencies;
- import com.google.inject.spi.Message;
- import junit.framework.TestCase;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
- public class FactoryModuleBuilderTest extends TestCase {
-
- private enum Color { BLUE, GREEN, RED, GRAY, BLACK }
- public void testImplicitForwardingAssistedBindingFailsWithInterface() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(Car.class).to(Golf.class);
- install(new FactoryModuleBuilder().build(ColoredCarFactory.class));
- }
- });
- fail();
- } catch (CreationException ce) {
- assertContains(
- ce.getMessage(), "1) " + Car.class.getName() + " is an interface, not a concrete class.",
- "Unable to create AssistedInject factory.",
- "while locating " + Car.class.getName(),
- "at " + ColoredCarFactory.class.getName() + ".create(");
- assertEquals(1, ce.getErrorMessages().size());
- }
- }
-
- public void testImplicitForwardingAssistedBindingFailsWithAbstractClass() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(AbstractCar.class).to(ArtCar.class);
- install(new FactoryModuleBuilder().build(ColoredAbstractCarFactory.class));
- }
- });
- fail();
- } catch (CreationException ce) {
- assertContains(
- ce.getMessage(), "1) " + AbstractCar.class.getName() + " is abstract, not a concrete class.",
- "Unable to create AssistedInject factory.",
- "while locating " + AbstractCar.class.getName(),
- "at " + ColoredAbstractCarFactory.class.getName() + ".create(");
- assertEquals(1, ce.getErrorMessages().size());
- }
- }
- public void testImplicitForwardingAssistedBindingCreatesNewObjects() {
- final Mustang providedMustang = new Mustang(Color.BLUE);
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override protected void configure() {
- install(new FactoryModuleBuilder().build(MustangFactory.class));
- }
- @Provides Mustang provide() { return providedMustang; }
- });
- assertSame(providedMustang, injector.getInstance(Mustang.class));
- MustangFactory factory = injector.getInstance(MustangFactory.class);
- Mustang created = factory.create(Color.GREEN);
- assertNotSame(providedMustang, created);
- assertEquals(Color.BLUE, providedMustang.color);
- assertEquals(Color.GREEN, created.color);
- }
- public void testExplicitForwardingAssistedBindingFailsWithInterface() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(Volkswagen.class).to(Golf.class);
- install(new FactoryModuleBuilder()
- .implement(Car.class, Volkswagen.class)
- .build(ColoredCarFactory.class));
- }
- });
- fail();
- } catch (CreationException ce) {
- assertContains(
- ce.getMessage(), "1) " + Volkswagen.class.getName() + " is an interface, not a concrete class.",
- "Unable to create AssistedInject factory.",
- "while locating " + Volkswagen.class.getName(),
- "while locating " + Car.class.getName(),
- "at " + ColoredCarFactory.class.getName() + ".create(");
- assertEquals(1, ce.getErrorMessages().size());
- }
- }
- public void testExplicitForwardingAssistedBindingFailsWithAbstractClass() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(AbstractCar.class).to(ArtCar.class);
- install(new FactoryModuleBuilder()
- .implement(Car.class, AbstractCar.class)
- .build(ColoredCarFactory.class));
- }
- });
- fail();
- } catch (CreationException ce) {
- assertContains(
- ce.getMessage(), "1) " + AbstractCar.class.getName() + " is abstract, not a concrete class.",
- "Unable to create AssistedInject factory.",
- "while locating " + AbstractCar.class.getName(),
- "while locating " + Car.class.getName(),
- "at " + ColoredCarFactory.class.getName() + ".create(");
- assertEquals(1, ce.getErrorMessages().size());
- }
- }
-
- public void testExplicitForwardingAssistedBindingCreatesNewObjects() {
- final Mustang providedMustang = new Mustang(Color.BLUE);
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override protected void configure() {
- install(new FactoryModuleBuilder().implement(Car.class, Mustang.class).build(
- ColoredCarFactory.class));
- }
- @Provides Mustang provide() { return providedMustang; }
- });
- assertSame(providedMustang, injector.getInstance(Mustang.class));
- ColoredCarFactory factory = injector.getInstance(ColoredCarFactory.class);
- Mustang created = (Mustang)factory.create(Color.GREEN);
- assertNotSame(providedMustang, created);
- assertEquals(Color.BLUE, providedMustang.color);
- assertEquals(Color.GREEN, created.color);
- }
- public void testAnnotatedAndParentBoundReturnValue() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override protected void configure() {
- bind(Car.class).to(Golf.class);
- bind(Integer.class).toInstance(911);
- bind(Double.class).toInstance(5.0d);
- install(new FactoryModuleBuilder()
- .implement(Car.class, Names.named("german"), Beetle.class)
- .implement(Car.class, Names.named("american"), Mustang.class)
- .build(AnnotatedVersatileCarFactory.class));
- }
- });
- AnnotatedVersatileCarFactory factory = injector.getInstance(AnnotatedVersatileCarFactory.class);
- assertTrue(factory.getGermanCar(Color.BLACK) instanceof Beetle);
- assertTrue(injector.getInstance(Car.class) instanceof Golf);
- }
- public void testParentBoundReturnValue() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override protected void configure() {
- bind(Car.class).to(Golf.class);
- bind(Double.class).toInstance(5.0d);
- install(new FactoryModuleBuilder()
- .implement(Car.class, Mustang.class)
- .build(ColoredCarFactory.class));
- }
- });
- ColoredCarFactory factory = injector.getInstance(ColoredCarFactory.class);
- assertTrue(factory.create(Color.RED) instanceof Mustang);
- assertTrue(injector.getInstance(Car.class) instanceof Golf);
- }
- public void testConfigureAnnotatedReturnValue() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override protected void configure() {
- install(new FactoryModuleBuilder()
- .implement(Car.class, Names.named("german"), Beetle.class)
- .implement(Car.class, Names.named("american"), Mustang.class)
- .build(AnnotatedVersatileCarFactory.class));
- }
- });
- AnnotatedVersatileCarFactory factory = injector.getInstance(AnnotatedVersatileCarFactory.class);
- assertTrue(factory.getGermanCar(Color.GRAY) instanceof Beetle);
- assertTrue(factory.getAmericanCar(Color.BLACK) instanceof Mustang);
- }
- public void testNoBindingAssistedInject() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder().build(MustangFactory.class));
- }
- });
- MustangFactory factory = injector.getInstance(MustangFactory.class);
- Mustang mustang = factory.create(Color.BLUE);
- assertEquals(Color.BLUE, mustang.color);
- }
- public void testBindingAssistedInject() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder()
- .implement(Car.class, Mustang.class)
- .build(ColoredCarFactory.class));
- }
- });
- ColoredCarFactory factory = injector.getInstance(ColoredCarFactory.class);
- Mustang mustang = (Mustang) factory.create(Color.BLUE);
- assertEquals(Color.BLUE, mustang.color);
- }
- public void testDuplicateBindings() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder()
- .implement(Car.class, Mustang.class)
- .build(ColoredCarFactory.class));
- install(new FactoryModuleBuilder()
- .implement(Car.class, Mustang.class)
- .build(ColoredCarFactory.class));
- }
- });
- ColoredCarFactory factory = injector.getInstance(ColoredCarFactory.class);
- Mustang mustang = (Mustang) factory.create(Color.BLUE);
- assertEquals(Color.BLUE, mustang.color);
- }
- public void testSimilarBindingsWithConflictingImplementations() {
- try {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder()
- .implement(Car.class, Mustang.class)
- .build(ColoredCarFactory.class));
- install(new FactoryModuleBuilder()
- .implement(Car.class, Golf.class)
- .build(ColoredCarFactory.class));
- }
- });
- injector.getInstance(ColoredCarFactory.class);
- fail();
- } catch (CreationException ce) {
- assertContains(ce.getMessage(),
- "A binding to " + ColoredCarFactory.class.getName() + " was already configured");
- assertEquals(1, ce.getErrorMessages().size());
- }
- }
- public void testMultipleReturnTypes() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(Double.class).toInstance(5.0d);
- install(new FactoryModuleBuilder().build(VersatileCarFactory.class));
- }
- });
- VersatileCarFactory factory = injector.getInstance(VersatileCarFactory.class);
- Mustang mustang = factory.getMustang(Color.RED);
- assertEquals(Color.RED, mustang.color);
- Beetle beetle = factory.getBeetle(Color.GREEN);
- assertEquals(Color.GREEN, beetle.color);
- }
-
- public void testParameterizedClassesWithNoImplements() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder().build(new TypeLiteral<Foo.Factory<String>>() {}));
- }
- });
-
- Foo.Factory<String> factory = injector.getInstance(Key.get(new TypeLiteral<Foo.Factory<String>>() {}));
- @SuppressWarnings("unused")
- Foo<String> foo = factory.create(new Bar());
- }
-
- public void testGenericErrorMessageMakesSense() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder().build(Key.get(Foo.Factory.class)));
- }
- });
- fail();
- } catch(CreationException ce ) {
- // Assert not only that it's the correct message, but also that it's the *only* message.
- Collection<Message> messages = ce.getErrorMessages();
- assertEquals(
- Foo.Factory.class.getName() + " cannot be used as a key; It is not fully specified.",
- Iterables.getOnlyElement(messages).getMessage());
- }
- }
- interface Car {}
- interface Volkswagen extends Car {}
- interface ColoredCarFactory {
- Car create(Color color);
- }
- interface MustangFactory {
- Mustang create(Color color);
- }
- interface VersatileCarFactory {
- Mustang getMustang(Color color);
- Beetle getBeetle(Color color);
- }
- interface AnnotatedVersatileCarFactory {
- @Named("german") Car getGermanCar(Color color);
- @Named("american") Car getAmericanCar(Color color);
- }
- public static class Golf implements Volkswagen {}
- public static class Mustang implements Car {
- private final Color color;
- @Inject
- public Mustang(@Assisted Color color) {
- this.color = color;
- }
- }
- public static class Beetle implements Car {
- private final Color color;
- @Inject
- public Beetle(@Assisted Color color) {
- this.color = color;
- }
- }
-
- public static class Foo<E> {
- static interface Factory<E> {
- Foo<E> create(Bar bar);
- }
- @SuppressWarnings("unused")
- @Inject Foo(@Assisted Bar bar, Baz<E> baz) {}
- }
-
- public static class Bar {}
- @SuppressWarnings("unused")
- public static class Baz<E> {}
-
- abstract static class AbstractCar implements Car {}
- interface ColoredAbstractCarFactory {
- AbstractCar create(Color color);
- }
- public static class ArtCar extends AbstractCar {}
-
- public void testFactoryBindingDependencies() {
- // validate dependencies work in all stages & as a raw element,
- // and that dependencies work for methods, fields, constructors,
- // and for @AssistedInject constructors too.
- Module module = new AbstractModule() {
- @Override
- protected void configure() {
- bind(Integer.class).toInstance(42);
- bind(Double.class).toInstance(4.2d);
- bind(Float.class).toInstance(4.2f);
- bind(String.class).annotatedWith(named("dog")).toInstance("dog");
- bind(String.class).annotatedWith(named("cat1")).toInstance("cat1");
- bind(String.class).annotatedWith(named("cat2")).toInstance("cat2");
- bind(String.class).annotatedWith(named("cat3")).toInstance("cat3");
- bind(String.class).annotatedWith(named("arbitrary")).toInstance("fail!");
- install(new FactoryModuleBuilder()
- .implement(Animal.class, Dog.class)
- .build(AnimalHouse.class));
- }
- };
- Set<Key<?>> expectedKeys = ImmutableSet.<Key<?>>of(
- Key.get(Integer.class),
- Key.get(Double.class),
- Key.get(Float.class),
- Key.get(String.class, named("dog")),
- Key.get(String.class, named("cat1")),
- Key.get(String.class, named("cat2")),
- Key.get(String.class, named("cat3"))
- );
-
- Injector injector = Guice.createInjector(module);
- validateDependencies(expectedKeys, injector.getBinding(AnimalHouse.class));
-
- injector = Guice.createInjector(Stage.TOOL, module);
- validateDependencies(expectedKeys, injector.getBinding(AnimalHouse.class));
-
- List<Element> elements = Elements.getElements(module);
- boolean found = false;
- for(Element element : elements) {
- if(element instanceof Binding) {
- Binding<?> binding = (Binding<?>) element;
- if(binding.getKey().equals(Key.get(AnimalHouse.class))) {
- found = true;
- validateDependencies(expectedKeys, binding);
- break;
- }
- }
- }
- assertTrue(found);
- }
-
- private void validateDependencies(Set<Key<?>> expectedKeys, Binding<?> binding) {
- Set<Dependency<?>> dependencies = ((HasDependencies)binding).getDependencies();
- Set<Key<?>> actualKeys = new HashSet<Key<?>>();
- for (Dependency<?> dependency : dependencies) {
- actualKeys.add(dependency.getKey());
- }
- assertEquals(expectedKeys, actualKeys);
- }
-
- interface AnimalHouse {
- Animal createAnimal(String name);
- Cat createCat(String name);
- Cat createCat(int age);
- }
-
- interface Animal {}
- @SuppressWarnings("unused")
- private static class Dog implements Animal {
- @Inject int a;
- @Inject Dog(@Assisted String a, double b) {}
- @Inject void register(@Named("dog") String a) {}
- }
- @SuppressWarnings("unused")
- private static class Cat implements Animal {
- @Inject float a;
- @AssistedInject Cat(@Assisted String a, @Named("cat1") String b) {}
- @AssistedInject Cat(@Assisted int a, @Named("cat2") String b) {}
- @AssistedInject Cat(@Assisted byte a, @Named("catfail") String b) {} // not a dependency!
- @Inject void register(@Named("cat3") String a) {}
- }
-
- public void testFactoryPublicAndReturnTypeNotPublic() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder()
- .implement(Hidden.class, HiddenImpl.class)
- .build(NotHidden.class));
- }
- });
- } catch(CreationException ce) {
- assertEquals(NotHidden.class.getName() + " is public, but has a method that returns a non-public type: "
- + Hidden.class.getName() + ". Due to limitations with java.lang.reflect.Proxy, this is not allowed. "
- + "Please either make the factory non-public or the return type public.",
- Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
- }
- }
-
- interface Hidden {}
- public static class HiddenImpl implements Hidden {}
- public interface NotHidden {
- Hidden create();
- }
-
- public void testSingletonScopeOnAssistedClassIsIgnored() {
- try {
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- install(new FactoryModuleBuilder().build(SingletonFactory.class));
- }
- });
- fail();
- } catch (CreationException ce) {
- assertEquals(1, ce.getErrorMessages().size());
- assertEquals("Found scope annotation [" + Singleton.class.getName() + "]"
- + " on implementation class [" + AssistedSingleton.class.getName() + "]"
- + " of AssistedInject factory [" + SingletonFactory.class.getName() + "]."
- + "\nThis is not allowed, please remove the scope annotation.",
- Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
- }
- }
-
- interface SingletonFactory {
- AssistedSingleton create(String string);
- }
- @SuppressWarnings("GuiceAssistedInjectScoping")
- @Singleton
- static class AssistedSingleton {
- @Inject
- public AssistedSingleton(@SuppressWarnings("unused") @Assisted String string) {
- }
- }
-
- }