blob: dfe05f260dc10f3630c4bdb9a2a75c55da98a0ae [file] [log] [blame]
/**
* 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.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
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.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++;
}
}
}