Author: limpbizkit
Date: Sat Jun 20 10:30:23 2009
New Revision: 1022
Modified:
trunk/src/com/google/inject/internal/BindingProcessor.java
trunk/src/com/google/inject/internal/ConstructionContext.java
trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
trunk/src/com/google/inject/internal/ConstructorInjectorStore.java
trunk/src/com/google/inject/internal/InjectorImpl.java
trunk/src/com/google/inject/spi/InjectionPoint.java
trunk/test/com/google/inject/BindingTest.java
Log:
toConstructor() core implementation. This still requires test coverage, and
maybe a review of the API.
Modified: trunk/src/com/google/inject/internal/BindingProcessor.java
==============================================================================
--- trunk/src/com/google/inject/internal/BindingProcessor.java (original)
+++ trunk/src/com/google/inject/internal/BindingProcessor.java Sat Jun 20
10:30:23 2009
@@ -85,6 +85,18 @@
((BindingImpl<?>) command).getScoping(), injector, errors);
command.acceptTargetVisitor(new BindingTargetVisitor<T, Void>() {
+ public Void visit(ConstructorBinding<? extends T> binding) {
+ try {
+ ConstructorBindingImpl<T> onInjector =
ConstructorBindingImpl.create(injector, key,
+ binding.getConstructor(), source, scoping, errors);
+ scheduleInitialization(onInjector);
+ putBinding(onInjector);
+ } catch (ErrorsException e) {
+ errors.merge(e.getErrors());
+ putBinding(invalidBinding(injector, key, source));
+ }
+ return null;
+ }
public Void visit(InstanceBinding<? extends T> binding) {
Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
@@ -148,26 +160,15 @@
}
// This cast is safe after the preceeding check.
- final BindingImpl<T> binding;
try {
- binding = injector.createUnitializedBinding(key, scoping,
source, errors);
+ BindingImpl<T> binding = injector.createUnitializedBinding(key,
scoping, source, errors);
+ scheduleInitialization(binding);
putBinding(binding);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
putBinding(invalidBinding(injector, key, source));
- return null;
}
- uninitializedBindings.add(new Runnable() {
- public void run() {
- try {
- binding.getInjector().initializeBinding(binding,
errors.withSource(source));
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
- }
- }
- });
-
return null;
}
@@ -179,12 +180,20 @@
throw new IllegalArgumentException("Cannot apply a non-module
element");
}
- public Void visit(ConstructorBinding<? extends T> binding) {
+ public Void visit(ProviderBinding<? extends T> binding) {
throw new IllegalArgumentException("Cannot apply a non-module
element");
}
- public Void visit(ProviderBinding<? extends T> binding) {
- throw new IllegalArgumentException("Cannot apply a non-module
element");
+ private void scheduleInitialization(final BindingImpl<?> binding) {
+ uninitializedBindings.add(new Runnable() {
+ public void run() {
+ try {
+ binding.getInjector().initializeBinding(binding,
errors.withSource(source));
+ } catch (ErrorsException e) {
+ errors.merge(e.getErrors());
+ }
+ }
+ });
}
});
Modified: trunk/src/com/google/inject/internal/ConstructionContext.java
==============================================================================
--- trunk/src/com/google/inject/internal/ConstructionContext.java
(original)
+++ trunk/src/com/google/inject/internal/ConstructionContext.java Sat Jun
20 10:30:23 2009
@@ -73,8 +73,7 @@
invocationHandlers = new ArrayList<DelegatingInvocationHandler<T>>();
}
- DelegatingInvocationHandler<T> invocationHandler
- = new DelegatingInvocationHandler<T>();
+ DelegatingInvocationHandler<T> invocationHandler = new
DelegatingInvocationHandler<T>();
invocationHandlers.add(invocationHandler);
ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType);
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 Sat
Jun 20 10:30:23 2009
@@ -18,13 +18,17 @@
import com.google.inject.Binder;
import com.google.inject.Key;
+import com.google.inject.ConfigurationException;
import static com.google.inject.internal.Preconditions.checkState;
+import static com.google.inject.internal.Annotations.findScopeAnnotation;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.ConstructorBinding;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -32,34 +36,78 @@
final class ConstructorBindingImpl<T> extends BindingImpl<T> implements
ConstructorBinding<T> {
private final Factory<T> factory;
+ private final InjectionPoint constructorInjectionPoint;
private ConstructorBindingImpl(InjectorImpl injector, Key<T> key, Object
source,
- InternalFactory<? extends T> scopedFactory, Scoping scoping,
Factory<T> factory) {
+ InternalFactory<? extends T> scopedFactory, Scoping scoping,
Factory<T> factory,
+ InjectionPoint constructorInjectionPoint) {
super(injector, key, source, scopedFactory, scoping);
this.factory = factory;
+ this.constructorInjectionPoint = constructorInjectionPoint;
}
public ConstructorBindingImpl(Key<T> key, Object source, Scoping scoping,
- InjectionPoint constructorInjector, Set<InjectionPoint>
injectionPoints) {
+ InjectionPoint constructorInjectionPoint, Set<InjectionPoint>
injectionPoints) {
super(source, key, scoping);
this.factory = new Factory<T>();
ConstructionProxy<T> constructionProxy
- = new
DefaultConstructionProxyFactory<T>(constructorInjector).create();
+ = new
DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create();
+ this.constructorInjectionPoint = constructorInjectionPoint;
factory.constructorInjector = new ConstructorInjector<T>(
injectionPoints, constructionProxy, null, null);
}
- static <T> ConstructorBindingImpl<T> create(
- InjectorImpl injector, Key<T> key, Object source, Scoping scoping) {
+ /**
+ * @param constructorInjector the constructor to use, or {...@code null} to
use the default.
+ */
+ static <T> ConstructorBindingImpl<T> create(InjectorImpl injector,
Key<T> key,
+ InjectionPoint constructorInjector, Object source, Scoping scoping,
Errors errors)
+ throws ErrorsException {
+ int numErrors = errors.size();
+ Class<? super T> rawType = key.getTypeLiteral().getRawType();
+
+ // We can't inject abstract classes.
+ if (Modifier.isAbstract(rawType.getModifiers())) {
+ errors.missingImplementation(key);
+ }
+
+ // Error: Inner class.
+ if (Classes.isInnerClass(rawType)) {
+ errors.cannotInjectInnerClass(rawType);
+ }
+
+ // if no scope is specified, look for a scoping annotation on the
concrete class
+ if (!scoping.isExplicitlyScoped()) {
+ Class<? extends Annotation> scopeAnnotation =
findScopeAnnotation(errors, rawType);
+ if (scopeAnnotation != null) {
+ scoping =
Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
+ injector, errors.withSource(rawType));
+ }
+ }
+
+ errors.throwIfNewErrors(numErrors);
+
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);
+ injector, key, source, scopedFactory, scoping, factoryFactory,
constructorInjector);
}
+ @SuppressWarnings("unchecked") // the result type always agrees with the
ConstructorInjector type
public void initialize(InjectorImpl injector, Errors errors) throws
ErrorsException {
- factory.constructorInjector =
injector.constructors.get(getKey().getTypeLiteral(), errors);
+ factory.constructorInjector
+ = (ConstructorInjector<T>)
injector.constructors.get(constructorInjectionPoint, errors);
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V>
visitor) {
@@ -93,12 +141,12 @@
@Override protected BindingImpl<T> withScoping(Scoping scoping) {
return new ConstructorBindingImpl<T>(
- null, getKey(), getSource(), factory, scoping, factory);
+ null, getKey(), getSource(), factory, scoping, factory,
constructorInjectionPoint);
}
@Override protected BindingImpl<T> withKey(Key<T> key) {
return new ConstructorBindingImpl<T>(
- null, key, getSource(), factory, getScoping(), factory);
+ null, key, getSource(), factory, getScoping(), factory,
constructorInjectionPoint);
}
public void applyTo(Binder binder) {
Modified: trunk/src/com/google/inject/internal/ConstructorInjectorStore.java
==============================================================================
--- trunk/src/com/google/inject/internal/ConstructorInjectorStore.java
(original)
+++ trunk/src/com/google/inject/internal/ConstructorInjectorStore.java Sat
Jun 20 10:30:23 2009
@@ -16,8 +16,6 @@
package com.google.inject.internal;
-import com.google.inject.ConfigurationException;
-import com.google.inject.TypeLiteral;
import static com.google.inject.internal.Iterables.concat;
import com.google.inject.spi.InjectionPoint;
@@ -29,12 +27,12 @@
final class ConstructorInjectorStore {
private final InjectorImpl injector;
- private final FailableCache<TypeLiteral<?>, ConstructorInjector<?>>
cache
- = new FailableCache<TypeLiteral<?>, ConstructorInjector<?>> () {
+ private final FailableCache<InjectionPoint, ConstructorInjector<?>>
cache
+ = new FailableCache<InjectionPoint, ConstructorInjector<?>> () {
@SuppressWarnings("unchecked")
- protected ConstructorInjector<?> create(TypeLiteral<?> type, Errors
errors)
+ protected ConstructorInjector<?> create(InjectionPoint
constructorInjector, Errors errors)
throws ErrorsException {
- return createConstructor(type, errors);
+ return createConstructor(constructorInjector, errors);
}
};
@@ -45,26 +43,21 @@
/**
* Returns a new complete constructor injector with injection listeners
registered.
*/
- @SuppressWarnings("unchecked") // the ConstructorInjector type always
agrees with the passed type
- public <T> ConstructorInjector<T> get(TypeLiteral<T> key, Errors errors)
throws ErrorsException {
- return (ConstructorInjector<T>) cache.get(key, errors);
+ public ConstructorInjector<?> get(InjectionPoint constructorInjector,
Errors errors)
+ throws ErrorsException {
+ return cache.get(constructorInjector, errors);
}
- private <T> ConstructorInjector<T> createConstructor(TypeLiteral<T>
type, Errors errors)
+ private <T> ConstructorInjector<T> createConstructor(InjectionPoint
injectionPoint, Errors errors)
throws ErrorsException {
int numErrorsBefore = errors.size();
- InjectionPoint injectionPoint;
- try {
- injectionPoint = InjectionPoint.forConstructorOf(type);
- } catch (ConfigurationException e) {
- errors.merge(e.getErrorMessages());
- throw errors.toException();
- }
-
SingleParameterInjector<?>[] constructorParameterInjectors
=
injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
- MembersInjectorImpl<T> membersInjector =
injector.membersInjectorStore.get(type, errors);
+
+ @SuppressWarnings("unchecked") // the injector type agrees with the
injection point type
+ MembersInjectorImpl<T> membersInjector = (MembersInjectorImpl<T>)
injector.membersInjectorStore
+ .get(injectionPoint.getDeclaringType(), errors);
/*if[AOP]*/
ImmutableList<MethodAspect> injectorAspects =
injector.state.getMethodAspects();
Modified: trunk/src/com/google/inject/internal/InjectorImpl.java
==============================================================================
--- trunk/src/com/google/inject/internal/InjectorImpl.java (original)
+++ trunk/src/com/google/inject/internal/InjectorImpl.java Sat Jun 20
10:30:23 2009
@@ -28,7 +28,6 @@
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.TypeLiteral;
-import static com.google.inject.internal.Annotations.findScopeAnnotation;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.ConvertedConstantBinding;
import com.google.inject.spi.Dependency;
@@ -36,10 +35,8 @@
import com.google.inject.spi.ProviderBinding;
import com.google.inject.spi.ProviderKeyBinding;
import com.google.inject.util.Providers;
-import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
@@ -412,27 +409,7 @@
return createProvidedByBinding(key, scoping, providedBy, errors);
}
- // We can't inject abstract classes.
- // TODO: Method interceptors could actually enable us to implement
- // abstract types. Should we remove this restriction?
- if (Modifier.isAbstract(rawType.getModifiers())) {
- throw errors.missingImplementation(key).toException();
- }
-
- // Error: Inner class.
- if (Classes.isInnerClass(rawType)) {
- throw errors.cannotInjectInnerClass(rawType).toException();
- }
-
- if (!scoping.isExplicitlyScoped()) {
- Class<? extends Annotation> scopeAnnotation =
findScopeAnnotation(errors, rawType);
- if (scopeAnnotation != null) {
- scoping =
Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
- this, errors.withSource(rawType));
- }
- }
-
- return ConstructorBindingImpl.create(this, key, source, scoping);
+ return ConstructorBindingImpl.create(this, key, null, source, scoping,
errors);
}
/**
Modified: trunk/src/com/google/inject/spi/InjectionPoint.java
==============================================================================
--- trunk/src/com/google/inject/spi/InjectionPoint.java (original)
+++ trunk/src/com/google/inject/spi/InjectionPoint.java Sat Jun 20 10:30:23
2009
@@ -54,25 +54,30 @@
private final boolean optional;
private final Member member;
+ private final TypeLiteral<?> declaringType;
private final ImmutableList<Dependency<?>> dependencies;
- InjectionPoint(TypeLiteral<?> type, Method method) {
+ InjectionPoint(TypeLiteral<?> declaringType, Method method) {
this.member = method;
+ this.declaringType = declaringType;
Inject inject = method.getAnnotation(Inject.class);
this.optional = inject.optional();
- this.dependencies = forMember(method, type,
method.getParameterAnnotations());
+ this.dependencies = forMember(method, declaringType,
method.getParameterAnnotations());
}
- InjectionPoint(TypeLiteral<?> type, Constructor<?> constructor) {
+ InjectionPoint(TypeLiteral<?> declaringType, Constructor<?> constructor)
{
this.member = constructor;
+ this.declaringType = declaringType;
this.optional = false;
- this.dependencies = forMember(constructor, type,
constructor.getParameterAnnotations());
+ this.dependencies = forMember(
+ constructor, declaringType, constructor.getParameterAnnotations());
}
- InjectionPoint(TypeLiteral<?> type, Field field) {
+ InjectionPoint(TypeLiteral<?> declaringType, Field field) {
this.member = field;
+ this.declaringType = declaringType;
Inject inject = field.getAnnotation(Inject.class);
this.optional = inject.optional();
@@ -82,7 +87,7 @@
Errors errors = new Errors(field);
Key<?> key = null;
try {
- key = Annotations.getKey(type.getFieldType(field), field,
annotations, errors);
+ key = Annotations.getKey(declaringType.getFieldType(field), field,
annotations, errors);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
@@ -148,6 +153,15 @@
return optional;
}
+ /**
+ * Returns the generic type that defines this injection point. If the
member exists on a
+ * parameterized type, the result will include more type information
than the member's {...@link
+ * Member#getDeclaringClass() raw declaring class}.
+ */
+ public TypeLiteral<?> getDeclaringType() {
+ return declaringType;
+ }
+
@Override public boolean equals(Object o) {
return o instanceof InjectionPoint
&& member.equals(((InjectionPoint) o).member);
@@ -162,14 +176,13 @@
}
/**
- * Returns a new injection point for the specified constructor. If any
parameter of
- * {...@code constructor} includes a type variable (such as {...@code
List<T>}), prefer the overload
- * that includes a type literal.
+ * Returns a new injection point for the specified constructor. If the
declaring type of {...@code
+ * constructor} is parameterized (such as {...@code List<T>}), prefer the
overload that includes a
+ * type literal.
*
* @param constructor any single constructor present on {...@code type}.
*/
public static <T> InjectionPoint forConstructor(Constructor<T>
constructor) {
- // TODO: verify that constructor is valid? (defined on a non-abstract
class, etc.)
return new
InjectionPoint(TypeLiteral.get(constructor.getDeclaringClass()),
constructor);
}
@@ -187,7 +200,6 @@
.throwConfigurationExceptionIfErrorsExist();
}
- // TODO: verify that constructor is valid? (defined on a non-abstract
class, etc.)
return new InjectionPoint(type, constructor);
}
Modified: trunk/test/com/google/inject/BindingTest.java
==============================================================================
--- trunk/test/com/google/inject/BindingTest.java (original)
+++ trunk/test/com/google/inject/BindingTest.java Sat Jun 20 10:30:23 2009
@@ -21,6 +21,7 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
+import java.lang.reflect.Constructor;
import junit.framework.TestCase;
/**
@@ -206,4 +207,30 @@
@Inject TooManyConstructors(Injector i) {}
@Inject TooManyConstructors() {}
}
+
+ public void testToConstructorBindings() throws NoSuchMethodException {
+ final Constructor<C> constructor = C.class.getConstructor(Stage.class);
+
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(C.class).toConstructor(constructor);
+ }
+ });
+
+ assertEquals(Stage.DEVELOPMENT, injector.getInstance(C.class).stage);
+ }
+
+ public static class C {
+ private final Stage stage;
+
+ public C(Stage stage) {
+ this.stage = stage;
+ }
+
+ @Inject C() {
+ this.stage = null;
+ }
+ }
+
+
}
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---