blob: c7fccc33f91317d852f7097b86942b0453dcfedb [file] [log] [blame]
/**
* 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.assistedinject;
import static com.google.inject.Asserts.assertContains;
import static com.google.inject.Asserts.assertEqualsBothWays;
import com.google.inject.AbstractModule;
import com.google.inject.ConfigurationException;
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.Provider;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.Matchers;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import junit.framework.TestCase;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@SuppressWarnings("deprecation")
public class FactoryProvider2Test extends TestCase {
private enum Color { BLUE, GREEN, RED, GRAY, BLACK, ORANGE, PINK }
public void testAssistedFactory() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Double.class).toInstance(5.0d);
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Mustang blueMustang = (Mustang) carFactory.create(Color.BLUE);
assertEquals(Color.BLUE, blueMustang.color);
assertEquals(5.0d, blueMustang.engineSize);
Mustang redMustang = (Mustang) carFactory.create(Color.RED);
assertEquals(Color.RED, redMustang.color);
assertEquals(5.0d, redMustang.engineSize);
}
public void testAssistedFactoryWithAnnotations() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Camaro.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Camaro blueCamaro = (Camaro) carFactory.create(Color.BLUE);
assertEquals(Color.BLUE, blueCamaro.color);
assertEquals(1984, blueCamaro.modelYear);
assertEquals(250, blueCamaro.horsePower);
Camaro redCamaro = (Camaro) carFactory.create(Color.RED);
assertEquals(Color.RED, redCamaro.color);
assertEquals(1984, redCamaro.modelYear);
assertEquals(250, redCamaro.horsePower);
}
public interface Car {}
interface ColoredCarFactory {
Car create(Color color);
}
public static class Mustang implements Car {
private final double engineSize;
private final Color color;
@Inject
public Mustang(double engineSize, @Assisted Color color) {
this.engineSize = engineSize;
this.color = color;
}
public void drive() {}
}
public static class Camaro implements Car {
private final int horsePower;
private final int modelYear;
private final Color color;
@Inject
public Camaro(
@Named("horsePower") int horsePower,
@Named("modelYear") int modelYear,
@Assisted Color color) {
this.horsePower = horsePower;
this.modelYear = modelYear;
this.color = color;
}
}
interface SummerCarFactory {
Car create(Color color, boolean convertable);
}
public void testFactoryUsesInjectedConstructor() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(float.class).toInstance(140f);
bind(SummerCarFactory.class).toProvider(
FactoryProvider.newFactory(SummerCarFactory.class, Corvette.class));
}
});
SummerCarFactory carFactory = injector.getInstance(SummerCarFactory.class);
Corvette redCorvette = (Corvette) carFactory.create(Color.RED, false);
assertEquals(Color.RED, redCorvette.color);
assertEquals(140f, redCorvette.maxMph);
assertFalse(redCorvette.isConvertable);
}
public static class Corvette implements Car {
private boolean isConvertable;
private Color color;
private float maxMph;
public Corvette(Color color, boolean isConvertable) {
throw new IllegalStateException("Not an @AssistedInject constructor");
}
@Inject
public Corvette(@Assisted Color color, Float maxMph, @Assisted boolean isConvertable) {
this.isConvertable = isConvertable;
this.color = color;
this.maxMph = maxMph;
}
}
public void testConstructorDoesntNeedAllFactoryMethodArguments() {
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(SummerCarFactory.class).toProvider(
FactoryProvider.newFactory(SummerCarFactory.class, Beetle.class));
}
});
SummerCarFactory factory = injector.getInstance(SummerCarFactory.class);
Beetle beetle = (Beetle) factory.create(Color.RED, true);
assertSame(Color.RED, beetle.color);
}
public static class Beetle implements Car {
private final Color color;
@Inject
public Beetle(@Assisted Color color) {
this.color = color;
}
}
public void testMethodsAndFieldsGetInjected() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(String.class).toInstance("turbo");
bind(int.class).toInstance(911);
bind(double.class).toInstance(50000d);
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Porsche.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Porsche grayPorsche = (Porsche) carFactory.create(Color.GRAY);
assertEquals(Color.GRAY, grayPorsche.color);
assertEquals(50000d, grayPorsche.price);
assertEquals(911, grayPorsche.model);
assertEquals("turbo", grayPorsche.name);
}
public static class Porsche implements Car {
private final Color color;
private final double price;
private @Inject String name;
private int model;
@Inject
public Porsche(@Assisted Color color, double price) {
this.color = color;
this.price = price;
}
@Inject void setModel(int model) {
this.model = model;
}
}
public void testProviderInjection() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(String.class).toInstance("trans am");
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Firebird.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Firebird blackFirebird = (Firebird) carFactory.create(Color.BLACK);
assertEquals(Color.BLACK, blackFirebird.color);
assertEquals("trans am", blackFirebird.modifiersProvider.get());
}
public static class Firebird implements Car {
private final Provider<String> modifiersProvider;
private final Color color;
@Inject
public Firebird(Provider<String> modifiersProvider, @Assisted Color color) {
this.modifiersProvider = modifiersProvider;
this.color = color;
}
}
public void testAssistedProviderInjection() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(String.class).toInstance("trans am");
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Flamingbird.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Flamingbird flamingbird = (Flamingbird) carFactory.create(Color.BLACK);
assertEquals(Color.BLACK, flamingbird.colorProvider.get());
assertEquals("trans am", flamingbird.modifiersProvider.get());
Flamingbird flamingbird2 = (Flamingbird) carFactory.create(Color.RED);
assertEquals(Color.RED, flamingbird2.colorProvider.get());
assertEquals("trans am", flamingbird2.modifiersProvider.get());
// Make sure the original flamingbird is black still.
assertEquals(Color.BLACK, flamingbird.colorProvider.get());
}
public static class Flamingbird implements Car {
private final Provider<String> modifiersProvider;
private final Provider<Color> colorProvider;
@Inject
public Flamingbird(Provider<String> modifiersProvider, @Assisted Provider<Color> colorProvider) {
this.modifiersProvider = modifiersProvider;
this.colorProvider = colorProvider;
}
}
public void testTypeTokenInjection() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(new TypeLiteral<Set<String>>() {}).toInstance(Collections.singleton("Flux Capacitor"));
bind(new TypeLiteral<Set<Integer>>() {}).toInstance(Collections.singleton(88));
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, DeLorean.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
DeLorean deLorean = (DeLorean) carFactory.create(Color.GRAY);
assertEquals(Color.GRAY, deLorean.color);
assertEquals("Flux Capacitor", deLorean.features.iterator().next());
assertEquals(new Integer(88), deLorean.featureActivationSpeeds.iterator().next());
}
public static class DeLorean implements Car {
private final Set<String> features;
private final Set<Integer> featureActivationSpeeds;
private final Color color;
@Inject
public DeLorean(
Set<String> extraFeatures, Set<Integer> featureActivationSpeeds, @Assisted Color color) {
this.features = extraFeatures;
this.featureActivationSpeeds = featureActivationSpeeds;
this.color = color;
}
}
public void testTypeTokenProviderInjection() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(new TypeLiteral<Set<String>>() { }).toInstance(Collections.singleton("Datsun"));
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Z.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Z orangeZ = (Z) carFactory.create(Color.ORANGE);
assertEquals(Color.ORANGE, orangeZ.color);
assertEquals("Datsun", orangeZ.manufacturersProvider.get().iterator().next());
}
public static class Z implements Car {
private final Provider<Set<String>> manufacturersProvider;
private final Color color;
@Inject
public Z(Provider<Set<String>> manufacturersProvider, @Assisted Color color) {
this.manufacturersProvider = manufacturersProvider;
this.color = color;
}
}
public static class Prius implements Car {
final Color color;
@Inject
private Prius(@Assisted Color color) {
this.color = color;
}
}
public void testAssistInjectionInNonPublicConstructor() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Prius.class));
}
});
Prius prius = (Prius) injector.getInstance(ColoredCarFactory.class).create(Color.ORANGE);
assertEquals(prius.color, Color.ORANGE);
}
public static class ExplodingCar implements Car {
@Inject
public ExplodingCar(@Assisted Color color) {
throw new IllegalStateException("kaboom!");
}
}
public void testExceptionDuringConstruction() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, ExplodingCar.class));
}
});
try {
injector.getInstance(ColoredCarFactory.class).create(Color.ORANGE);
fail();
} catch (IllegalStateException e) {
assertEquals("kaboom!", e.getMessage());
}
}
public static class DefectiveCar implements Car {
@Inject
public DefectiveCar() throws ExplosionException, FireException {
throw new ExplosionException();
}
}
public static class ExplosionException extends Exception { }
public static class FireException extends Exception { }
public interface DefectiveCarFactoryWithNoExceptions {
Car createCar();
}
public interface DefectiveCarFactory {
Car createCar() throws FireException;
}
public interface CorrectDefectiveCarFactory {
Car createCar() throws FireException, ExplosionException;
}
public void testConstructorExceptionsAreThrownByFactory() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(CorrectDefectiveCarFactory.class).toProvider(
FactoryProvider.newFactory(CorrectDefectiveCarFactory.class, DefectiveCar.class));
}
});
try {
injector.getInstance(CorrectDefectiveCarFactory.class).createCar();
fail();
} catch (FireException e) {
fail();
} catch (ExplosionException expected) {
}
}
public static class WildcardCollection {
public interface Factory {
WildcardCollection create(Collection<?> items);
}
@Inject
public WildcardCollection(@Assisted Collection<?> items) { }
}
public void testWildcardGenerics() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(WildcardCollection.Factory.class).toProvider(
FactoryProvider.newFactory(WildcardCollection.Factory.class, WildcardCollection.class));
}
});
WildcardCollection.Factory factory = injector.getInstance(WildcardCollection.Factory.class);
factory.create(Collections.emptyList());
}
public static class SteeringWheel {}
public static class Fiat implements Car {
private final SteeringWheel steeringWheel;
private final Color color;
@Inject
public Fiat(SteeringWheel steeringWheel, @Assisted Color color) {
this.steeringWheel = steeringWheel;
this.color = color;
}
}
public void testFactoryWithImplicitBindings() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Fiat.class));
}
});
ColoredCarFactory coloredCarFactory = injector.getInstance(ColoredCarFactory.class);
Fiat fiat = (Fiat) coloredCarFactory.create(Color.GREEN);
assertEquals(Color.GREEN, fiat.color);
assertNotNull(fiat.steeringWheel);
}
public void testFactoryFailsWithMissingBinding() {
try {
Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
}
});
fail();
} catch (CreationException expected) {
assertContains(expected.getMessage(),
"Could not find a suitable constructor in java.lang.Double.",
"at " + ColoredCarFactory.class.getName() + ".create(FactoryProvider2Test.java");
}
}
public void testFactoryFailsWithMissingBindingInToolStage() {
try {
Guice.createInjector(Stage.TOOL, new AbstractModule() {
@Override protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
}
});
fail();
} catch (CreationException expected) {
assertContains(expected.getMessage(),
"Could not find a suitable constructor in java.lang.Double.",
"at " + ColoredCarFactory.class.getName() + ".create(FactoryProvider2Test.java");
}
}
public void testMethodsDeclaredInObject() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(Double.class).toInstance(5.0d);
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
assertEqualsBothWays(carFactory, carFactory);
}
static class Subaru implements Car {
@Inject @Assisted Provider<Color> colorProvider;
}
public void testInjectingProviderOfParameter() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Subaru subaru = (Subaru) carFactory.create(Color.RED);
assertSame(Color.RED, subaru.colorProvider.get());
assertSame(Color.RED, subaru.colorProvider.get());
Subaru sedan = (Subaru) carFactory.create(Color.BLUE);
assertSame(Color.BLUE, sedan.colorProvider.get());
assertSame(Color.BLUE, sedan.colorProvider.get());
// and make sure the subaru is still red
assertSame(Color.RED, subaru.colorProvider.get());
}
public void testInjectingNullParameter() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Subaru subaru = (Subaru) carFactory.create(null);
assertNull(subaru.colorProvider.get());
assertNull(subaru.colorProvider.get());
}
interface ProviderBasedColoredCarFactory {
Car createCar(Provider<Color> colorProvider, Provider<String> stringProvider);
Mustang createMustang(@Assisted("color") Provider<Color> colorProvider);
}
public void testAssistedProviderIsDisallowed() {
try {
Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(ProviderBasedColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ProviderBasedColoredCarFactory.class, Subaru.class));
}
});
fail();
} catch (CreationException expected) {
assertEquals(expected.getMessage(), 4, expected.getErrorMessages().size());
// Assert each method individually, because JDK7 doesn't guarantee method ordering.
assertContains(expected.getMessage(),
") A Provider may not be a type in a factory method of an AssistedInject."
+ "\n Offending instance is parameter [1] with key"
+ " [com.google.inject.Provider<" + Color.class.getName() + ">] on method ["
+ ProviderBasedColoredCarFactory.class.getName() + ".createCar()]");
assertContains(expected.getMessage(),
") A Provider may not be a type in a factory method of an AssistedInject."
+ "\n Offending instance is parameter [2] with key"
+ " [com.google.inject.Provider<java.lang.String>] on method ["
+ ProviderBasedColoredCarFactory.class.getName() + ".createCar()]");
assertContains(expected.getMessage(),
") A Provider may not be a type in a factory method of an AssistedInject."
+ "\n Offending instance is parameter [1] with key"
+ " [com.google.inject.Provider<" + Color.class.getName() + ">"
+ " annotated with @com.google.inject.assistedinject.Assisted(value=color)]"
+ " on method [" + ProviderBasedColoredCarFactory.class.getName() + ".createMustang()]"
);
assertContains(expected.getMessage(),
") No implementation for com.google.inject.assistedinject."
+ "FactoryProvider2Test$ProviderBasedColoredCarFactory was bound.");
}
}
interface JavaxProviderBasedColoredCarFactory {
Car createCar(javax.inject.Provider<Color> colorProvider, javax.inject.Provider<String> stringProvider);
Mustang createMustang(@Assisted("color") javax.inject.Provider<Color> colorProvider);
}
public void testAssistedJavaxProviderIsDisallowed() {
try {
Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(JavaxProviderBasedColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(JavaxProviderBasedColoredCarFactory.class, Subaru.class));
}
});
fail();
} catch (CreationException expected) {
assertEquals(expected.getMessage(), 4, expected.getErrorMessages().size());
assertContains(expected.getMessage(),
") A Provider may not be a type in a factory method of an AssistedInject."
+ "\n Offending instance is parameter [1] with key"
+ " [com.google.inject.Provider<" + Color.class.getName() + ">] on method ["
+ JavaxProviderBasedColoredCarFactory.class.getName() + ".createCar()]");
assertContains(expected.getMessage(),
") A Provider may not be a type in a factory method of an AssistedInject."
+ "\n Offending instance is parameter [2] with key"
+ " [com.google.inject.Provider<java.lang.String>] on method ["
+ JavaxProviderBasedColoredCarFactory.class.getName() + ".createCar()]");
assertContains(expected.getMessage(),
") A Provider may not be a type in a factory method of an AssistedInject."
+ "\n Offending instance is parameter [1] with key"
+ " [com.google.inject.Provider<" + Color.class.getName() + ">"
+ " annotated with @com.google.inject.assistedinject.Assisted(value=color)]"
+ " on method [" + JavaxProviderBasedColoredCarFactory.class.getName() + ".createMustang()]"
);
assertContains(expected.getMessage(),
") No implementation for com.google.inject.assistedinject."
+ "FactoryProvider2Test$JavaxProviderBasedColoredCarFactory was bound.");
}
}
public void testFactoryUseBeforeInitialization() {
ColoredCarFactory carFactory = FactoryProvider.newFactory(ColoredCarFactory.class, Subaru.class)
.get();
try {
carFactory.create(Color.RED);
fail();
} catch (IllegalStateException expected) {
assertContains(expected.getMessage(),
"Factories.create() factories cannot be used until they're initialized by Guice.");
}
}
interface MustangFactory {
Mustang create(Color color);
}
public void testFactoryBuildingConcreteTypes() {
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(double.class).toInstance(5.0d);
// note there is no 'thatMakes()' call here:
bind(MustangFactory.class).toProvider(
FactoryProvider.newFactory(MustangFactory.class, Mustang.class));
}
});
MustangFactory factory = injector.getInstance(MustangFactory.class);
Mustang mustang = factory.create(Color.RED);
assertSame(Color.RED, mustang.color);
assertEquals(5.0d, mustang.engineSize);
}
static class Fleet {
@Inject Mustang mustang;
@Inject Camaro camaro;
}
interface FleetFactory {
Fleet createFleet(Color color);
}
public void testInjectDeepIntoConstructedObjects() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(double.class).toInstance(5.0d);
bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
bind(FleetFactory.class).toProvider(FactoryProvider.newFactory(FleetFactory.class,
Fleet.class));
}
});
FleetFactory fleetFactory = injector.getInstance(FleetFactory.class);
Fleet fleet = fleetFactory.createFleet(Color.RED);
assertSame(Color.RED, fleet.mustang.color);
assertEquals(5.0d, fleet.mustang.engineSize);
assertSame(Color.RED, fleet.camaro.color);
assertEquals(250, fleet.camaro.horsePower);
assertEquals(1984, fleet.camaro.modelYear);
}
interface TwoToneCarFactory {
Car create(@Assisted("paint") Color paint, @Assisted("fabric") Color fabric);
}
static class Maxima implements Car {
@Inject @Assisted("paint") Color paint;
@Inject @Assisted("fabric") Color fabric;
}
public void testDistinctKeys() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(TwoToneCarFactory.class).toProvider(
FactoryProvider.newFactory(TwoToneCarFactory.class, Maxima.class));
}
});
TwoToneCarFactory factory = injector.getInstance(TwoToneCarFactory.class);
Maxima maxima = (Maxima) factory.create(Color.BLACK, Color.GRAY);
assertSame(Color.BLACK, maxima.paint);
assertSame(Color.GRAY, maxima.fabric);
}
interface DoubleToneCarFactory {
Car create(@Assisted("paint") Color paint, @Assisted("paint") Color morePaint);
}
public void testDuplicateKeys() {
try {
Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(DoubleToneCarFactory.class).toProvider(
FactoryProvider.newFactory(DoubleToneCarFactory.class, Maxima.class));
}
});
fail();
} catch (CreationException expected) {
assertContains(expected.getMessage(), "A binding to " + Color.class.getName() + " annotated with @"
+ Assisted.class.getName() + "(value=paint) was already configured at");
}
}
/*if[AOP]*/
public void testMethodInterceptorsOnAssistedTypes() {
final AtomicInteger invocationCount = new AtomicInteger();
final org.aopalliance.intercept.MethodInterceptor interceptor
= new org.aopalliance.intercept.MethodInterceptor() {
public Object invoke(org.aopalliance.intercept.MethodInvocation methodInvocation)
throws Throwable {
invocationCount.incrementAndGet();
return methodInvocation.proceed();
}
};
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.any(), interceptor);
bind(Double.class).toInstance(5.0d);
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class));
}
});
ColoredCarFactory factory = injector.getInstance(ColoredCarFactory.class);
Mustang mustang = (Mustang) factory.create(Color.GREEN);
assertEquals(0, invocationCount.get());
mustang.drive();
assertEquals(1, invocationCount.get());
}
/*end[AOP]*/
/**
* Our factories aren't reusable across injectors. Although this behaviour isn't something we
* like, I have a test case to make sure the error message is pretty.
*/
public void testFactoryReuseErrorMessageIsPretty() {
final Provider<ColoredCarFactory> factoryProvider
= FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class);
Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(Double.class).toInstance(5.0d);
bind(ColoredCarFactory.class).toProvider(factoryProvider);
}
});
try {
Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(Double.class).toInstance(5.0d);
bind(ColoredCarFactory.class).toProvider(factoryProvider);
}
});
fail();
} catch(CreationException expected) {
assertContains(expected.getMessage(),
"Factories.create() factories may only be used in one Injector!");
}
}
public void testNonAssistedFactoryMethodParameter() {
try {
FactoryProvider.newFactory(NamedParameterFactory.class, Mustang.class);
fail();
} catch(ConfigurationException expected) {
assertContains(expected.getMessage(),
"Only @Assisted is allowed for factory parameters, but found @" + Named.class.getName());
}
}
interface NamedParameterFactory {
Car create(@Named("seats") int seats, double engineSize);
}
public void testDefaultAssistedAnnotation() throws NoSuchFieldException {
Assisted plainAssisted
= Subaru.class.getDeclaredField("colorProvider").getAnnotation(Assisted.class);
assertEqualsBothWays(FactoryProvider2.DEFAULT_ANNOTATION, plainAssisted);
assertEquals(FactoryProvider2.DEFAULT_ANNOTATION.toString(), plainAssisted.toString());
}
interface GenericColoredCarFactory<T extends Car> {
T create(Color color);
}
public void testGenericAssistedFactory() {
final TypeLiteral<GenericColoredCarFactory<Mustang>> mustangTypeLiteral
= new TypeLiteral<GenericColoredCarFactory<Mustang>>() {};
final TypeLiteral<GenericColoredCarFactory<Camaro>> camaroTypeLiteral
= new TypeLiteral<GenericColoredCarFactory<Camaro>>() {};
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Double.class).toInstance(5.0d);
bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250);
bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984);
bind(mustangTypeLiteral)
.toProvider(FactoryProvider.newFactory(mustangTypeLiteral, TypeLiteral.get(Mustang.class)));
bind(camaroTypeLiteral)
.toProvider(FactoryProvider.newFactory(camaroTypeLiteral, TypeLiteral.get(Camaro.class)));
}
});
GenericColoredCarFactory<Mustang> mustangFactory
= injector.getInstance(Key.get(mustangTypeLiteral));
GenericColoredCarFactory<Camaro> camaroFactory
= injector.getInstance(Key.get(camaroTypeLiteral));
Mustang blueMustang = mustangFactory.create(Color.BLUE);
assertEquals(Color.BLUE, blueMustang.color);
assertEquals(5.0d, blueMustang.engineSize);
Camaro redCamaro = camaroFactory.create(Color.RED);
assertEquals(Color.RED, redCamaro.color);
assertEquals(1984, redCamaro.modelYear);
assertEquals(250, redCamaro.horsePower);
}
public interface Insurance<T extends Car> {
}
public static class MustangInsurance implements Insurance<Mustang> {
private final double premium;
private final double limit;
private Mustang car;
@Inject
public MustangInsurance(@Named("lowLimit") double limit, @Assisted Mustang car,
@Assisted double premium) {
this.premium = premium;
this.limit = limit;
this.car = car;
}
public void sell() {}
}
public static class CamaroInsurance implements Insurance<Camaro> {
private final double premium;
private final double limit;
private Camaro car;
@Inject
public CamaroInsurance(@Named("highLimit") double limit, @Assisted Camaro car,
@Assisted double premium) {
this.premium = premium;
this.limit = limit;
this.car = car;
}
public void sell() {}
}
public interface MustangInsuranceFactory {
public Insurance<Mustang> create(Mustang car, double premium);
}
public interface CamaroInsuranceFactory {
public Insurance<Camaro> create(Camaro car, double premium);
}
public void testAssistedFactoryForConcreteType() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
bind(MustangInsuranceFactory.class).toProvider(
FactoryProvider.newFactory(MustangInsuranceFactory.class, MustangInsurance.class));
bind(CamaroInsuranceFactory.class).toProvider(
FactoryProvider.newFactory(CamaroInsuranceFactory.class, CamaroInsurance.class));
}
});
MustangInsuranceFactory mustangInsuranceFactory =
injector.getInstance(MustangInsuranceFactory.class);
CamaroInsuranceFactory camaroInsuranceFactory =
injector.getInstance(CamaroInsuranceFactory.class);
Mustang mustang = new Mustang(5000d, Color.BLACK);
MustangInsurance mustangPolicy =
(MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
assertEquals(800.0d, mustangPolicy.premium);
assertEquals(50000.0d, mustangPolicy.limit);
Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
CamaroInsurance camaroPolicy = (CamaroInsurance) camaroInsuranceFactory.create(camaro, 800.0d);
assertEquals(800.0d, camaroPolicy.premium);
assertEquals(100000.0d, camaroPolicy.limit);
}
public interface InsuranceFactory<T extends Car> {
public Insurance<T> create(T car, double premium);
}
public void testAssistedFactoryForParameterizedType() {
final TypeLiteral<InsuranceFactory<Mustang>> mustangInsuranceFactoryType =
new TypeLiteral<InsuranceFactory<Mustang>>() {};
final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType =
new TypeLiteral<InsuranceFactory<Camaro>>() {};
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d);
bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d);
bind(mustangInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
mustangInsuranceFactoryType, TypeLiteral.get(MustangInsurance.class)));
bind(camaroInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
camaroInsuranceFactoryType, TypeLiteral.get(CamaroInsurance.class)));
}
});
InsuranceFactory<Mustang> mustangInsuranceFactory =
injector.getInstance(Key.get(mustangInsuranceFactoryType));
InsuranceFactory<Camaro> camaroInsuranceFactory =
injector.getInstance(Key.get(camaroInsuranceFactoryType));
Mustang mustang = new Mustang(5000d, Color.BLACK);
MustangInsurance mustangPolicy =
(MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d);
assertEquals(800.0d, mustangPolicy.premium);
assertEquals(50000.0d, mustangPolicy.limit);
Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
CamaroInsurance camaroPolicy = (CamaroInsurance) camaroInsuranceFactory.create(camaro, 800.0d);
assertEquals(800.0d, camaroPolicy.premium);
assertEquals(100000.0d, camaroPolicy.limit);
}
public static class AutoInsurance<T extends Car> implements Insurance<T> {
private final double premium;
private final double limit;
private final T car;
@Inject
public AutoInsurance(double limit, @Assisted T car, @Assisted double premium) {
this.limit = limit;
this.car = car;
this.premium = premium;
}
public void sell() {}
}
public void testAssistedFactoryForTypeVariableParameters() {
final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType =
new TypeLiteral<InsuranceFactory<Camaro>>() {};
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Double.class).toInstance(50000.0d);
bind(camaroInsuranceFactoryType).toProvider(FactoryProvider.newFactory(
camaroInsuranceFactoryType, new TypeLiteral<AutoInsurance<Camaro>>() {}));
}
});
InsuranceFactory<Camaro> camaroInsuranceFactory =
injector.getInstance(Key.get(camaroInsuranceFactoryType));
Camaro camaro = new Camaro(3000, 1967, Color.BLUE);
AutoInsurance camaroPolicy = (AutoInsurance) camaroInsuranceFactory.create(camaro, 800.0d);
assertEquals(800.0d, camaroPolicy.premium);
assertEquals(50000.0d, camaroPolicy.limit);
assertEquals(camaro, camaroPolicy.car);
}
public void testInjectingAndUsingInjector() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
bind(ColoredCarFactory.class).toProvider(
FactoryProvider.newFactory(ColoredCarFactory.class, Segway.class));
}
});
ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class);
Segway green = (Segway)carFactory.create(Color.GREEN);
assertSame(Color.GREEN, green.getColor());
assertSame(Color.GREEN, green.getColor());
Segway pink = (Segway)carFactory.create(Color.PINK);
assertSame(Color.PINK, pink.getColor());
assertSame(Color.PINK, pink.getColor());
assertSame(Color.GREEN, green.getColor());
}
static class Segway implements Car {
@Inject Injector injector;
Color getColor() { return injector.getInstance(Key.get(Color.class, FactoryProvider2.DEFAULT_ANNOTATION)); }
}
public void testReturnValueMatchesParamValue() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
public void configure() {
install(new FactoryModuleBuilder().build(Delegater.Factory.class));
}
});
Delegater delegate = new Delegater();
Delegater user = injector.getInstance(Delegater.Factory.class).create(delegate);
assertSame(delegate, user.delegate);
}
static class Delegater {
interface Factory {
Delegater create(Delegater delegate);
}
private final Delegater delegate;
@Inject Delegater(@Assisted Delegater delegater) {
this.delegate = delegater;
}
Delegater() {
this.delegate = null;
}
}
}