blob: a83e8a5c92bf4a8ce13c7ffc9874fa0fad975353 [file] [log] [blame]
/**
* Copyright (C) 2006 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;
import static com.google.inject.Asserts.assertContains;
import static com.google.inject.Asserts.assertNotSerializable;
import java.io.IOException;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import junit.framework.TestCase;
/**
* @author crazybob@google.com (Bob Lee)
*/
public class InjectorTest extends TestCase {
@Retention(RUNTIME)
@BindingAnnotation @interface Other {}
@Retention(RUNTIME)
@BindingAnnotation @interface S {}
@Retention(RUNTIME)
@BindingAnnotation @interface I {}
public void testToStringDoesNotInfinitelyRecurse() {
Injector injector = Guice.createInjector(Stage.TOOL);
injector.toString();
injector.getBinding(Injector.class).toString();
}
public void testProviderMethods() throws CreationException {
final SampleSingleton singleton = new SampleSingleton();
final SampleSingleton other = new SampleSingleton();
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(SampleSingleton.class).toInstance(singleton);
bind(SampleSingleton.class)
.annotatedWith(Other.class)
.toInstance(other);
}
});
assertSame(singleton,
injector.getInstance(Key.get(SampleSingleton.class)));
assertSame(singleton, injector.getInstance(SampleSingleton.class));
assertSame(other,
injector.getInstance(Key.get(SampleSingleton.class, Other.class)));
}
static class SampleSingleton {}
public void testInjection() throws CreationException {
Injector injector = createFooInjector();
Foo foo = injector.getInstance(Foo.class);
assertEquals("test", foo.s);
assertEquals("test", foo.bar.getTee().getS());
assertSame(foo.bar, foo.copy);
assertEquals(5, foo.i);
assertEquals(5, foo.bar.getI());
// Test circular dependency.
assertSame(foo.bar, foo.bar.getTee().getBar());
}
private Injector createFooInjector() throws CreationException {
return Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(Bar.class).to(BarImpl.class);
bind(Tee.class).to(TeeImpl.class);
bindConstant().annotatedWith(S.class).to("test");
bindConstant().annotatedWith(I.class).to(5);
}
});
}
public void testGetInstance() throws CreationException {
Injector injector = createFooInjector();
Bar bar = injector.getInstance(Key.get(Bar.class));
assertEquals("test", bar.getTee().getS());
assertEquals(5, bar.getI());
}
public void testIntAndIntegerAreInterchangeable()
throws CreationException {
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(I.class).to(5);
}
});
IntegerWrapper iw = injector.getInstance(IntegerWrapper.class);
assertEquals(5, (int) iw.i);
}
public void testInjectorApiIsNotSerializable() throws IOException {
Injector injector = Guice.createInjector();
assertNotSerializable(injector);
assertNotSerializable(injector.getProvider(String.class));
assertNotSerializable(injector.getBinding(String.class));
for (Binding<?> binding : injector.getBindings().values()) {
assertNotSerializable(binding);
}
}
static class IntegerWrapper {
@Inject @I Integer i;
}
static class Foo {
@Inject Bar bar;
@Inject Bar copy;
@Inject @S String s;
int i;
@Inject
void setI(@I int i) {
this.i = i;
}
}
interface Bar {
Tee getTee();
int getI();
}
@Singleton
static class BarImpl implements Bar {
@Inject @I int i;
Tee tee;
@Inject
void initialize(Tee tee) {
this.tee = tee;
}
public Tee getTee() {
return tee;
}
public int getI() {
return i;
}
}
interface Tee {
String getS();
Bar getBar();
}
static class TeeImpl implements Tee {
final String s;
@Inject Bar bar;
@Inject
TeeImpl(@S String s) {
this.s = s;
}
public String getS() {
return s;
}
public Bar getBar() {
return bar;
}
}
public void testInjectStatics() throws CreationException {
Guice.createInjector(new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(S.class).to("test");
bindConstant().annotatedWith(I.class).to(5);
requestStaticInjection(Static.class);
}
});
assertEquals("test", Static.s);
assertEquals(5, Static.i);
}
static class Static {
@Inject @I static int i;
static String s;
@Inject static void setS(@S String s) {
Static.s = s;
}
}
public void testPrivateInjection() throws CreationException {
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(String.class).toInstance("foo");
bind(int.class).toInstance(5);
}
});
Private p = injector.getInstance(Private.class);
assertEquals("foo", p.fromConstructor);
assertEquals(5, p.fromMethod);
}
static class Private {
String fromConstructor;
int fromMethod;
@Inject
private Private(String fromConstructor) {
this.fromConstructor = fromConstructor;
}
@Inject
private void setInt(int i) {
this.fromMethod = i;
}
}
public void testProtectedInjection() throws CreationException {
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(String.class).toInstance("foo");
bind(int.class).toInstance(5);
}
});
Protected p = injector.getInstance(Protected.class);
assertEquals("foo", p.fromConstructor);
assertEquals(5, p.fromMethod);
}
static class Protected {
String fromConstructor;
int fromMethod;
@Inject
protected Protected(String fromConstructor) {
this.fromConstructor = fromConstructor;
}
@Inject
protected void setInt(int i) {
this.fromMethod = i;
}
}
public void testInstanceInjectionHappensAfterFactoriesAreSetUp() {
Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(Object.class).toInstance(new Object() {
@Inject Runnable r;
});
bind(Runnable.class).to(MyRunnable.class);
}
});
}
public void testSubtypeNotProvided() {
try {
Guice.createInjector().getInstance(Money.class);
fail();
} catch (ProvisionException expected) {
assertContains(expected.getMessage(),
Tree.class.getName() + " doesn't provide instances of " + Money.class.getName(),
"while locating ", Tree.class.getName(),
"while locating ", Money.class.getName());
}
}
public void testNotASubtype() {
try {
Guice.createInjector().getInstance(PineTree.class);
fail();
} catch (ConfigurationException expected) {
assertContains(expected.getMessage(),
Tree.class.getName() + " doesn't extend " + PineTree.class.getName(),
"while locating ", PineTree.class.getName());
}
}
public void testRecursiveImplementationType() {
try {
Guice.createInjector().getInstance(SeaHorse.class);
fail();
} catch (ConfigurationException expected) {
assertContains(expected.getMessage(),
"@ImplementedBy points to the same class it annotates.",
"while locating ", SeaHorse.class.getName());
}
}
public void testRecursiveProviderType() {
try {
Guice.createInjector().getInstance(Chicken.class);
fail();
} catch (ConfigurationException expected) {
assertContains(expected.getMessage(),
"@ProvidedBy points to the same class it annotates",
"while locating ", Chicken.class.getName());
}
}
static class MyRunnable implements Runnable {
public void run() {}
}
@ProvidedBy(Tree.class)
static class Money {}
static class Tree implements Provider<Object> {
public Object get() {
return "Money doesn't grow on trees";
}
}
@ImplementedBy(Tree.class)
static class PineTree extends Tree {}
@ImplementedBy(SeaHorse.class)
static class SeaHorse {}
@ProvidedBy(Chicken.class)
static class Chicken implements Provider<Chicken> {
public Chicken get() {
return this;
}
}
public void testJitBindingFromAnotherThreadDuringInjection() {
final ExecutorService executorService = Executors.newSingleThreadExecutor();
final AtomicReference<JustInTime> got = new AtomicReference<JustInTime>();
Guice.createInjector(new AbstractModule() {
protected void configure() {
requestInjection(new Object() {
@Inject void initialize(final Injector injector)
throws ExecutionException, InterruptedException {
Future<JustInTime> future = executorService.submit(new Callable<JustInTime>() {
public JustInTime call() throws Exception {
return injector.getInstance(JustInTime.class);
}
});
got.set(future.get());
}
});
}
});
assertNotNull(got.get());
}
static class JustInTime {}
}