Author: limpbizkit
Date: Sun Jun 21 10:28:03 2009
New Revision: 1024
Modified:
trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
trunk/test/com/google/inject/BindingTest.java
Log:
New tests for toConstructor().
I found one bug - we were looking for scoping annotations on the bind
source type rather than the bind target type. This is fixed now.
One weird behaviour - @Singleton is per-binding, not per-type. Check the
scoping test for an illustration.
Modified: trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
==============================================================================
--- trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
(original)
+++ trunk/src/com/google/inject/internal/ConstructorBindingImpl.java Sun
Jun 21 10:28:03 2009
@@ -17,8 +17,8 @@
package com.google.inject.internal;
import com.google.inject.Binder;
-import com.google.inject.Key;
import com.google.inject.ConfigurationException;
+import com.google.inject.Key;
import static com.google.inject.internal.Preconditions.checkState;
import static com.google.inject.internal.Annotations.findScopeAnnotation;
import com.google.inject.spi.BindingTargetVisitor;
@@ -76,9 +76,21 @@
errors.cannotInjectInnerClass(rawType);
}
+ errors.throwIfNewErrors(numErrors);
+
+ // Find a constructor annotated @Inject
+ if (constructorInjector == null) {
+ try {
+ constructorInjector =
InjectionPoint.forConstructorOf(key.getTypeLiteral());
+ } catch (ConfigurationException e) {
+ throw errors.merge(e.getErrorMessages()).toException();
+ }
+ }
+
// if no scope is specified, look for a scoping annotation on the
concrete class
if (!scoping.isExplicitlyScoped()) {
- Class<? extends Annotation> scopeAnnotation =
findScopeAnnotation(errors, rawType);
+ Class<?> annotatedType =
constructorInjector.getMember().getDeclaringClass();
+ Class<? extends Annotation> scopeAnnotation =
findScopeAnnotation(errors, annotatedType);
if (scopeAnnotation != null) {
scoping =
Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
injector, errors.withSource(rawType));
@@ -90,15 +102,6 @@
Factory<T> factoryFactory = new Factory<T>();
InternalFactory<? extends T> scopedFactory
= Scoping.scope(key, injector, factoryFactory, scoping);
-
- // Find a constructor annotated @Inject
- if (constructorInjector == null) {
- try {
- constructorInjector =
InjectionPoint.forConstructorOf(key.getTypeLiteral());
- } catch (ConfigurationException e) {
- throw errors.merge(e.getErrorMessages()).toException();
- }
- }
return new ConstructorBindingImpl<T>(
injector, key, source, scopedFactory, scoping, factoryFactory,
constructorInjector);
Modified: trunk/test/com/google/inject/BindingTest.java
==============================================================================
--- trunk/test/com/google/inject/BindingTest.java (original)
+++ trunk/test/com/google/inject/BindingTest.java Sun Jun 21 10:28:03 2009
@@ -17,12 +17,20 @@
package com.google.inject;
import static com.google.inject.Asserts.assertContains;
-import com.google.inject.name.Names;
+import com.google.inject.internal.ImmutableSet;
+import com.google.inject.internal.Sets;
+import com.google.inject.matcher.Matchers;
+import static com.google.inject.name.Names.named;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.spi.TypeListener;
+import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
-import java.lang.reflect.Constructor;
import junit.framework.TestCase;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
/**
* @author [email protected] (Bob Lee)
@@ -69,14 +77,14 @@
// Provider.
bind(Foo.class)
- .annotatedWith(Names.named("provider"))
+ .annotatedWith(named("provider"))
.toProvider(FooProvider.class);
// Class.
bind(Bar.class).in(Scopes.SINGLETON);
// Constant.
- bindConstant().annotatedWith(Names.named("name")).to("Bob");
+ bindConstant().annotatedWith(named("name")).to("Bob");
}
}
@@ -229,36 +237,142 @@
assertEquals(injector, two.anotherT);
}
- public static class C<T> {
- private Stage stage;
- private T t;
- @Inject T anotherT;
+ public void testToConstructorBinding() throws NoSuchMethodException {
+ final Constructor<D> constructor = D.class.getConstructor(Stage.class);
- public C(Stage stage, T t) {
- this.stage = stage;
- this.t = t;
- }
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(Object.class).toConstructor(constructor);
+ }
+ });
- @Inject C() {}
+ D d = (D) injector.getInstance(Object.class);
+ assertEquals(Stage.DEVELOPMENT, d.stage);
}
-
- public void testToConstructorBinding() throws NoSuchMethodException {
+ public void testToConstructorAndMethodInterceptors() throws
NoSuchMethodException {
final Constructor<D> constructor = D.class.getConstructor(Stage.class);
+ final AtomicInteger count = new AtomicInteger();
+ final MethodInterceptor countingInterceptor = new MethodInterceptor() {
+ public Object invoke(MethodInvocation methodInvocation) throws
Throwable {
+ count.incrementAndGet();
+ return methodInvocation.proceed();
+ }
+ };
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(Object.class).toConstructor(constructor);
+ bindInterceptor(Matchers.any(), Matchers.any(),
countingInterceptor);
}
});
D d = (D) injector.getInstance(Object.class);
- assertEquals(Stage.DEVELOPMENT, d.stage);
+ d.hashCode();
+ d.hashCode();
+ assertEquals(2, count.get());
+ }
+
+ public void testInaccessibleConstructor() throws NoSuchMethodException {
+ final Constructor<E> constructor =
E.class.getDeclaredConstructor(Stage.class);
+
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(E.class).toConstructor(constructor);
+ }
+ });
+
+ E e = injector.getInstance(E.class);
+ assertEquals(Stage.DEVELOPMENT, e.stage);
+ }
+
+ public void testToConstructorAndScopes() throws NoSuchMethodException {
+ final Constructor<F> constructor = F.class.getConstructor(Stage.class);
+
+ final Key<Object> d = Key.get(Object.class, named("D")); // default
scoping
+ final Key<Object> s = Key.get(Object.class, named("S")); // singleton
+ final Key<Object> n = Key.get(Object.class, named("N")); // "N"
instances
+ final Key<Object> r = Key.get(Object.class, named("R")); // a regular
binding
+
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(d).toConstructor(constructor);
+ bind(s).toConstructor(constructor).in(Singleton.class);
+ bind(n).toConstructor(constructor).in(Scopes.NO_SCOPE);
+ bind(r).to(F.class);
+ }
+ });
+
+ assertDistinct(injector, 1, d, d, d, d);
+ assertDistinct(injector, 1, s, s, s, s);
+ assertDistinct(injector, 4, n, n, n, n);
+ assertDistinct(injector, 1, r, r, r, r);
+ assertDistinct(injector, 4, d, d, r, r, s, s, n);
+ }
+
+ public void assertDistinct(Injector injector, int expectedCount,
Key<?>... keys) {
+ ImmutableSet.Builder<Object> builder = ImmutableSet.builder();
+ for (Key<?> k : keys) {
+ builder.add(injector.getInstance(k));
+ }
+ assertEquals(expectedCount, builder.build().size());
+ }
+
+ public void testToConstructorSpiData() throws NoSuchMethodException {
+ final Set<TypeLiteral<?>> heardTypes = Sets.newHashSet();
+
+ final Constructor<D> constructor = D.class.getConstructor(Stage.class);
+ final TypeListener listener = new TypeListener() {
+ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>
encounter) {
+ if (!heardTypes.add(type)) {
+ fail("Heard " + type + " multiple times!");
+ }
+ }
+ };
+
+ Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(Object.class).toConstructor(constructor);
+ bind(D.class).toConstructor(constructor);
+ bindListener(Matchers.any(), listener);
+ }
+ });
+
+ assertEquals(ImmutableSet.of(TypeLiteral.get(Stage.class),
TypeLiteral.get(D.class)),
+ heardTypes);
+ }
+
+ public static class C<T> {
+ private Stage stage;
+ private T t;
+ @Inject T anotherT;
+
+ public C(Stage stage, T t) {
+ this.stage = stage;
+ this.t = t;
+ }
+
+ @Inject C() {}
}
public static class D {
Stage stage;
public D(Stage stage) {
+ this.stage = stage;
+ }
+ }
+
+ private static class E {
+ Stage stage;
+ private E(Stage stage) {
+ this.stage = stage;
+ }
+ }
+
+ @Singleton
+ public static class F {
+ Stage stage;
+ @Inject public F(Stage stage) {
this.stage = stage;
}
}
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---