/** * 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.assistedinject; import static com.google.inject.name.Names.named; import com.google.inject.AbstractModule; import com.google.inject.Binding; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Stage; import com.google.inject.internal.util.ImmutableList; import com.google.inject.internal.util.ImmutableSet; import com.google.inject.internal.util.Iterables; import com.google.inject.internal.util.Lists; import com.google.inject.name.Named; import com.google.inject.spi.DefaultBindingTargetVisitor; import com.google.inject.spi.Dependency; import com.google.inject.spi.Element; import com.google.inject.spi.Elements; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import java.util.List; import java.util.Set; import java.util.logging.Logger; /** * Tests for AssistedInject Spi. * * @author ramakrishna@google.com (Ramakrishna Rajanna) */ public class ExtensionSpiTest extends TestCase { public final void testSpiOnElements() throws Exception { AssistedInjectSpiVisitor visitor = new AssistedInjectSpiVisitor(); Integer count = 0; for(Element element : Elements.getElements(new Module())) { if(element instanceof Binding) { assertEquals(count++, ((Binding<?>)element).acceptTargetVisitor(visitor)); } } validateVisitor(visitor); } public void testSpiOnVisitor() throws Exception { AssistedInjectSpiVisitor visitor = new AssistedInjectSpiVisitor(); Integer count = 0; Injector injector = Guice.createInjector(new Module()); for(Binding<?> binding : injector.getBindings().values()) { assertEquals(count++, binding.acceptTargetVisitor(visitor)); } validateVisitor(visitor); } private void validateVisitor(AssistedInjectSpiVisitor visitor) throws Exception { assertEquals(1, visitor.assistedBindingCount); List<AssistedMethod> assistedMethods = Lists.newArrayList(Iterables.getOnlyElement( visitor.assistedInjectBindings).getAssistedMethods()); assertEquals(7, assistedMethods.size()); assertEquals(1, visitor.assistedBindingCount); assertEquals(1, visitor.assistedInjectBindings.size()); // Validate for each of the methods in AnimalFactory validateCreateAStrangeCatAsAnimal(assistedMethods.get(0)); validatecreateStrangeCatWithConstructorForOwner(assistedMethods.get(1)); validatecreateStrangeCatWithConstructorForAge(assistedMethods.get(2)); validateCreateCatWithANonAssistedDependency(assistedMethods.get(3)); validateCreateCat(assistedMethods.get(4)); validateCreateASimpleCatAsAnimal(assistedMethods.get(5)); validateCreateCatWithNonAssistedDependencies(assistedMethods.get(6)); } private void validateCreateAStrangeCatAsAnimal(AssistedMethod assistedMethod) { validateAssistedMethod(assistedMethod, "createAStrangeCatAsAnimal", StrangeCat.class, ImmutableList.<Key<?>>of()); } private void validatecreateStrangeCatWithConstructorForOwner(AssistedMethod assistedMethod) { validateAssistedMethod(assistedMethod, "createStrangeCatWithConstructorForOwner", StrangeCat.class, ImmutableList.<Key<?>>of()); } private void validatecreateStrangeCatWithConstructorForAge(AssistedMethod assistedMethod) { validateAssistedMethod(assistedMethod, "createStrangeCatWithConstructorForAge", StrangeCat.class, ImmutableList.<Key<?>>of()); } private void validateCreateCatWithANonAssistedDependency(AssistedMethod assistedMethod) throws Exception { validateAssistedMethod(assistedMethod, "createCatWithANonAssistedDependency", CatWithAName.class, ImmutableList.<Key<?>>of(Key.get(String.class, named("catName2")))); } private void validateCreateCat(AssistedMethod assistedMethod) throws Exception { validateAssistedMethod(assistedMethod, "createCat", Cat.class, ImmutableList.<Key<?>>of()); } private void validateCreateASimpleCatAsAnimal(AssistedMethod assistedMethod) { validateAssistedMethod(assistedMethod, "createASimpleCatAsAnimal", SimpleCat.class, ImmutableList.<Key<?>>of()); } private void validateCreateCatWithNonAssistedDependencies(AssistedMethod assistedMethod) { List<Key<?>> dependencyKeys = ImmutableList.<Key<?>>of( Key.get(String.class, named("catName1")), Key.get(String.class, named("petName")), Key.get(Integer.class, named("age"))); validateAssistedMethod(assistedMethod, "createCatWithNonAssistedDependencies", ExplodingCat.class, dependencyKeys); } private void validateAssistedMethod(AssistedMethod assistedMethod, String factoryMethodName, Class clazz, List<Key<?>> dependencyKeys){ assertEquals(factoryMethodName, assistedMethod.getFactoryMethod().getName()); assertEquals(clazz, assistedMethod.getImplementationConstructor().getDeclaringClass()); assertEquals(dependencyKeys.size(), assistedMethod.getDependencies().size()); for (Dependency<?> dependency : assistedMethod.getDependencies()) { assertTrue(dependencyKeys.contains(dependency.getKey())); } assertEquals(clazz, assistedMethod.getImplementationType().getType()); } interface AnimalFactory { Cat createCat(String owner); CatWithAName createCatWithANonAssistedDependency(String owner); @Named("SimpleCat") Animal createASimpleCatAsAnimal(String owner); Animal createAStrangeCatAsAnimal(String owner); StrangeCat createStrangeCatWithConstructorForOwner(String owner); StrangeCat createStrangeCatWithConstructorForAge(Integer age); ExplodingCat createCatWithNonAssistedDependencies(String owner); } interface Animal {} private static class Cat implements Animal { @Inject Cat(@Assisted String owner) {} } private static class SimpleCat implements Animal { @Inject SimpleCat(@Assisted String owner) { } } private static class StrangeCat implements Animal { @AssistedInject StrangeCat(@Assisted String owner) {} @AssistedInject StrangeCat(@Assisted Integer age) {} } private static class ExplodingCat implements Animal { @Inject public ExplodingCat(@Named("catName1") String name, @Assisted String owner, @Named("age") Integer age, @Named("petName") String petName) {} } private static class CatWithAName extends Cat { @Inject CatWithAName(@Assisted String owner, @Named("catName2") String name) { super(owner); } } public class Module extends AbstractModule{ @Override protected void configure() { bind(String.class).annotatedWith(named("catName1")).toInstance("kitty1"); bind(String.class).annotatedWith(named("catName2")).toInstance("kitty2"); bind(String.class).annotatedWith(named("petName")).toInstance("pussy"); bind(Integer.class).annotatedWith(named("age")).toInstance(12); install(new FactoryModuleBuilder() .implement(Animal.class, StrangeCat.class) .implement(Animal.class, named("SimpleCat"), SimpleCat.class) .build(AnimalFactory.class)); } } public class AssistedInjectSpiVisitor extends DefaultBindingTargetVisitor<Object, Integer> implements AssistedInjectTargetVisitor<Object, Integer> { private final Set<Class> allowedClasses = ImmutableSet.<Class> of( Injector.class, Stage.class, Logger.class, String.class, Integer.class); private int assistedBindingCount = 0; private int currentCount = 0; private List<AssistedInjectBinding<?>> assistedInjectBindings = Lists.newArrayList(); public Integer visit(AssistedInjectBinding assistedInjectBinding) { assistedInjectBindings.add(assistedInjectBinding); assistedBindingCount++; return currentCount++; } @Override protected Integer visitOther(Binding<? extends Object> binding) { if(!allowedClasses.contains(binding.getKey().getTypeLiteral().getRawType())) { throw new AssertionFailedError("invalid other binding: " + binding); } return currentCount++; } } }