Early draft of InjectionListeners.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@906 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/AbstractModule.java b/src/com/google/inject/AbstractModule.java
index 4950308..9e52f4f 100644
--- a/src/com/google/inject/AbstractModule.java
+++ b/src/com/google/inject/AbstractModule.java
@@ -24,6 +24,7 @@
import com.google.inject.matcher.Matcher;
import com.google.inject.spi.Message;
import com.google.inject.spi.TypeConverter;
+import com.google.inject.spi.InjectableType;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@@ -140,11 +141,11 @@
}
/**
- * @see Binder#requestInjection(Object[])
+ * @see Binder#requestInjection(Object)
* @since 2.0
*/
- protected void requestInjection(Object... objects) {
- binder.requestInjection(objects);
+ protected void requestInjection(Object instance) {
+ binder.requestInjection(instance);
}
/**
@@ -223,4 +224,30 @@
protected Stage currentStage() {
return binder.currentStage();
}
+
+ /**
+ * @see Binder#getMembersInjector(Class)
+ * @since 2.0
+ */
+ protected <T> MembersInjector<T> getMembersInjector(Class<T> type) {
+ return binder.getMembersInjector(type);
+ }
+
+ /**
+ * @see Binder#getMembersInjector(TypeLiteral)
+ * @since 2.0
+ */
+ protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
+ return binder.getMembersInjector(type);
+ }
+
+ /**
+ * @see Binder#bindListener(com.google.inject.matcher.Matcher,
+ * com.google.inject.spi.InjectableType.Listener)
+ * @since 2.0
+ */
+ protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
+ InjectableType.Listener listener) {
+ binder.bindListener(typeMatcher, listener);
+ }
}
diff --git a/src/com/google/inject/AbstractProcessor.java b/src/com/google/inject/AbstractProcessor.java
index 5ea73a3..9a43034 100644
--- a/src/com/google/inject/AbstractProcessor.java
+++ b/src/com/google/inject/AbstractProcessor.java
@@ -26,6 +26,8 @@
import com.google.inject.spi.ScopeBinding;
import com.google.inject.spi.StaticInjectionRequest;
import com.google.inject.spi.TypeConverterBinding;
+import com.google.inject.spi.MembersInjectorLookup;
+import com.google.inject.spi.InjectableTypeListenerBinding;
import java.util.Iterator;
import java.util.List;
@@ -71,42 +73,50 @@
}
}
- public Boolean visitMessage(Message message) {
+ public Boolean visit(Message message) {
return false;
}
/*if[AOP]*/
- public Boolean visitInterceptorBinding(
+ public Boolean visit(
com.google.inject.spi.InterceptorBinding interceptorBinding) {
return false;
}
/*end[AOP]*/
- public Boolean visitScopeBinding(ScopeBinding scopeBinding) {
+ public Boolean visit(ScopeBinding scopeBinding) {
return false;
}
- public Boolean visitInjectionRequest(InjectionRequest injectionRequest) {
+ public Boolean visit(InjectionRequest injectionRequest) {
return false;
}
- public Boolean visitStaticInjectionRequest(StaticInjectionRequest staticInjectionRequest) {
+ public Boolean visit(StaticInjectionRequest staticInjectionRequest) {
return false;
}
- public Boolean visitTypeConverterBinding(TypeConverterBinding typeConverterBinding) {
+ public Boolean visit(TypeConverterBinding typeConverterBinding) {
return false;
}
- public <T> Boolean visitBinding(Binding<T> binding) {
+ public <T> Boolean visit(Binding<T> binding) {
return false;
}
- public <T> Boolean visitProviderLookup(ProviderLookup<T> providerLookup) {
+ public <T> Boolean visit(ProviderLookup<T> providerLookup) {
return false;
}
- public Boolean visitPrivateElements(PrivateElements privateElements) {
+ public Boolean visit(PrivateElements privateElements) {
+ return false;
+ }
+
+ public <T> Boolean visit(MembersInjectorLookup<T> lookup) {
+ return false;
+ }
+
+ public Boolean visit(InjectableTypeListenerBinding binding) {
return false;
}
}
diff --git a/src/com/google/inject/Binder.java b/src/com/google/inject/Binder.java
index 2331c87..22f0252 100644
--- a/src/com/google/inject/Binder.java
+++ b/src/com/google/inject/Binder.java
@@ -20,6 +20,7 @@
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.matcher.Matcher;
+import com.google.inject.spi.InjectableType;
import com.google.inject.spi.Message;
import com.google.inject.spi.TypeConverter;
import java.lang.annotation.Annotation;
@@ -183,13 +184,21 @@
* documentation.
*
* @author crazybob@google.com (Bob Lee)
+ * @author jessewilson@google.com (Jesse Wilson)
+ * @author kevinb@google.com (Kevin Bourrillion)
*/
public interface Binder {
/*if[AOP]*/
/**
- * Binds a method interceptor to methods matched by class and method
- * matchers.
+ * Binds method interceptor[s] to methods matched by class and method matchers. A method is
+ * eligible for interception if:
+ *
+ * <ul>
+ * <li>Guice created the instance the method is on</li>
+ * <li>Neither the enclosing type nor the method is final</li>
+ * <li>And the method is package-private, protected, or public</li>
+ * </ul>
*
* @param classMatcher matches classes the interceptor should apply to. For
* example: {@code only(Runnable.class)}.
@@ -229,12 +238,22 @@
/**
* Upon successful creation, the {@link Injector} will inject instance fields
- * and methods of the given objects.
+ * and methods of the given object.
*
- * @param instances for which members will be injected
+ * @param type of instance
+ * @param instance for which members will be injected
* @since 2.0
*/
- void requestInjection(Object... instances);
+ <T> void requestInjection(TypeLiteral<T> type, T instance);
+
+ /**
+ * Upon successful creation, the {@link Injector} will inject instance fields
+ * and methods of the given object.
+ *
+ * @param instance for which members will be injected
+ * @since 2.0
+ */
+ void requestInjection(Object instance);
/**
* Upon successful creation, the {@link Injector} will inject static fields
@@ -290,7 +309,7 @@
/**
* Returns the provider used to obtain instances for the given injection type.
- * The returned will not be valid until the {@link Injector} has been
+ * The returned provider will not be valid until the {@link Injector} has been
* created. The provider will throw an {@code IllegalStateException} if you
* try to use it beforehand.
*
@@ -299,6 +318,28 @@
<T> Provider<T> getProvider(Class<T> type);
/**
+ * Returns the members injector used to inject dependencies into methods and fields on instances
+ * of the given type {@code T}. The returned members injector will not be valid until the main
+ * {@link Injector} has been created. The members injector will throw an {@code
+ * IllegalStateException} if you try to use it beforehand.
+ *
+ * @param typeLiteral type to get members injector for
+ * @since 2.0
+ */
+ <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral);
+
+ /**
+ * Returns the members injector used to inject dependencies into methods and fields on instances
+ * of the given type {@code T}. The returned members injector will not be valid until the main
+ * {@link Injector} has been created. The members injector will throw an {@code
+ * IllegalStateException} if you try to use it beforehand.
+ *
+ * @param type type to get members injector for
+ * @since 2.0
+ */
+ <T> MembersInjector<T> getMembersInjector(Class<T> type);
+
+ /**
* Binds a type converter. The injector will use the given converter to
* convert string constants to matching types as needed.
*
@@ -306,7 +347,19 @@
* @param converter converts values
* @since 2.0
*/
- void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter);
+ void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
+ TypeConverter converter);
+
+ /**
+ * Registers a listener for injectable types. Guice will notify the listener when it encounters
+ * injectable types matched by the given type matcher.
+ *
+ * @param typeMatcher that matches injectable types the listener should be notified of
+ * @param listener for injectable types matched by typeMatcher
+ * @since 2.0
+ */
+ void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
+ InjectableType.Listener listener);
/**
* Returns a binder that uses {@code source} as the reference location for
diff --git a/src/com/google/inject/Binding.java b/src/com/google/inject/Binding.java
index c25d354..332237e 100644
--- a/src/com/google/inject/Binding.java
+++ b/src/com/google/inject/Binding.java
@@ -89,5 +89,4 @@
* @since 2.0
*/
<V> V acceptScopingVisitor(BindingScopingVisitor<V> visitor);
-
}
diff --git a/src/com/google/inject/BindingProcessor.java b/src/com/google/inject/BindingProcessor.java
index 0d08aa0..46d4105 100644
--- a/src/com/google/inject/BindingProcessor.java
+++ b/src/com/google/inject/BindingProcessor.java
@@ -62,7 +62,7 @@
this.initializer = initializer;
}
- @Override public <T> Boolean visitBinding(Binding<T> command) {
+ @Override public <T> Boolean visit(Binding<T> command) {
final Object source = command.getSource();
if (Void.class.equals(command.getKey().getRawType())) {
@@ -85,7 +85,7 @@
command.acceptTargetVisitor(new BindingTargetVisitor<T, Void>() {
- public Void visitInstance(InstanceBinding<? extends T> binding) {
+ public Void visit(InstanceBinding<? extends T> binding) {
Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
T instance = binding.getInstance();
Initializable<T> ref = initializer.requestInjection(
@@ -97,7 +97,7 @@
return null;
}
- public Void visitProviderInstance(ProviderInstanceBinding<? extends T> binding) {
+ public Void visit(ProviderInstanceBinding<? extends T> binding) {
Provider<? extends T> provider = binding.getProviderInstance();
Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
Initializable<Provider<? extends T>> initializable = initializer
@@ -109,7 +109,7 @@
return null;
}
- public Void visitProviderKey(ProviderKeyBinding<? extends T> binding) {
+ public Void visit(ProviderKeyBinding<? extends T> binding) {
Key<? extends Provider<? extends T>> providerKey = binding.getProviderKey();
BoundProviderFactory<T> boundProviderFactory
= new BoundProviderFactory<T>(injector, providerKey, source);
@@ -121,7 +121,7 @@
return null;
}
- public Void visitLinkedKey(LinkedKeyBinding<? extends T> binding) {
+ public Void visit(LinkedKeyBinding<? extends T> binding) {
Key<? extends T> linkedKey = binding.getLinkedKey();
if (key.equals(linkedKey)) {
errors.recursiveBinding();
@@ -135,7 +135,7 @@
return null;
}
- public Void visitUntargetted(UntargettedBinding<? extends T> untargetted) {
+ public Void visit(UntargettedBinding<? extends T> untargetted) {
// Error: Missing implementation.
// Example: bind(Date.class).annotatedWith(Red.class);
// We can't assume abstract types aren't injectable. They may have an
@@ -171,7 +171,7 @@
return null;
}
- public Void visitExposed(ExposedBinding<? extends T> binding) {
+ public Void visit(ExposedBinding<? extends T> binding) {
PrivateElements privateElements = binding.getPrivateElements();
ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
creationListeners.add(exposedKeyFactory);
@@ -180,15 +180,15 @@
return null;
}
- public Void visitConvertedConstant(ConvertedConstantBinding<? extends T> binding) {
+ public Void visit(ConvertedConstantBinding<? extends T> binding) {
throw new IllegalArgumentException("Cannot apply a non-module element");
}
- public Void visitConstructor(ConstructorBinding<? extends T> binding) {
+ public Void visit(ConstructorBinding<? extends T> binding) {
throw new IllegalArgumentException("Cannot apply a non-module element");
}
- public Void visitProviderBinding(ProviderBinding<? extends T> binding) {
+ public Void visit(ProviderBinding<? extends T> binding) {
throw new IllegalArgumentException("Cannot apply a non-module element");
}
});
diff --git a/src/com/google/inject/ClassBindingImpl.java b/src/com/google/inject/ClassBindingImpl.java
deleted file mode 100644
index dd83669..0000000
--- a/src/com/google/inject/ClassBindingImpl.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.google.inject.InjectorImpl.LateBoundConstructor;
-import com.google.inject.internal.BindingImpl;
-import com.google.inject.internal.Errors;
-import com.google.inject.internal.ErrorsException;
-import com.google.inject.internal.ImmutableSet;
-import com.google.inject.internal.InternalFactory;
-import static com.google.inject.internal.Preconditions.checkState;
-import com.google.inject.internal.Scoping;
-import com.google.inject.internal.ToStringBuilder;
-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.util.List;
-import java.util.Map;
-import java.util.Set;
-
-class ClassBindingImpl<T> extends BindingImpl<T> implements ConstructorBinding<T> {
-
- private final LateBoundConstructor<T> lateBoundConstructor;
- private ImmutableSet<InjectionPoint> injectionPoints;
-
- ClassBindingImpl(Injector injector, Key<T> key, Object source,
- InternalFactory<? extends T> internalFactory, Scoping scoping,
- LateBoundConstructor<T> lateBoundConstructor) {
- super(injector, key, source, internalFactory, scoping);
- this.lateBoundConstructor = lateBoundConstructor;
- }
-
- @Override public void initialize(Injector injector, Errors errors) throws ErrorsException {
- lateBoundConstructor.bind(injector, getKey().getTypeLiteral(), errors);
- injectionPoints = lateBoundConstructor.constructorInjector.getInjectionPoints();
- }
-
- public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- checkState(injectionPoints != null, "not initialized");
- return visitor.visitConstructor(this);
- }
-
- public Constructor<? extends T> getConstructor() {
- return lateBoundConstructor.getConstructor();
- }
-
- public Set<InjectionPoint> getInjectionPoints() {
- return injectionPoints;
- }
-
- public Set<Dependency<?>> getDependencies() {
- return Dependency.forInjectionPoints(injectionPoints);
- }
-
- /*if[AOP]*/
- public Map<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors() {
- return lateBoundConstructor.constructorInjector.constructionProxy.getMethodInterceptors();
- }
- /*end[AOP]*/
-
- @Override public String toString() {
- return new ToStringBuilder(ConstructorBinding.class)
- .add("key", getKey())
- .add("source", getSource())
- .add("scope", getScoping())
- .toString();
- }
-}
diff --git a/src/com/google/inject/ConstructionProxyFactory.java b/src/com/google/inject/ConstructionProxyFactory.java
index af404ef..de9c47e 100644
--- a/src/com/google/inject/ConstructionProxyFactory.java
+++ b/src/com/google/inject/ConstructionProxyFactory.java
@@ -16,19 +16,15 @@
package com.google.inject;
-import com.google.inject.spi.InjectionPoint;
-
/**
* Creates {@link ConstructionProxy} instances.
*
* @author crazybob@google.com (Bob Lee)
*/
-interface ConstructionProxyFactory {
+interface ConstructionProxyFactory<T> {
/**
* Gets a construction proxy for the given constructor.
- *
- * @param injectionPoint an injection point whose member is a constructor of {@code T}.
*/
- <T> ConstructionProxy<T> get(InjectionPoint injectionPoint);
+ ConstructionProxy<T> create();
}
diff --git a/src/com/google/inject/ConstructorBindingImpl.java b/src/com/google/inject/ConstructorBindingImpl.java
new file mode 100644
index 0000000..0498902
--- /dev/null
+++ b/src/com/google/inject/ConstructorBindingImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 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 com.google.inject.internal.BindingImpl;
+import com.google.inject.internal.Errors;
+import com.google.inject.internal.ErrorsException;
+import com.google.inject.internal.InternalContext;
+import com.google.inject.internal.InternalFactory;
+import static com.google.inject.internal.Preconditions.checkState;
+import com.google.inject.internal.Scoping;
+import com.google.inject.internal.ToStringBuilder;
+import com.google.inject.spi.BindingTargetVisitor;
+import com.google.inject.spi.ConstructorBinding;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectableType;
+import java.lang.reflect.Constructor;
+import java.util.Set;
+
+class ConstructorBindingImpl<T> extends BindingImpl<T> implements ConstructorBinding<T> {
+
+ private final Factory<T> factory;
+ private InjectableType<T> injectableType;
+
+ private ConstructorBindingImpl(Injector injector, Key<T> key, Object source,
+ InternalFactory<? extends T> scopedFactory, Scoping scoping, Factory<T> factory) {
+ super(injector, key, source, scopedFactory, scoping);
+ this.factory = factory;
+ }
+
+ static <T> ConstructorBindingImpl<T> create(
+ InjectorImpl injector, Key<T> key, Object source, Scoping scoping) {
+ Factory<T> factoryFactory = new Factory<T>();
+ InternalFactory<? extends T> scopedFactory
+ = Scopes.scope(key, injector, factoryFactory, scoping);
+ return new ConstructorBindingImpl<T>(
+ injector, key, source, scopedFactory, scoping, factoryFactory);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ factory.constructorInjector = (ConstructorInjector<T>) injector.constructors.get(
+ getKey().getTypeLiteral(), errors);
+ injectableType = factory.constructorInjector.getInjectableType();
+ }
+
+ public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
+ checkState(injectableType != null, "not initialized");
+ return visitor.visit(this);
+ }
+
+ @SuppressWarnings("unchecked") // our injectable type always has a constructor of type T
+ public Constructor<? extends T> getConstructor() {
+ checkState(factory.constructorInjector != null, "Constructor is not ready");
+ return (Constructor<? extends T>) injectableType.getInjectableConstructor().getMember();
+ }
+
+ public InjectableType<T> getInjectableType() {
+ return injectableType;
+ }
+
+ public Set<Dependency<?>> getDependencies() {
+ return Dependency.forInjectableType(injectableType);
+ }
+
+ public void applyTo(Binder binder) {
+ throw new UnsupportedOperationException("This element represents a synthetic binding.");
+ }
+
+ @Override public String toString() {
+ return new ToStringBuilder(ConstructorBinding.class)
+ .add("key", getKey())
+ .add("source", getSource())
+ .add("scope", getScoping())
+ .toString();
+ }
+
+ private static class Factory<T> implements InternalFactory<T> {
+ private ConstructorInjector<T> constructorInjector;
+
+ @SuppressWarnings("unchecked")
+ public T get(Errors errors, InternalContext context, Dependency<?> dependency)
+ throws ErrorsException {
+ checkState(constructorInjector != null, "Constructor not ready");
+
+ // This may not actually be safe because it could return a super type of T (if that's all the
+ // client needs), but it should be OK in practice thanks to the wonders of erasure.
+ return (T) constructorInjector.construct(errors, context, dependency.getKey().getRawType());
+ }
+ }
+}
diff --git a/src/com/google/inject/ConstructorInjector.java b/src/com/google/inject/ConstructorInjector.java
index f911804..7176474 100644
--- a/src/com/google/inject/ConstructorInjector.java
+++ b/src/com/google/inject/ConstructorInjector.java
@@ -20,9 +20,9 @@
import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
import com.google.inject.internal.ImmutableList;
-import com.google.inject.internal.ImmutableSet;
import com.google.inject.internal.InternalContext;
-import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.InjectableType;
+import com.google.inject.spi.InjectionListener;
import java.lang.reflect.InvocationTargetException;
/**
@@ -33,35 +33,24 @@
*/
class ConstructorInjector<T> {
- final TypeLiteral<T> implementation;
- final InjectionPoint injectionPoint;
- final ImmutableList<SingleMemberInjector> memberInjectors;
- final ImmutableList<SingleParameterInjector<?>> parameterInjectors;
- final ConstructionProxy<T> constructionProxy;
+ private final ImmutableList<SingleParameterInjector<?>> parameterInjectors;
+ private final ConstructionProxy<T> constructionProxy;
+ private final ImmutableList<SingleMemberInjector> memberInjectors;
+ private final ImmutableList<InjectionListener<? super T>> injectionListeners;
- ConstructorInjector(Errors errors, InjectorImpl injector, TypeLiteral<T> implementation)
+ private final InjectableType<T> injectableType;
+
+ ConstructorInjector(ConstructionProxy<T> constructionProxy,
+ ImmutableList<SingleParameterInjector<?>> parameterInjectors,
+ ImmutableList<SingleMemberInjector> memberInjectors,
+ ImmutableList<InjectionListener<? super T>> injectionListeners,
+ InjectableType<T> injectableType)
throws ErrorsException {
- this.implementation = implementation;
-
- try {
- this.injectionPoint = InjectionPoint.forConstructorOf(implementation);
- } catch (ConfigurationException e) {
- throw errors.merge(e.getErrorMessages()).toException();
- }
-
- constructionProxy = injector.constructionProxyFactory.get(injectionPoint);
- parameterInjectors = injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
- memberInjectors = injector.injectors.get(implementation, errors);
- }
-
- ImmutableSet<InjectionPoint> getInjectionPoints() {
- InjectionPoint[] injectionPoints = new InjectionPoint[memberInjectors.size() + 1];
- injectionPoints[0] = constructionProxy.getInjectionPoint();
- int i = 1;
- for (SingleMemberInjector memberInjector : memberInjectors) {
- injectionPoints[i++] = memberInjector.getInjectionPoint();
- }
- return ImmutableSet.of(injectionPoints);
+ this.constructionProxy = constructionProxy;
+ this.parameterInjectors = parameterInjectors;
+ this.memberInjectors = memberInjectors;
+ this.injectionListeners = injectionListeners;
+ this.injectableType = injectableType;
}
/**
@@ -105,6 +94,10 @@
injector.inject(errors, context, t);
}
+ for (InjectionListener<? super T> injectionListener : injectionListeners) {
+ injectionListener.afterInjection(t); // TODO: handle user exceptions here
+ }
+
return t;
} catch (InvocationTargetException userException) {
Throwable cause = userException.getCause() != null
@@ -116,4 +109,8 @@
constructionContext.removeCurrentReference();
}
}
+
+ public InjectableType<T> getInjectableType() {
+ return injectableType;
+ }
}
diff --git a/src/com/google/inject/ConstructorInjectorStore.java b/src/com/google/inject/ConstructorInjectorStore.java
new file mode 100644
index 0000000..ff78e6d
--- /dev/null
+++ b/src/com/google/inject/ConstructorInjectorStore.java
@@ -0,0 +1,197 @@
+/**
+ * Copyright (C) 2009 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 com.google.inject.internal.Errors;
+import com.google.inject.internal.ErrorsException;
+import com.google.inject.internal.FailableCache;
+import com.google.inject.internal.ImmutableList;
+import com.google.inject.internal.ImmutableSet;
+import static com.google.inject.internal.Iterables.concat;
+import com.google.inject.internal.Lists;
+import com.google.inject.matcher.Matcher;
+import com.google.inject.matcher.Matchers;
+import com.google.inject.spi.InjectableType;
+import com.google.inject.spi.InjectableTypeListenerBinding;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.Message;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.aopalliance.intercept.MethodInterceptor;
+
+/**
+ * Constructor injectors by type.
+ *
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+class ConstructorInjectorStore extends FailableCache<TypeLiteral<?>, ConstructorInjector<?>> {
+
+ private final InjectorImpl injector;
+ private final ImmutableList<InjectableTypeListenerBinding> injectableTypeListenerBindings;
+
+ public ConstructorInjectorStore(InjectorImpl injector,
+ List<InjectableTypeListenerBinding> injectableTypeListenerBindings) {
+ this.injector = injector;
+ this.injectableTypeListenerBindings = ImmutableList.copyOf(injectableTypeListenerBindings);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected ConstructorInjector<?> create(TypeLiteral<?> type, Errors errors)
+ throws ErrorsException {
+ try {
+ return createConstructor(type, errors);
+ } catch (ConfigurationException e) {
+ throw errors.merge(e.getErrorMessages()).toException();
+ }
+ }
+
+ private <T> ConstructorInjector<T> createConstructor(TypeLiteral<T> type, Errors errors)
+ throws ErrorsException {
+
+ InjectionPoint injectionPoint = InjectionPoint.forConstructorOf(type);
+ ImmutableList<SingleParameterInjector<?>> constructorParameterInjectors
+ = injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
+ ImmutableList<SingleMemberInjector> memberInjectors = injector.injectors.get(type, errors);
+
+ ImmutableSet.Builder<InjectionPoint> injectableMembersBuilder = ImmutableSet.builder();
+ for (SingleMemberInjector memberInjector : memberInjectors) {
+ injectableMembersBuilder.add(memberInjector.getInjectionPoint());
+ }
+ ImmutableSet<InjectionPoint> injectableMembers = injectableMembersBuilder.build();
+
+ ProxyFactory<T> proxyFactory = new ProxyFactory<T>(injectionPoint, injector.methodAspects);
+ EncounterImpl<T> encounter = new EncounterImpl<T>();
+ InjectableType<T> injectableType = new InjectableTypeImpl<T>(
+ injectionPoint, type, injectableMembers, proxyFactory.getInterceptors());
+
+ for (InjectableTypeListenerBinding typeListener : injectableTypeListenerBindings) {
+ if (typeListener.getTypeMatcher().matches(type)) {
+ // TODO: wrap this user code in a better try/catch block
+ typeListener.getListener().hear(injectableType, encounter);
+ }
+ }
+
+ // rebuild the proxy factory and injectable type if new interceptors were added
+ if (encounter.hasAddedAspects()) {
+ proxyFactory = new ProxyFactory<T>(
+ injectionPoint, concat(injector.methodAspects, encounter.aspects));
+ injectableType = new InjectableTypeImpl<T>(
+ injectionPoint, type, injectableMembers, proxyFactory.getInterceptors());
+ }
+
+ return new ConstructorInjector<T>(proxyFactory.create(), constructorParameterInjectors,
+ memberInjectors, encounter.getInjectionListeners(), injectableType);
+ }
+
+ private static class EncounterImpl<T> implements InjectableType.Encounter<T> {
+ private List<InjectionListener<? super T>> injectionListeners; // lazy
+ private List<MethodAspect> aspects; // lazy
+
+ boolean hasAddedAspects() {
+ return aspects != null;
+ }
+
+ ImmutableList<InjectionListener<? super T>> getInjectionListeners() {
+ return injectionListeners == null
+ ? ImmutableList.<InjectionListener<? super T>>of()
+ : ImmutableList.copyOf(injectionListeners);
+ }
+
+ public void register(InjectionListener<? super T> injectionListener) {
+ if (injectionListeners == null) {
+ injectionListeners = Lists.newArrayList();
+ }
+
+ injectionListeners.add(injectionListener);
+ }
+
+ public void bindInterceptor(Matcher<? super Method> methodMatcher,
+ MethodInterceptor... interceptors) {
+ // make sure the applicable aspects is mutable
+ if (aspects == null) {
+ aspects = Lists.newArrayList();
+ }
+
+ aspects.add(new MethodAspect(Matchers.any(), methodMatcher, interceptors));
+ }
+
+ public void addError(String message, Object... arguments) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public void addError(Throwable t) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public void addError(Message message) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public <T> Provider<T> getProvider(Key<T> key) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public <T> Provider<T> getProvider(Class<T> type) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
+ throw new UnsupportedOperationException("TODO");
+ }
+ }
+
+ static class InjectableTypeImpl<T> implements InjectableType<T> {
+ private final InjectionPoint injectionPoint;
+ private final TypeLiteral<T> type;
+ private final Set<InjectionPoint> injectableMembers;
+ private final Map<Method, List<MethodInterceptor>> methodInterceptors;
+
+ InjectableTypeImpl(InjectionPoint injectionPoint, TypeLiteral<T> type,
+ Set<InjectionPoint> injectableMembers,
+ Map<Method, List<MethodInterceptor>> methodInterceptors) {
+ this.injectionPoint = injectionPoint;
+ this.type = type;
+ this.injectableMembers = injectableMembers;
+ this.methodInterceptors = methodInterceptors;
+ }
+
+ public TypeLiteral<T> getType() {
+ return type;
+ }
+
+ public InjectionPoint getInjectableConstructor() {
+ return injectionPoint;
+ }
+
+ public Set<InjectionPoint> getInjectableMembers() throws ConfigurationException {
+ return injectableMembers;
+ }
+
+ /*if[AOP]*/
+ public Map<Method, List<MethodInterceptor>> getMethodInterceptors() {
+ return methodInterceptors;
+ }
+ /*end[AOP]*/
+ }
+}
diff --git a/src/com/google/inject/DefaultConstructionProxyFactory.java b/src/com/google/inject/DefaultConstructionProxyFactory.java
index d56d40d..d2370d5 100644
--- a/src/com/google/inject/DefaultConstructionProxyFactory.java
+++ b/src/com/google/inject/DefaultConstructionProxyFactory.java
@@ -28,15 +28,22 @@
import java.util.Map;
/**
- * Default {@link ConstructionProxyFactory} implementation. Simply invokes the
- * constructor. Can be reused by other {@code ConstructionProxyFactory}
- * implementations.
+ * Produces construction proxies that invoke the class constructor.
*
* @author crazybob@google.com (Bob Lee)
*/
-class DefaultConstructionProxyFactory implements ConstructionProxyFactory {
+class DefaultConstructionProxyFactory<T> implements ConstructionProxyFactory<T> {
- public <T> ConstructionProxy<T> get(final InjectionPoint injectionPoint) {
+ private final InjectionPoint injectionPoint;
+
+ /**
+ * @param injectionPoint an injection point whose member is a constructor of {@code T}.
+ */
+ DefaultConstructionProxyFactory(InjectionPoint injectionPoint) {
+ this.injectionPoint = injectionPoint;
+ }
+
+ public ConstructionProxy<T> create() {
@SuppressWarnings("unchecked") // the injection point is for a constructor of T
final Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
diff --git a/src/com/google/inject/InheritingState.java b/src/com/google/inject/InheritingState.java
index 68f1c3d..857b163 100644
--- a/src/com/google/inject/InheritingState.java
+++ b/src/com/google/inject/InheritingState.java
@@ -22,7 +22,9 @@
import com.google.inject.internal.Maps;
import com.google.inject.internal.MatcherAndConverter;
import static com.google.inject.internal.Preconditions.checkNotNull;
+import com.google.inject.spi.InjectableTypeListenerBinding;
import java.lang.annotation.Annotation;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -43,6 +45,7 @@
/*if[AOP]*/
private final List<MethodAspect> methodAspects = Lists.newArrayList();
/*end[AOP]*/
+ private final List<InjectableTypeListenerBinding> listenerBindings = Lists.newArrayList();
private final WeakKeySet blacklistedKeys = new WeakKeySet();
private final Object lock;
@@ -115,6 +118,19 @@
}
/*end[AOP]*/
+ public void addInjectableTypeListener(InjectableTypeListenerBinding listenerBinding) {
+ listenerBindings.add(listenerBinding);
+ }
+
+ public List<InjectableTypeListenerBinding> getInjectableTypeListenerBindings() {
+ List<InjectableTypeListenerBinding> parentBindings = parent.getInjectableTypeListenerBindings();
+ List<InjectableTypeListenerBinding> result
+ = new ArrayList<InjectableTypeListenerBinding>(parentBindings.size() + 1);
+ result.addAll(parentBindings);
+ result.addAll(listenerBindings);
+ return result;
+ }
+
public void blacklist(Key<?> key) {
parent.blacklist(key);
blacklistedKeys.add(key);
diff --git a/src/com/google/inject/InjectableTypeListenerBindingProcessor.java b/src/com/google/inject/InjectableTypeListenerBindingProcessor.java
new file mode 100644
index 0000000..13217e5
--- /dev/null
+++ b/src/com/google/inject/InjectableTypeListenerBindingProcessor.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2009 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 com.google.inject.internal.Errors;
+import com.google.inject.spi.InjectableTypeListenerBinding;
+
+/**
+ * Handles {@link Binder#bindListener} commands.
+ *
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+class InjectableTypeListenerBindingProcessor extends AbstractProcessor {
+
+ InjectableTypeListenerBindingProcessor(Errors errors) {
+ super(errors);
+ }
+
+ @Override public Boolean visit(InjectableTypeListenerBinding binding) {
+ injector.state.addInjectableTypeListener(binding);
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/com/google/inject/InjectionRequestProcessor.java b/src/com/google/inject/InjectionRequestProcessor.java
index 2862496..03d5e29 100644
--- a/src/com/google/inject/InjectionRequestProcessor.java
+++ b/src/com/google/inject/InjectionRequestProcessor.java
@@ -44,12 +44,12 @@
this.initializer = initializer;
}
- @Override public Boolean visitStaticInjectionRequest(StaticInjectionRequest request) {
+ @Override public Boolean visit(StaticInjectionRequest request) {
staticInjections.add(new StaticInjection(injector, request));
return true;
}
- @Override public Boolean visitInjectionRequest(InjectionRequest request) {
+ @Override public Boolean visit(InjectionRequest request) {
Set<InjectionPoint> injectionPoints;
try {
injectionPoints = request.getInjectionPoints();
diff --git a/src/com/google/inject/Injector.java b/src/com/google/inject/Injector.java
index 8ff26b7..e49540c 100644
--- a/src/com/google/inject/Injector.java
+++ b/src/com/google/inject/Injector.java
@@ -47,6 +47,7 @@
* enables tools and extensions to operate on an injector reflectively.
*
* @author crazybob@google.com (Bob Lee)
+ * @author jessewilson@google.com (Jesse Wilson)
*/
public interface Injector {
@@ -57,10 +58,38 @@
* <p>Whenever Guice creates an instance, it performs this injection automatically (after first
* performing constructor injection), so if you're able to let Guice create all your objects for
* you, you'll never need to use this method.
+ *
+ * @param instance to inject members on
+ *
+ * @see Binder#getMembersInjector(Class) for a preferred alternative that supports checks before
+ * run time
*/
void injectMembers(Object instance);
/**
+ * Returns the members injector used to inject dependencies into methods and fields on instances
+ * of the given type {@code T}.
+ *
+ * @param typeLiteral type to get members injector for
+ * @see Binder#getMembersInjector(TypeLiteral) for an alternative that offers up front error
+ * detection
+ * @since 2.0
+ */
+ <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral);
+
+ /**
+ * Returns the members injector used to inject dependencies into methods and fields on instances
+ * of the given type {@code T}. When feasible, use {@link Binder#getMembersInjector(TypeLiteral)}
+ * instead to get increased up front error detection.
+ *
+ * @param type type to get members injector for
+ * @see Binder#getMembersInjector(Class) for an alternative that offers up front error
+ * detection
+ * @since 2.0
+ */
+ <T> MembersInjector<T> getMembersInjector(Class<T> type);
+
+ /**
* Returns all explicit bindings.
*
* <p>The returned map does not include bindings inherited from a {@link #getParent() parent
@@ -69,7 +98,6 @@
* the order in which bindings appear in user Modules.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
- *
*/
Map<Key<?>, Binding<?>> getBindings();
@@ -108,6 +136,7 @@
* using this method, in favor of having Guice inject your dependencies ahead of time.
*
* @throws ConfigurationException if this injector cannot find or create the provider.
+ * @see Binder#getProvider(Key) for an alternative that offers up front error detection
*/
<T> Provider<T> getProvider(Key<T> key);
@@ -116,6 +145,7 @@
* using this method, in favor of having Guice inject your dependencies ahead of time.
*
* @throws ConfigurationException if this injector cannot find or create the provider.
+ * @see Binder#getProvider(Class) for an alternative that offers up front error detection
*/
<T> Provider<T> getProvider(Class<T> type);
diff --git a/src/com/google/inject/InjectorBuilder.java b/src/com/google/inject/InjectorBuilder.java
index ad3777a..eeb3529 100644
--- a/src/com/google/inject/InjectorBuilder.java
+++ b/src/com/google/inject/InjectorBuilder.java
@@ -251,6 +251,14 @@
throw new UnsupportedOperationException(
"Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
}
+ public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
+ throw new UnsupportedOperationException(
+ "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
+ }
+ public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
+ throw new UnsupportedOperationException(
+ "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
+ }
public <T> T getInstance(Key<T> key) {
throw new UnsupportedOperationException(
"Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
diff --git a/src/com/google/inject/InjectorImpl.java b/src/com/google/inject/InjectorImpl.java
index d0a60e1..a17fb40 100644
--- a/src/com/google/inject/InjectorImpl.java
+++ b/src/com/google/inject/InjectorImpl.java
@@ -34,7 +34,6 @@
import com.google.inject.internal.Maps;
import com.google.inject.internal.MatcherAndConverter;
import com.google.inject.internal.Nullable;
-import static com.google.inject.internal.Preconditions.checkState;
import com.google.inject.internal.Scoping;
import com.google.inject.internal.SourceProvider;
import com.google.inject.internal.ToStringBuilder;
@@ -47,7 +46,6 @@
import com.google.inject.util.Providers;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
@@ -71,7 +69,7 @@
final InjectorImpl parent;
final BindingsMultimap bindingsMultimap = new BindingsMultimap();
final Initializer initializer;
- ConstructionProxyFactory constructionProxyFactory;
+ ImmutableList<MethodAspect> methodAspects;
/** Just-in-time binding cache. Guarded by state.lock() */
final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap();
@@ -226,7 +224,11 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) {
- return visitor.visitProviderBinding(this);
+ return visitor.visit(this);
+ }
+
+ public void applyTo(Binder binder) {
+ throw new UnsupportedOperationException("This element represents a synthetic binding.");
}
@Override public String toString() {
@@ -308,7 +310,7 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- return visitor.visitConvertedConstant(this);
+ return visitor.visit(this);
}
public T getValue() {
@@ -323,6 +325,10 @@
return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey()));
}
+ public void applyTo(Binder binder) {
+ throw new UnsupportedOperationException("This element represents a synthetic binding.");
+ }
+
@Override public String toString() {
return new ToStringBuilder(ConvertedConstantBinding.class)
.add("key", getKey())
@@ -336,13 +342,13 @@
// Put the partially constructed binding in the map a little early. This enables us to handle
// circular dependencies. Example: FooImpl -> BarImpl -> FooImpl.
// Note: We don't need to synchronize on state.lock() during injector creation.
- if (binding instanceof ClassBindingImpl<?>) {
+ // TODO: for the above example, remove the binding for BarImpl if the binding for FooImpl fails
+ if (binding instanceof ConstructorBindingImpl<?>) {
Key<T> key = binding.getKey();
jitBindings.put(key, binding);
boolean successful = false;
try {
- // TODO: does this put the binding in JIT bindings?
- binding.initialize(this, errors);
+ ((ConstructorBindingImpl) binding).initialize(this, errors);
successful = true;
} finally {
if (!successful) {
@@ -399,8 +405,6 @@
throw errors.cannotInjectInnerClass(rawType).toException();
}
- LateBoundConstructor<T> lateBoundConstructor = new LateBoundConstructor<T>();
-
if (!scoping.isExplicitlyScoped()) {
Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, rawType);
if (scopeAnnotation != null) {
@@ -409,10 +413,7 @@
}
}
- InternalFactory<? extends T> scopedFactory
- = Scopes.scope(key, this, lateBoundConstructor, scoping);
- return new ClassBindingImpl<T>(
- this, key, source, scopedFactory, scoping, lateBoundConstructor);
+ return ConstructorBindingImpl.create(this, key, source, scoping);
}
/**
@@ -445,34 +446,6 @@
factory, ImmutableSet.<InjectionPoint>of(), value);
}
- static class LateBoundConstructor<T> implements InternalFactory<T> {
- ConstructorInjector<T> constructorInjector;
-
- @SuppressWarnings("unchecked") // the constructor T is the same as the implementation T
- void bind(Injector injector, TypeLiteral<T> implementation, Errors errors)
- throws ErrorsException {
- InjectorImpl injectorImpl = (InjectorImpl) injector;
- constructorInjector
- = (ConstructorInjector<T>) injectorImpl.constructors.get(implementation, errors);
- }
-
- public Constructor<T> getConstructor() {
- checkState(constructorInjector != null, "Constructor is not ready");
- return constructorInjector.constructionProxy.getConstructor();
- }
-
- @SuppressWarnings("unchecked")
- public T get(Errors errors, InternalContext context, Dependency<?> dependency)
- throws ErrorsException {
- checkState(constructorInjector != null, "Construct before bind, " + constructorInjector);
-
- // This may not actually be safe because it could return a super type of T (if that's all the
- // client needs), but it should be OK in practice thanks to the wonders of erasure.
- return (T) constructorInjector.construct(
- errors, context, dependency.getKey().getRawType());
- }
- }
-
/** Creates a binding for a type annotated with @ProvidedBy. */
<T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scoping scoping,
ProvidedBy providedBy, Errors errors) throws ErrorsException {
@@ -751,14 +724,7 @@
}
/** Cached constructor injectors for each type */
- final FailableCache<TypeLiteral<?>, ConstructorInjector<?>> constructors
- = new FailableCache<TypeLiteral<?>, ConstructorInjector<?>>() {
- @SuppressWarnings("unchecked")
- protected ConstructorInjector<?> create(TypeLiteral<?> type, Errors errors)
- throws ErrorsException {
- return new ConstructorInjector(errors, InjectorImpl.this, type);
- }
- };
+ FailableCache<TypeLiteral<?>, ConstructorInjector<?>> constructors;
void injectMembers(Errors errors, Object o, InternalContext context,
List<SingleMemberInjector> injectors)
@@ -790,6 +756,14 @@
errors.throwProvisionExceptionIfErrorsExist();
}
+ public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
public void injectMembersOrThrow(final Errors errors, final Object o,
final List<SingleMemberInjector> injectors)
throws ErrorsException {
diff --git a/src/com/google/inject/InjectorShell.java b/src/com/google/inject/InjectorShell.java
index 69c4b74..7176729 100644
--- a/src/com/google/inject/InjectorShell.java
+++ b/src/com/google/inject/InjectorShell.java
@@ -146,6 +146,11 @@
injector.constructionProxyFactory = new DefaultConstructionProxyFactory();
end[NO_AOP]*/
+ new InjectableTypeListenerBindingProcessor(errors).process(injector, elements);
+ stopwatch.resetAndLog("InjectableType listeners creation");
+ injector.constructors = new ConstructorInjectorStore(
+ injector, injector.state.getInjectableTypeListenerBindings());
+
new ScopeBindingProcessor(errors).process(injector, elements);
stopwatch.resetAndLog("Scopes creation");
diff --git a/src/com/google/inject/InterceptorBindingProcessor.java b/src/com/google/inject/InterceptorBindingProcessor.java
index 3967355..da1419f 100644
--- a/src/com/google/inject/InterceptorBindingProcessor.java
+++ b/src/com/google/inject/InterceptorBindingProcessor.java
@@ -17,6 +17,7 @@
package com.google.inject;
import com.google.inject.internal.Errors;
+import com.google.inject.internal.ImmutableList;
import com.google.inject.spi.InterceptorBinding;
/**
@@ -31,13 +32,13 @@
super(errors);
}
- @Override public Boolean visitInterceptorBinding(InterceptorBinding command) {
+ @Override public Boolean visit(InterceptorBinding command) {
injector.state.addMethodAspect(new MethodAspect(
command.getClassMatcher(), command.getMethodMatcher(), command.getInterceptors()));
return true;
}
void setupProxyFactory(InjectorImpl injector) {
- injector.constructionProxyFactory = new ProxyFactory(injector.state.getMethodAspects());
+ injector.methodAspects = ImmutableList.copyOf(injector.state.getMethodAspects());
}
}
diff --git a/src/com/google/inject/MembersInjector.java b/src/com/google/inject/MembersInjector.java
new file mode 100644
index 0000000..d0c8125
--- /dev/null
+++ b/src/com/google/inject/MembersInjector.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 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;
+
+/**
+ * Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the
+ * presence or absence of an injectable constructor.
+ *
+ * @param <T> type to inject members of
+ *
+ * @author crazybob@google.com (Bob Lee)
+ * @author jessewilson@google.com (Jesse Wilson)
+ * @since 2.0
+ */
+public interface MembersInjector<T> {
+
+ /**
+ * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
+ * absence of an injectable constructor.
+ *
+ * <p>Whenever Guice creates an instance, it performs this injection automatically (after first
+ * performing constructor injection), so if you're able to let Guice create all your objects for
+ * you, you'll never need to use this method.
+ *
+ * @param instance to inject members on
+ */
+ void injectMembers(T instance);
+}
diff --git a/src/com/google/inject/MessageProcessor.java b/src/com/google/inject/MessageProcessor.java
index 1cf79eb..99b3d09 100644
--- a/src/com/google/inject/MessageProcessor.java
+++ b/src/com/google/inject/MessageProcessor.java
@@ -35,7 +35,7 @@
super(errors);
}
- @Override public Boolean visitMessage(Message message) {
+ @Override public Boolean visit(Message message) {
if (message.getCause() != null) {
String rootMessage = getRootMessage(message.getCause());
logger.log(Level.INFO,
diff --git a/src/com/google/inject/PrivateElementProcessor.java b/src/com/google/inject/PrivateElementProcessor.java
index 44b331f..a767b9f 100644
--- a/src/com/google/inject/PrivateElementProcessor.java
+++ b/src/com/google/inject/PrivateElementProcessor.java
@@ -36,7 +36,7 @@
this.stage = stage;
}
- @Override public Boolean visitPrivateElements(PrivateElements privateElements) {
+ @Override public Boolean visit(PrivateElements privateElements) {
InjectorShell.Builder builder = new InjectorShell.Builder()
.parent(injector)
.stage(stage)
diff --git a/src/com/google/inject/PrivateModule.java b/src/com/google/inject/PrivateModule.java
index 68dcecb..25cda90 100644
--- a/src/com/google/inject/PrivateModule.java
+++ b/src/com/google/inject/PrivateModule.java
@@ -24,6 +24,7 @@
import com.google.inject.matcher.Matcher;
import com.google.inject.spi.Message;
import com.google.inject.spi.TypeConverter;
+import com.google.inject.spi.InjectableType;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@@ -130,55 +131,94 @@
// everything below is copied from AbstractModule
+ /**
+ * Returns the current binder.
+ */
protected final PrivateBinder binder() {
return binder;
}
+ /**
+ * @see Binder#bindScope(Class, Scope)
+ */
protected final void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
binder.bindScope(scopeAnnotation, scope);
}
+ /**
+ * @see Binder#bind(Key)
+ */
protected final <T> LinkedBindingBuilder<T> bind(Key<T> key) {
return binder.bind(key);
}
+ /**
+ * @see Binder#bind(TypeLiteral)
+ */
protected final <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
return binder.bind(typeLiteral);
}
+ /**
+ * @see Binder#bind(Class)
+ */
protected final <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
return binder.bind(clazz);
}
+ /**
+ * @see Binder#bindConstant()
+ */
protected final AnnotatedConstantBindingBuilder bindConstant() {
return binder.bindConstant();
}
+ /**
+ * @see Binder#install(Module)
+ */
protected final void install(Module module) {
binder.install(module);
}
+ /**
+ * @see Binder#addError(String, Object[])
+ */
protected final void addError(String message, Object... arguments) {
binder.addError(message, arguments);
}
+ /**
+ * @see Binder#addError(Throwable)
+ */
protected final void addError(Throwable t) {
binder.addError(t);
}
+ /**
+ * @see Binder#addError(Message)
+ */
protected final void addError(Message message) {
binder.addError(message);
}
- protected final void requestInjection(Object... objects) {
- binder.requestInjection(objects);
+ /**
+ * @see Binder#requestInjection(Object)
+ */
+ protected final void requestInjection(Object instance) {
+ binder.requestInjection(instance);
}
+ /**
+ * @see Binder#requestStaticInjection(Class[])
+ */
protected final void requestStaticInjection(Class<?>... types) {
binder.requestStaticInjection(types);
}
/*if[AOP]*/
+ /**
+ * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher, com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
+ */
protected final void bindInterceptor(Matcher<? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher,
org.aopalliance.intercept.MethodInterceptor... interceptors) {
@@ -186,28 +226,68 @@
}
/*end[AOP]*/
+ /**
+ * Instructs Guice to require a binding to the given key.
+ */
protected final void requireBinding(Key<?> key) {
binder.getProvider(key);
}
+ /**
+ * Instructs Guice to require a binding to the given type.
+ */
protected final void requireBinding(Class<?> type) {
binder.getProvider(type);
}
+ /**
+ * @see Binder#getProvider(Key)
+ */
protected final <T> Provider<T> getProvider(Key<T> key) {
return binder.getProvider(key);
}
-
+
+ /**
+ * @see Binder#getProvider(Class)
+ */
protected final <T> Provider<T> getProvider(Class<T> type) {
return binder.getProvider(type);
}
+ /**
+ * @see Binder#convertToTypes(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeConverter)
+ */
protected final void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
TypeConverter converter) {
binder.convertToTypes(typeMatcher, converter);
}
+ /**
+ * @see Binder#currentStage()
+ */
protected final Stage currentStage() {
return binder.currentStage();
}
+
+ /**
+ * @see Binder#getMembersInjector(Class)
+ */
+ protected <T> MembersInjector<T> getMembersInjector(Class<T> type) {
+ return binder.getMembersInjector(type);
+ }
+
+ /**
+ * @see Binder#getMembersInjector(TypeLiteral)
+ */
+ protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
+ return binder.getMembersInjector(type);
+ }
+
+ /**
+ * @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.InjectableType.Listener)
+ */
+ protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
+ InjectableType.Listener listener) {
+ binder.bindListener(typeMatcher, listener);
+ }
}
diff --git a/src/com/google/inject/ProviderLookupProcessor.java b/src/com/google/inject/ProviderLookupProcessor.java
index 8c06228..689adde 100644
--- a/src/com/google/inject/ProviderLookupProcessor.java
+++ b/src/com/google/inject/ProviderLookupProcessor.java
@@ -32,11 +32,11 @@
super(errors);
}
- @Override public <T> Boolean visitProviderLookup(ProviderLookup<T> command) {
+ @Override public <T> Boolean visit(ProviderLookup<T> command) {
// ensure the provider can be created
try {
Provider<T> provider = injector.getProviderOrThrow(command.getKey(), errors);
- command.initDelegate(provider);
+ command.initializeDelegate(provider);
} catch (ErrorsException e) {
errors.merge(e.getErrors()); // TODO: source
}
diff --git a/src/com/google/inject/ProxyFactory.java b/src/com/google/inject/ProxyFactory.java
index 0143e2e..bac5382 100644
--- a/src/com/google/inject/ProxyFactory.java
+++ b/src/com/google/inject/ProxyFactory.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2006 Google Inc.
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,13 +17,10 @@
package com.google.inject;
import com.google.inject.internal.BytecodeGen;
-import com.google.inject.internal.BytecodeGen.Visibility;
-import static com.google.inject.internal.BytecodeGen.newEnhancer;
-import com.google.inject.internal.Function;
+import static com.google.inject.internal.BytecodeGen.newFastClass;
import com.google.inject.internal.ImmutableList;
import com.google.inject.internal.ImmutableMap;
import com.google.inject.internal.Lists;
-import com.google.inject.internal.MapMaker;
import com.google.inject.internal.Maps;
import com.google.inject.spi.InjectionPoint;
import java.lang.reflect.Constructor;
@@ -41,92 +38,12 @@
import org.aopalliance.intercept.MethodInterceptor;
/**
- * Proxies classes applying interceptors to methods.
+ * Builds a construction proxy that can participate in AOP. This class manages applying type and
+ * method matchers to come up with the set of intercepted methods.
*
- * @author crazybob@google.com (Bob Lee)
+ * @author jessewilson@google.com (Jesse Wilson)
*/
-class ProxyFactory implements ConstructionProxyFactory {
-
- final List<MethodAspect> methodAspects;
- final ConstructionProxyFactory defaultFactory;
-
- ProxyFactory(List<MethodAspect> methodAspects) {
- this.methodAspects = methodAspects;
- defaultFactory = new DefaultConstructionProxyFactory();
- }
-
- /** Cached construction proxies for each injection point */
- Map<InjectionPoint, ConstructionProxy> constructionProxies = new MapMaker().makeComputingMap(
- new Function<InjectionPoint, ConstructionProxy>() {
- public ConstructionProxy apply(InjectionPoint key) {
- return createConstructionProxy(key);
- }
- });
-
- @SuppressWarnings("unchecked") // the constructed T is the same as the injection point's T
- public <T> ConstructionProxy<T> get(InjectionPoint injectionPoint) {
- return (ConstructionProxy<T>) constructionProxies.get(injectionPoint);
- }
-
- // TODO: This isn't safe.
- <T> ConstructionProxy<T> createConstructionProxy(InjectionPoint injectionPoint) {
- @SuppressWarnings("unchecked") // the member of injectionPoint is always a Constructor<T>
- Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
- Class<T> declaringClass = constructor.getDeclaringClass();
-
- // Find applicable aspects. Bow out if none are applicable to this class.
- List<MethodAspect> applicableAspects = Lists.newArrayList();
- for (MethodAspect methodAspect : methodAspects) {
- if (methodAspect.matches(declaringClass)) {
- applicableAspects.add(methodAspect);
- }
- }
- if (applicableAspects.isEmpty()) {
- return defaultFactory.get(injectionPoint);
- }
-
- // Get list of methods from cglib.
- List<Method> methods = Lists.newArrayList();
- Enhancer.getMethods(declaringClass, null, methods);
-
- // Create method/interceptor holders and record indices.
- List<MethodInterceptorsPair> methodInterceptorsPairs = Lists.newArrayList();
- for (Method method : methods) {
- methodInterceptorsPairs.add(new MethodInterceptorsPair(method));
- }
-
- // PUBLIC if all the methods we're intercepting are public. This impacts which classloader we
- // should use for loading the enhanced class
- Visibility visibility = Visibility.PUBLIC;
-
- // Iterate over aspects and add interceptors for the methods they apply to
- boolean anyMatched = false;
- for (MethodAspect methodAspect : applicableAspects) {
- for (MethodInterceptorsPair pair : methodInterceptorsPairs) {
- if (methodAspect.matches(pair.method)) {
- visibility = visibility.and(Visibility.forMember(pair.method));
- pair.addAll(methodAspect.interceptors());
- anyMatched = true;
- }
- }
- }
- if (!anyMatched) {
- // not test-covered
- return defaultFactory.get(injectionPoint);
- }
-
- @SuppressWarnings("unchecked")
- Class<? extends Callback>[] callbackTypes = new Class[methods.size()];
- Arrays.fill(callbackTypes, net.sf.cglib.proxy.MethodInterceptor.class);
-
- // Create the proxied class. We're careful to ensure that all enhancer state is not-specific to
- // this injector. Otherwise, the proxies for each injector will waste Permgen memory
- Enhancer enhancer = newEnhancer(declaringClass, visibility);
- enhancer.setCallbackFilter(new IndicesCallbackFilter(declaringClass, methods));
- enhancer.setCallbackTypes(callbackTypes);
-
- return new ProxyConstructor<T>(methods, methodInterceptorsPairs, enhancer, injectionPoint);
- }
+class ProxyFactory<T> implements ConstructionProxyFactory<T> {
private static final net.sf.cglib.proxy.MethodInterceptor NO_OP_METHOD_INTERCEPTOR
= new net.sf.cglib.proxy.MethodInterceptor() {
@@ -137,78 +54,122 @@
}
};
+ private final InjectionPoint injectionPoint;
+ private final ImmutableMap<Method, List<MethodInterceptor>> interceptors;
+ private final Class<T> declaringClass;
+ private final List<Method> methods;
+ private final Callback[] callbacks;
+
/**
- * Constructs instances that participate in AOP.
+ * PUBLIC is default; it's used if all the methods we're intercepting are public. This impacts
+ * which classloader we should use for loading the enhanced class
*/
- private static class ProxyConstructor<T> implements ConstructionProxy<T> {
- private final Class<?> enhanced;
- private final InjectionPoint injectionPoint;
- private final Constructor<T> constructor;
+ private BytecodeGen.Visibility visibility = BytecodeGen.Visibility.PUBLIC;
- private final Callback[] callbacks;
- private final FastConstructor fastConstructor;
- private final ImmutableMap<Method, List<MethodInterceptor>> methodInterceptors;
+ ProxyFactory(InjectionPoint injectionPoint, Iterable<MethodAspect> methodAspects) {
+ this.injectionPoint = injectionPoint;
- @SuppressWarnings("unchecked") // the constructor promises to construct 'T's
- ProxyConstructor(List<Method> methods, List<MethodInterceptorsPair> methodInterceptorsPairs,
- Enhancer enhancer, InjectionPoint injectionPoint) {
- this.enhanced = enhancer.createClass(); // this returns a cached class if possible
- this.injectionPoint = injectionPoint;
- this.constructor = (Constructor<T>) injectionPoint.getMember();
+ @SuppressWarnings("unchecked") // the member of injectionPoint is always a Constructor<T>
+ Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
+ declaringClass = constructor.getDeclaringClass();
- ImmutableMap.Builder<Method, List<MethodInterceptor>> interceptorsMapBuilder = null; // lazy
-
- this.callbacks = new Callback[methods.size()];
- for (int i = 0; i < methods.size(); i++) {
- MethodInterceptorsPair pair = methodInterceptorsPairs.get(i);
-
- if (!pair.hasInterceptors()) {
- callbacks[i] = NO_OP_METHOD_INTERCEPTOR;
- continue;
- }
-
- if (interceptorsMapBuilder == null) {
- interceptorsMapBuilder = ImmutableMap.builder();
- }
- interceptorsMapBuilder.put(pair.method, ImmutableList.copyOf(pair.interceptors));
- callbacks[i] = new InterceptorStackCallback(pair.method, pair.interceptors);
- }
-
- FastClass fastClass = BytecodeGen.newFastClass(enhanced, Visibility.forMember(constructor));
- this.fastConstructor = fastClass.getConstructor(constructor.getParameterTypes());
- this.methodInterceptors = interceptorsMapBuilder != null
- ? interceptorsMapBuilder.build()
- : ImmutableMap.<Method, List<MethodInterceptor>>of();
- }
-
- @SuppressWarnings("unchecked") // the constructor promises to produce 'T's
- public T newInstance(Object[] arguments) throws InvocationTargetException {
- Enhancer.registerCallbacks(enhanced, callbacks);
- try {
- return (T) fastConstructor.newInstance(arguments);
- } finally {
- Enhancer.registerCallbacks(enhanced, null);
+ // Find applicable aspects. Bow out if none are applicable to this class.
+ List<MethodAspect> applicableAspects = Lists.newArrayList();
+ for (MethodAspect methodAspect : methodAspects) {
+ if (methodAspect.matches(declaringClass)) {
+ applicableAspects.add(methodAspect);
}
}
- public InjectionPoint getInjectionPoint() {
- return injectionPoint;
+ if (applicableAspects.isEmpty()) {
+ interceptors = ImmutableMap.of();
+ methods = ImmutableList.of();
+ callbacks = null;
+ return;
}
- public Constructor<T> getConstructor() {
- return constructor;
+ // Get list of methods from cglib.
+ methods = Lists.newArrayList();
+ Enhancer.getMethods(declaringClass, null, methods);
+
+ // Create method/interceptor holders and record indices.
+ List<MethodInterceptorsPair> methodInterceptorsPairs = Lists.newArrayList();
+ for (Method method : methods) {
+ methodInterceptorsPairs.add(new MethodInterceptorsPair(method));
}
- public Map<Method, List<MethodInterceptor>> getMethodInterceptors() {
- return methodInterceptors;
+ // Iterate over aspects and add interceptors for the methods they apply to
+ boolean anyMatched = false;
+ for (MethodAspect methodAspect : applicableAspects) {
+ for (MethodInterceptorsPair pair : methodInterceptorsPairs) {
+ if (methodAspect.matches(pair.method)) {
+ visibility = visibility.and(BytecodeGen.Visibility.forMember(pair.method));
+ pair.addAll(methodAspect.interceptors());
+ anyMatched = true;
+ }
+ }
}
+
+ if (!anyMatched) {
+ interceptors = ImmutableMap.of();
+ callbacks = null;
+ return;
+ }
+
+ ImmutableMap.Builder<Method, List<MethodInterceptor>> interceptorsMapBuilder = null; // lazy
+
+ callbacks = new Callback[methods.size()];
+ for (int i = 0; i < methods.size(); i++) {
+ MethodInterceptorsPair pair = methodInterceptorsPairs.get(i);
+
+ if (!pair.hasInterceptors()) {
+ callbacks[i] = NO_OP_METHOD_INTERCEPTOR;
+ continue;
+ }
+
+ if (interceptorsMapBuilder == null) {
+ interceptorsMapBuilder = ImmutableMap.builder();
+ }
+
+ interceptorsMapBuilder.put(pair.method, ImmutableList.copyOf(pair.interceptors));
+ callbacks[i] = new InterceptorStackCallback(pair.method, pair.interceptors);
+ }
+
+ interceptors = interceptorsMapBuilder != null
+ ? interceptorsMapBuilder.build()
+ : ImmutableMap.<Method, List<MethodInterceptor>>of();
+ }
+
+ /**
+ * Returns the interceptors that apply to the constructed type. When InjectableType.Listeners
+ * add additional interceptors, this builder will be thrown out and another created.n
+ */
+ public ImmutableMap<Method, List<MethodInterceptor>> getInterceptors() {
+ return interceptors;
+ }
+
+ public ConstructionProxy<T> create() {
+ if (interceptors.isEmpty()) {
+ return new DefaultConstructionProxyFactory<T>(injectionPoint).create();
+ }
+
+ @SuppressWarnings("unchecked")
+ Class<? extends Callback>[] callbackTypes = new Class[methods.size()];
+ Arrays.fill(callbackTypes, net.sf.cglib.proxy.MethodInterceptor.class);
+
+ // Create the proxied class. We're careful to ensure that all enhancer state is not-specific
+ // to this injector. Otherwise, the proxies for each injector will waste PermGen memory
+ Enhancer enhancer = BytecodeGen.newEnhancer(declaringClass, visibility);
+ enhancer.setCallbackFilter(new IndicesCallbackFilter(declaringClass, methods));
+ enhancer.setCallbackTypes(callbackTypes);
+ return new ProxyConstructor<T>(enhancer, injectionPoint, callbacks, interceptors);
}
private static class MethodInterceptorsPair {
final Method method;
- List<MethodInterceptor> interceptors;
+ List<MethodInterceptor> interceptors; // lazy
- public MethodInterceptorsPair(Method method) {
+ MethodInterceptorsPair(Method method) {
this.method = method;
}
@@ -232,7 +193,7 @@
final Class<?> declaringClass;
final Map<Method, Integer> indices;
- public IndicesCallbackFilter(Class<?> declaringClass, List<Method> methods) {
+ IndicesCallbackFilter(Class<?> declaringClass, List<Method> methods) {
this.declaringClass = declaringClass;
final Map<Method, Integer> indices = Maps.newHashMap();
for (int i = 0; i < methods.size(); i++) {
@@ -256,4 +217,52 @@
return declaringClass.hashCode();
}
}
+
+ /**
+ * Constructs instances that participate in AOP.
+ */
+ private static class ProxyConstructor<T> implements ConstructionProxy<T> {
+ final Class<?> enhanced;
+ final InjectionPoint injectionPoint;
+ final Constructor<T> constructor;
+ final Callback[] callbacks;
+
+ final FastConstructor fastConstructor;
+ final ImmutableMap<Method, List<MethodInterceptor>> methodInterceptors;
+
+ @SuppressWarnings("unchecked") // the constructor promises to construct 'T's
+ ProxyConstructor(Enhancer enhancer, InjectionPoint injectionPoint, Callback[] callbacks,
+ ImmutableMap<Method, List<MethodInterceptor>> methodInterceptors) {
+ this.enhanced = enhancer.createClass(); // this returns a cached class if possible
+ this.injectionPoint = injectionPoint;
+ this.constructor = (Constructor<T>) injectionPoint.getMember();
+ this.callbacks = callbacks;
+ this.methodInterceptors = methodInterceptors;
+
+ FastClass fastClass = newFastClass(enhanced, BytecodeGen.Visibility.forMember(constructor));
+ this.fastConstructor = fastClass.getConstructor(constructor.getParameterTypes());
+ }
+
+ @SuppressWarnings("unchecked") // the constructor promises to produce 'T's
+ public T newInstance(Object[] arguments) throws InvocationTargetException {
+ Enhancer.registerCallbacks(enhanced, callbacks);
+ try {
+ return (T) fastConstructor.newInstance(arguments);
+ } finally {
+ Enhancer.registerCallbacks(enhanced, null);
+ }
+ }
+
+ public InjectionPoint getInjectionPoint() {
+ return injectionPoint;
+ }
+
+ public Constructor<T> getConstructor() {
+ return constructor;
+ }
+
+ public Map<Method, List<MethodInterceptor>> getMethodInterceptors() {
+ return methodInterceptors;
+ }
+ }
}
diff --git a/src/com/google/inject/ScopeBindingProcessor.java b/src/com/google/inject/ScopeBindingProcessor.java
index 4dcbd3d..79bce81 100644
--- a/src/com/google/inject/ScopeBindingProcessor.java
+++ b/src/com/google/inject/ScopeBindingProcessor.java
@@ -34,7 +34,7 @@
super(errors);
}
- @Override public Boolean visitScopeBinding(ScopeBinding command) {
+ @Override public Boolean visit(ScopeBinding command) {
Scope scope = command.getScope();
Class<? extends Annotation> annotationType = command.getAnnotationType();
diff --git a/src/com/google/inject/State.java b/src/com/google/inject/State.java
index 058e229..7411aee 100644
--- a/src/com/google/inject/State.java
+++ b/src/com/google/inject/State.java
@@ -21,6 +21,7 @@
import com.google.inject.internal.ImmutableList;
import com.google.inject.internal.ImmutableSet;
import com.google.inject.internal.MatcherAndConverter;
+import com.google.inject.spi.InjectableTypeListenerBinding;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
@@ -81,6 +82,15 @@
}
/*end[AOP]*/
+ public void addInjectableTypeListener(
+ InjectableTypeListenerBinding injectableTypeListenerBinding) {
+ throw new UnsupportedOperationException();
+ }
+
+ public List<InjectableTypeListenerBinding> getInjectableTypeListenerBindings() {
+ return ImmutableList.of();
+ }
+
public void blacklist(Key<?> key) {
}
@@ -123,6 +133,10 @@
List<MethodAspect> getMethodAspects();
/*end[AOP]*/
+ void addInjectableTypeListener(InjectableTypeListenerBinding injectableTypeListenerBinding);
+
+ List<InjectableTypeListenerBinding> getInjectableTypeListenerBindings();
+
/**
* Forbids the corresponding injector from creating a binding to {@code key}. Child injectors
* blacklist their bound keys on their parent injectors to prevent just-in-time bindings on the
diff --git a/src/com/google/inject/TypeConverterBindingProcessor.java b/src/com/google/inject/TypeConverterBindingProcessor.java
index b2e5885..967ec97 100644
--- a/src/com/google/inject/TypeConverterBindingProcessor.java
+++ b/src/com/google/inject/TypeConverterBindingProcessor.java
@@ -166,7 +166,7 @@
new MatcherAndConverter(typeMatcher, converter, SourceProvider.UNKNOWN_SOURCE));
}
- @Override public Boolean visitTypeConverterBinding(TypeConverterBinding command) {
+ @Override public Boolean visit(TypeConverterBinding command) {
injector.state.addConverter(new MatcherAndConverter(
command.getTypeMatcher(), command.getTypeConverter(), command.getSource()));
return true;
diff --git a/src/com/google/inject/internal/BindingImpl.java b/src/com/google/inject/internal/BindingImpl.java
index 625b9ee..471dae3 100644
--- a/src/com/google/inject/internal/BindingImpl.java
+++ b/src/com/google/inject/internal/BindingImpl.java
@@ -90,18 +90,13 @@
}
public <V> V acceptVisitor(ElementVisitor<V> visitor) {
- return visitor.visitBinding(this);
+ return visitor.visit(this);
}
public <V> V acceptScopingVisitor(BindingScopingVisitor<V> visitor) {
return scoping.acceptVisitor(visitor);
}
- /**
- * Perform any post-creation initialization, that could require construction of other bindings.
- */
- public void initialize(Injector injector, Errors errors) throws ErrorsException {}
-
protected BindingImpl<T> withScoping(Scoping scoping) {
throw new AssertionError();
}
diff --git a/src/com/google/inject/internal/ExposedBindingImpl.java b/src/com/google/inject/internal/ExposedBindingImpl.java
index 2518cab..9e59a5c 100644
--- a/src/com/google/inject/internal/ExposedBindingImpl.java
+++ b/src/com/google/inject/internal/ExposedBindingImpl.java
@@ -16,6 +16,7 @@
package com.google.inject.internal;
+import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.spi.BindingTargetVisitor;
@@ -41,7 +42,7 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- return visitor.visitExposed(this);
+ return visitor.visit(this);
}
public Set<Dependency<?>> getDependencies() {
@@ -67,4 +68,8 @@
.add("privateElements", privateElements)
.toString();
}
+
+ public void applyTo(Binder binder) {
+ throw new UnsupportedOperationException("This element represents a synthetic binding.");
+ }
}
diff --git a/src/com/google/inject/internal/InstanceBindingImpl.java b/src/com/google/inject/internal/InstanceBindingImpl.java
index 92dc559..efa3f12 100644
--- a/src/com/google/inject/internal/InstanceBindingImpl.java
+++ b/src/com/google/inject/internal/InstanceBindingImpl.java
@@ -19,6 +19,7 @@
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
+import com.google.inject.Binder;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
@@ -55,7 +56,7 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- return visitor.visitInstance(this);
+ return visitor.visit(this);
}
public T getInstance() {
@@ -80,6 +81,11 @@
return new InstanceBindingImpl<T>(getSource(), key, getScoping(), injectionPoints, instance);
}
+ public void applyTo(Binder binder) {
+ // instance bindings aren't scoped
+ binder.withSource(getSource()).bind(getKey()).toInstance(instance);
+ }
+
@Override public String toString() {
return new ToStringBuilder(InstanceBinding.class)
.add("key", getKey())
diff --git a/src/com/google/inject/internal/LinkedBindingImpl.java b/src/com/google/inject/internal/LinkedBindingImpl.java
index 01485ba..0b29e0a 100644
--- a/src/com/google/inject/internal/LinkedBindingImpl.java
+++ b/src/com/google/inject/internal/LinkedBindingImpl.java
@@ -18,6 +18,7 @@
import com.google.inject.Injector;
import com.google.inject.Key;
+import com.google.inject.Binder;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.LinkedKeyBinding;
@@ -38,7 +39,7 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- return visitor.visitLinkedKey(this);
+ return visitor.visit(this);
}
public Key<? extends T> getLinkedKey() {
@@ -53,6 +54,10 @@
return new LinkedBindingImpl<T>(getSource(), key, getScoping(), targetKey);
}
+ public void applyTo(Binder binder) {
+ getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).to(getLinkedKey()));
+ }
+
@Override public String toString() {
return new ToStringBuilder(LinkedKeyBinding.class)
.add("key", getKey())
diff --git a/src/com/google/inject/internal/LinkedProviderBindingImpl.java b/src/com/google/inject/internal/LinkedProviderBindingImpl.java
index fe3a39f..38393dd 100644
--- a/src/com/google/inject/internal/LinkedProviderBindingImpl.java
+++ b/src/com/google/inject/internal/LinkedProviderBindingImpl.java
@@ -19,6 +19,7 @@
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
+import com.google.inject.Binder;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.ProviderKeyBinding;
@@ -41,7 +42,7 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- return visitor.visitProviderKey(this);
+ return visitor.visit(this);
}
public Key<? extends Provider<? extends T>> getProviderKey() {
@@ -56,6 +57,10 @@
return new LinkedProviderBindingImpl<T>(getSource(), key, getScoping(), providerKey);
}
+ public void applyTo(Binder binder) {
+ getScoping().applyTo(binder.bind(getKey()).toProvider(getProviderKey()));
+ }
+
@Override public String toString() {
return new ToStringBuilder(ProviderKeyBinding.class)
.add("key", getKey())
diff --git a/src/com/google/inject/internal/PrivateElementsImpl.java b/src/com/google/inject/internal/PrivateElementsImpl.java
index 0888309..92990d3 100644
--- a/src/com/google/inject/internal/PrivateElementsImpl.java
+++ b/src/com/google/inject/internal/PrivateElementsImpl.java
@@ -18,6 +18,7 @@
import com.google.inject.Injector;
import com.google.inject.Key;
+import com.google.inject.Binder;
import com.google.inject.internal.BindingBuilder.ExposureBuilder;
import static com.google.inject.internal.Preconditions.checkNotNull;
import static com.google.inject.internal.Preconditions.checkState;
@@ -90,7 +91,7 @@
}
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitPrivateElements(this);
+ return visitor.visit(this);
}
public List<Element> getElementsMutable() {
@@ -100,4 +101,8 @@
public void addExposureBuilder(ExposureBuilder<?> exposureBuilder) {
exposureBuilders.add(exposureBuilder);
}
+
+ public void applyTo(Binder binder) {
+ throw new UnsupportedOperationException("TODO");
+ }
}
diff --git a/src/com/google/inject/internal/ProviderInstanceBindingImpl.java b/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
index 4dc38f9..907e000 100644
--- a/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
+++ b/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
@@ -19,6 +19,7 @@
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
+import com.google.inject.Binder;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
@@ -49,7 +50,7 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- return visitor.visitProviderInstance(this);
+ return visitor.visit(this);
}
public Provider<? extends T> getProviderInstance() {
@@ -76,6 +77,11 @@
getSource(), key, getScoping(), injectionPoints, providerInstance);
}
+ public void applyTo(Binder binder) {
+ getScoping().applyTo(
+ binder.withSource(getSource()).bind(getKey()).toProvider(getProviderInstance()));
+ }
+
@Override
public String toString() {
return new ToStringBuilder(ProviderInstanceBinding.class)
diff --git a/src/com/google/inject/internal/Scoping.java b/src/com/google/inject/internal/Scoping.java
index d39b4ba..a0b3583 100644
--- a/src/com/google/inject/internal/Scoping.java
+++ b/src/com/google/inject/internal/Scoping.java
@@ -20,6 +20,7 @@
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.Stage;
+import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.spi.BindingScopingVisitor;
import java.lang.annotation.Annotation;
@@ -47,6 +48,10 @@
@Override public String toString() {
return Scopes.NO_SCOPE.toString();
}
+
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ // do nothing
+ }
};
public static final Scoping SINGLETON_ANNOTATION = new Scoping() {
@@ -61,6 +66,10 @@
@Override public String toString() {
return Singleton.class.getName();
}
+
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.in(Singleton.class);
+ }
};
public static final Scoping SINGLETON_INSTANCE = new Scoping() {
@@ -75,6 +84,10 @@
@Override public String toString() {
return Scopes.SINGLETON.toString();
}
+
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.in(Scopes.SINGLETON);
+ }
};
public static final Scoping EAGER_SINGLETON = new Scoping() {
@@ -89,6 +102,10 @@
@Override public String toString() {
return "eager singleton";
}
+
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.asEagerSingleton();
+ }
};
public static Scoping forAnnotation(final Class<? extends Annotation> scopingAnnotation) {
@@ -108,6 +125,10 @@
@Override public String toString() {
return scopingAnnotation.getName();
}
+
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.in(scopingAnnotation);
+ }
};
}
@@ -128,6 +149,10 @@
@Override public String toString() {
return scope.toString();
}
+
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.in(scope);
+ }
};
}
@@ -178,5 +203,7 @@
public abstract <V> V acceptVisitor(BindingScopingVisitor<V> visitor);
+ public abstract void applyTo(ScopedBindingBuilder scopedBindingBuilder);
+
private Scoping() {}
}
diff --git a/src/com/google/inject/internal/UntargettedBindingImpl.java b/src/com/google/inject/internal/UntargettedBindingImpl.java
index 90d7796..3e410e2 100644
--- a/src/com/google/inject/internal/UntargettedBindingImpl.java
+++ b/src/com/google/inject/internal/UntargettedBindingImpl.java
@@ -18,6 +18,7 @@
import com.google.inject.Injector;
import com.google.inject.Key;
+import com.google.inject.Binder;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.UntargettedBinding;
@@ -37,7 +38,7 @@
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- return visitor.visitUntargetted(this);
+ return visitor.visit(this);
}
public BindingImpl<T> withScoping(Scoping scoping) {
@@ -48,6 +49,10 @@
return new UntargettedBindingImpl<T>(getSource(), key, getScoping());
}
+ public void applyTo(Binder binder) {
+ getScoping().applyTo(binder.withSource(getSource()).bind(getKey()));
+ }
+
@Override public String toString() {
return new ToStringBuilder(UntargettedBinding.class)
.add("key", getKey())
diff --git a/src/com/google/inject/spi/BindingTargetVisitor.java b/src/com/google/inject/spi/BindingTargetVisitor.java
index d69506b..cfb57d7 100644
--- a/src/com/google/inject/spi/BindingTargetVisitor.java
+++ b/src/com/google/inject/spi/BindingTargetVisitor.java
@@ -29,55 +29,55 @@
* Visit a instance binding. The same instance is returned for every injection. This target is
* found in both module and injector bindings.
*/
- V visitInstance(InstanceBinding<? extends T> binding);
+ V visit(InstanceBinding<? extends T> binding);
/**
* Visit a provider instance binding. The provider's {@code get} method is invoked to resolve
* injections. This target is found in both module and injector bindings.
*/
- V visitProviderInstance(ProviderInstanceBinding<? extends T> binding);
+ V visit(ProviderInstanceBinding<? extends T> binding);
/**
* Visit a provider key binding. To resolve injections, the provider key is first resolved, then
* that provider's {@code get} method is invoked. This target is found in both module and injector
* bindings.
*/
- V visitProviderKey(ProviderKeyBinding<? extends T> binding);
+ V visit(ProviderKeyBinding<? extends T> binding);
/**
* Visit a linked key binding. The other key's binding is used to resolve injections. This
* target is found in both module and injector bindings.
*/
- V visitLinkedKey(LinkedKeyBinding<? extends T> binding);
+ V visit(LinkedKeyBinding<? extends T> binding);
/**
* Visit a binding to a key exposed from an enclosed private environment. This target is found in
* both module and injector bindings.
*/
- V visitExposed(ExposedBinding<? extends T> binding);
+ V visit(ExposedBinding<? extends T> binding);
/**
* Visit an untargetted binding. This target is found only on module bindings. It indicates
* that the injector should use its implicit binding strategies to resolve injections.
*/
- V visitUntargetted(UntargettedBinding<? extends T> binding);
+ V visit(UntargettedBinding<? extends T> binding);
/**
* Visit a constructor binding. To resolve injections, an instance is instantiated by invoking
* {@code constructor}. This target is found only on injector bindings.
*/
- V visitConstructor(ConstructorBinding<? extends T> binding);
+ V visit(ConstructorBinding<? extends T> binding);
/**
* Visit a binding created from converting a bound instance to a new type. The source binding
* has the same binding annotation but a different type. This target is found only on injector
* bindings.
*/
- V visitConvertedConstant(ConvertedConstantBinding<? extends T> binding);
+ V visit(ConvertedConstantBinding<? extends T> binding);
/**
* Visit a binding to a {@link com.google.inject.Provider} that delegates to the binding for the
* provided type. This target is found only on injector bindings.
*/
- V visitProviderBinding(ProviderBinding<? extends T> binding);
+ V visit(ProviderBinding<? extends T> binding);
}
diff --git a/src/com/google/inject/spi/ConstructorBinding.java b/src/com/google/inject/spi/ConstructorBinding.java
index e7dd163..7bc3e84 100644
--- a/src/com/google/inject/spi/ConstructorBinding.java
+++ b/src/com/google/inject/spi/ConstructorBinding.java
@@ -18,10 +18,6 @@
import com.google.inject.Binding;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
/**
* A binding to the constructor of a concrete clss. To resolve injections, an instance is
@@ -33,24 +29,12 @@
public interface ConstructorBinding<T> extends Binding<T>, HasDependencies {
/**
- * Returns the {@link com.google.inject.Inject annotated} or default constructor that is invoked
- * for creating values.
+ * Returns the injected type.
*/
- Constructor<? extends T> getConstructor();
+ InjectableType<T> getInjectableType();
/**
- * Returns the constructor, field and method injection points to create and populate a new
- * instance. The set contains exactly one constructor injection point.
+ * Gets the constructor this binding injects.
*/
- Set<InjectionPoint> getInjectionPoints();
-
- /*if[AOP]*/
- /**
- * Returns the interceptors applied to each method, in the order that they will be applied.
- *
- * @return a possibly empty map
- */
- Map<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors();
- /*end[AOP]*/
-
+ Constructor<?> getConstructor();
}
\ No newline at end of file
diff --git a/src/com/google/inject/spi/DefaultBindingScopingVisitor.java b/src/com/google/inject/spi/DefaultBindingScopingVisitor.java
index 0f59e88..f034187 100644
--- a/src/com/google/inject/spi/DefaultBindingScopingVisitor.java
+++ b/src/com/google/inject/spi/DefaultBindingScopingVisitor.java
@@ -31,6 +31,9 @@
*/
public class DefaultBindingScopingVisitor<V> implements BindingScopingVisitor<V> {
+ /**
+ * Default visit implementation. Returns {@code null}.
+ */
protected V visitOther() {
return null;
}
diff --git a/src/com/google/inject/spi/DefaultBindingTargetVisitor.java b/src/com/google/inject/spi/DefaultBindingTargetVisitor.java
index 638f1ff..e5cfd4d 100644
--- a/src/com/google/inject/spi/DefaultBindingTargetVisitor.java
+++ b/src/com/google/inject/spi/DefaultBindingTargetVisitor.java
@@ -30,45 +30,48 @@
*/
public abstract class DefaultBindingTargetVisitor<T, V> implements BindingTargetVisitor<T, V> {
+ /**
+ * Default visit implementation. Returns {@code null}.
+ */
protected V visitOther(Binding<? extends T> binding) {
return null;
}
- public V visitInstance(InstanceBinding<? extends T> instanceBinding) {
+ public V visit(InstanceBinding<? extends T> instanceBinding) {
return visitOther(instanceBinding);
}
- public V visitProviderInstance(ProviderInstanceBinding<? extends T> providerInstanceBinding) {
+ public V visit(ProviderInstanceBinding<? extends T> providerInstanceBinding) {
return visitOther(providerInstanceBinding);
}
- public V visitProviderKey(ProviderKeyBinding<? extends T> providerKeyBinding) {
+ public V visit(ProviderKeyBinding<? extends T> providerKeyBinding) {
return visitOther(providerKeyBinding);
}
- public V visitLinkedKey(LinkedKeyBinding<? extends T> linkedKeyBinding) {
+ public V visit(LinkedKeyBinding<? extends T> linkedKeyBinding) {
return visitOther(linkedKeyBinding);
}
- public V visitExposed(ExposedBinding<? extends T> exposedBinding) {
+ public V visit(ExposedBinding<? extends T> exposedBinding) {
return visitOther(exposedBinding);
}
- public V visitUntargetted(UntargettedBinding<? extends T> untargettedBinding) {
+ public V visit(UntargettedBinding<? extends T> untargettedBinding) {
return visitOther(untargettedBinding);
}
- public V visitConstructor(ConstructorBinding<? extends T> constructorBinding) {
+ public V visit(ConstructorBinding<? extends T> constructorBinding) {
return visitOther(constructorBinding);
}
- public V visitConvertedConstant(ConvertedConstantBinding<? extends T> convertedConstantBinding) {
+ public V visit(ConvertedConstantBinding<? extends T> convertedConstantBinding) {
return visitOther(convertedConstantBinding);
}
// javac says it's an error to cast ProviderBinding<? extends T> to Binding<? extends T>
@SuppressWarnings("unchecked")
- public V visitProviderBinding(ProviderBinding<? extends T> providerBinding) {
+ public V visit(ProviderBinding<? extends T> providerBinding) {
return visitOther((Binding) providerBinding);
}
}
diff --git a/src/com/google/inject/spi/DefaultElementVisitor.java b/src/com/google/inject/spi/DefaultElementVisitor.java
index 5afb7f0..77c0e1d 100644
--- a/src/com/google/inject/spi/DefaultElementVisitor.java
+++ b/src/com/google/inject/spi/DefaultElementVisitor.java
@@ -20,7 +20,7 @@
/**
* No-op visitor for subclassing. All interface methods simply delegate to
- * {@link #visitElement(Element)}, returning its result.
+ * {@link #visitOther(Element)}, returning its result.
*
* @param <V> any type to be returned by the visit method. Use {@link Void} with
* {@code return null} if no return type is needed.
@@ -31,47 +31,55 @@
public abstract class DefaultElementVisitor<V> implements ElementVisitor<V> {
/**
- * Visit {@code element} and return a result.
+ * Default visit implementation. Returns {@code null}.
*/
- protected V visitElement(Element element) {
+ protected V visitOther(Element element) {
return null;
}
- public V visitMessage(Message message) {
- return visitElement(message);
+ public V visit(Message message) {
+ return visitOther(message);
}
- public <T> V visitBinding(Binding<T> binding) {
- return visitElement(binding);
+ public <T> V visit(Binding<T> binding) {
+ return visitOther(binding);
}
/*if[AOP]*/
- public V visitInterceptorBinding(InterceptorBinding interceptorBinding) {
- return visitElement(interceptorBinding);
+ public V visit(InterceptorBinding interceptorBinding) {
+ return visitOther(interceptorBinding);
}
/*end[AOP]*/
- public V visitScopeBinding(ScopeBinding scopeBinding) {
- return visitElement(scopeBinding);
+ public V visit(ScopeBinding scopeBinding) {
+ return visitOther(scopeBinding);
}
- public V visitTypeConverterBinding(TypeConverterBinding typeConverterBinding) {
- return visitElement(typeConverterBinding);
+ public V visit(TypeConverterBinding typeConverterBinding) {
+ return visitOther(typeConverterBinding);
}
- public <T> V visitProviderLookup(ProviderLookup<T> providerLookup) {
- return visitElement(providerLookup);
+ public <T> V visit(ProviderLookup<T> providerLookup) {
+ return visitOther(providerLookup);
}
- public V visitInjectionRequest(InjectionRequest injectionRequest) {
- return visitElement(injectionRequest);
+ public V visit(InjectionRequest injectionRequest) {
+ return visitOther(injectionRequest);
}
- public V visitStaticInjectionRequest(StaticInjectionRequest staticInjectionRequest) {
- return visitElement(staticInjectionRequest);
+ public V visit(StaticInjectionRequest staticInjectionRequest) {
+ return visitOther(staticInjectionRequest);
}
- public V visitPrivateElements(PrivateElements privateElements) {
- return visitElement(privateElements);
+ public V visit(PrivateElements privateElements) {
+ return visitOther(privateElements);
+ }
+
+ public <T> V visit(MembersInjectorLookup<T> lookup) {
+ return visitOther(lookup);
+ }
+
+ public V visit(InjectableTypeListenerBinding binding) {
+ return visitOther(binding);
}
}
diff --git a/src/com/google/inject/spi/Dependency.java b/src/com/google/inject/spi/Dependency.java
index 5c8e5be..c4de6bc 100644
--- a/src/com/google/inject/spi/Dependency.java
+++ b/src/com/google/inject/spi/Dependency.java
@@ -68,6 +68,20 @@
}
/**
+ * Returns the dependencies from the given injectable type.
+ */
+ public static Set<Dependency<?>> forInjectableType(InjectableType<?> injectableType) {
+ List<Dependency<?>> dependencies = Lists.newArrayList();
+ if (injectableType.getInjectableConstructor() != null) {
+ dependencies.addAll(injectableType.getInjectableConstructor().getDependencies());
+ }
+ for (InjectionPoint injectionPoint : injectableType.getInjectableMembers()) {
+ dependencies.addAll(injectionPoint.getDependencies());
+ }
+ return ImmutableSet.copyOf(dependencies);
+ }
+
+ /**
* Returns the key to the binding that satisfies this dependency.
*/
public Key<T> getKey() {
diff --git a/src/com/google/inject/spi/Element.java b/src/com/google/inject/spi/Element.java
index 882f774..8fca6eb 100644
--- a/src/com/google/inject/spi/Element.java
+++ b/src/com/google/inject/spi/Element.java
@@ -16,6 +16,8 @@
package com.google.inject.spi;
+import com.google.inject.Binder;
+
/**
* A core component of a module or injector.
*
@@ -28,6 +30,7 @@
* com.google.inject.Injector#getBindings Injector.getBindings()} to reflect on Guice injectors.
*
* @author jessewilson@google.com (Jesse Wilson)
+ * @author crazybob@google.com (Bob Lee)
* @since 2.0
*/
public interface Element {
@@ -49,4 +52,13 @@
*/
<T> T acceptVisitor(ElementVisitor<T> visitor);
+ /**
+ * Writes this module element to the given binder (optional operation).
+ *
+ * @param binder to apply configuration element to
+ * @throws UnsupportedOperationException if the {@code applyTo} method is not supported by this
+ * element.
+ */
+ void applyTo(Binder binder);
+
}
diff --git a/src/com/google/inject/spi/ElementVisitor.java b/src/com/google/inject/spi/ElementVisitor.java
index 9f6df6c..29bf111 100644
--- a/src/com/google/inject/spi/ElementVisitor.java
+++ b/src/com/google/inject/spi/ElementVisitor.java
@@ -32,47 +32,58 @@
* Visit a mapping from a key (type and optional annotation) to the strategy for getting
* instances of the type.
*/
- <T> V visitBinding(Binding<T> binding);
+ <T> V visit(Binding<T> binding);
/*if[AOP]*/
/**
* Visit a registration of interceptors for matching methods of matching classes.
*/
- V visitInterceptorBinding(InterceptorBinding interceptorBinding);
+ V visit(InterceptorBinding binding);
/*end[AOP]*/
/**
* Visit a registration of a scope annotation with the scope that implements it.
*/
- V visitScopeBinding(ScopeBinding scopeBinding);
+ V visit(ScopeBinding binding);
/**
* Visit a registration of type converters for matching target types.
*/
- V visitTypeConverterBinding(TypeConverterBinding typeConverterBinding);
+ V visit(TypeConverterBinding binding);
/**
* Visit a request to inject the instance fields and methods of an instance.
*/
- V visitInjectionRequest(InjectionRequest injectionRequest);
+ V visit(InjectionRequest request);
/**
* Visit a request to inject the static fields and methods of type.
*/
- V visitStaticInjectionRequest(StaticInjectionRequest staticInjectionRequest);
+ V visit(StaticInjectionRequest request);
/**
* Visit a lookup of the provider for a type.
*/
- <T> V visitProviderLookup(ProviderLookup<T> providerLookup);
+ <T> V visit(ProviderLookup<T> lookup);
+
+ /**
+ * Visit a lookup of the members injector.
+ */
+ <T> V visit(MembersInjectorLookup<T> lookup);
/**
* Visit an error message and the context in which it occured.
*/
- V visitMessage(Message message);
+ V visit(Message message);
/**
- * Visit a collection of configuration elements for a private environment.
+ * Visit a collection of configuration elements for a {@linkplain com.google.inject.PrivateBinder
+ * private binder}.
*/
- V visitPrivateElements(PrivateElements privateElements);
+ V visit(PrivateElements elements);
+
+ /**
+ * Visit an injectable type listener binding.
+ */
+ V visit(InjectableTypeListenerBinding binding);
}
diff --git a/src/com/google/inject/spi/Elements.java b/src/com/google/inject/spi/Elements.java
index 44084d7..efe4c9f 100644
--- a/src/com/google/inject/spi/Elements.java
+++ b/src/com/google/inject/spi/Elements.java
@@ -27,6 +27,7 @@
import com.google.inject.Scope;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
+import com.google.inject.MembersInjector;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.AnnotatedElementBuilder;
@@ -37,7 +38,6 @@
import com.google.inject.internal.ImmutableList;
import com.google.inject.internal.Lists;
import static com.google.inject.internal.Preconditions.checkArgument;
-import static com.google.inject.internal.Preconditions.checkNotNull;
import static com.google.inject.internal.Preconditions.checkState;
import com.google.inject.internal.PrivateElementsImpl;
import com.google.inject.internal.ProviderMethodsModule;
@@ -62,7 +62,7 @@
public final class Elements {
private static final BindingTargetVisitor<Object, Object> GET_INSTANCE_VISITOR
= new DefaultBindingTargetVisitor<Object, Object>() {
- @Override public Object visitInstance(InstanceBinding<?> binding) {
+ @Override public Object visit(InstanceBinding<?> binding) {
return binding.getInstance();
}
@@ -169,10 +169,26 @@
elements.add(new ScopeBinding(getSource(), annotationType, scope));
}
- public void requestInjection(Object... instances) {
- for (Object instance : instances) {
- elements.add(new InjectionRequest(getSource(), instance));
- }
+ @SuppressWarnings("unchecked") // it is safe to use the type literal for the raw type
+ public void requestInjection(Object instance) {
+ requestInjection((TypeLiteral) TypeLiteral.get(instance.getClass()), instance);
+ }
+
+ public <T> void requestInjection(TypeLiteral<T> type, T instance) {
+ elements.add(new InjectionRequest<T>(getSource(), type, instance));
+ }
+
+ public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
+ InjectableType.Listener listener) {
+ elements.add(new InjectableTypeListenerBinding(getSource(), listener, typeMatcher));
}
public void requestStaticInjection(Class<?>... types) {
@@ -182,8 +198,6 @@
}
public void install(Module module) {
- checkNotNull(module, "module");
-
if (modules.add(module)) {
Binder binder = this;
if (module instanceof PrivateModule) {
diff --git a/src/com/google/inject/spi/ExposedBinding.java b/src/com/google/inject/spi/ExposedBinding.java
index fe26071..66f0536 100644
--- a/src/com/google/inject/spi/ExposedBinding.java
+++ b/src/com/google/inject/spi/ExposedBinding.java
@@ -17,6 +17,7 @@
package com.google.inject.spi;
import com.google.inject.Binding;
+import com.google.inject.Binder;
/**
* A binding to a key exposed from an enclosed private environment.
@@ -31,4 +32,8 @@
*/
PrivateElements getPrivateElements();
+ /**
+ * Unsupported. Always throws {@link UnsupportedOperationException}.
+ */
+ void applyTo(Binder binder);
}
\ No newline at end of file
diff --git a/src/com/google/inject/spi/InjectableType.java b/src/com/google/inject/spi/InjectableType.java
new file mode 100644
index 0000000..00e7f44
--- /dev/null
+++ b/src/com/google/inject/spi/InjectableType.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2009 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.spi;
+
+import com.google.inject.ConfigurationException;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import com.google.inject.MembersInjector;
+import com.google.inject.matcher.Matcher;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.aopalliance.intercept.MethodInterceptor;
+
+/**
+ * Represents an injectable type. A type is injectable if:
+ *
+ * <ol type="a">
+ * <li>Guice can inject its constructor, or</li>
+ * <li>Guice can inject the methods and fields of a pre-existing instance of the type</li>
+ * </ol>
+ *
+ * <p>Note: Despite generic type erasure, Guice keeps track of full types, so it can and does treat
+ * {@code Foo<String>} and {@code Foo<Integer>} as distinct injectable types.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ * @author jessewilson@google.com (Jesse Wilson)
+ * @since 2.0
+ */
+public interface InjectableType<I> {
+
+ /**
+ * Gets the type literal.
+ */
+ TypeLiteral<I> getType();
+
+ /**
+ * Returns the injection point representing the contructor or {@code null} if no injectable
+ * constructor is present
+ */
+ InjectionPoint getInjectableConstructor();
+
+ /**
+ * Returns the instance methods and fields of {@code T} that can be injected.
+ *
+ * @return a possibly empty set of injection points. The set has a specified iteration order.
+ * All fields are returned and then all methods. Within the fields, supertype fields are
+ * returned before subtype fields. Similarly, supertype methods are returned before subtype
+ * methods.
+ * @throws com.google.inject.ConfigurationException if there is a malformed injection point on
+ * the class of {@code instance}, such as a field with multiple binding annotations. The
+ * exception's {@link com.google.inject.ConfigurationException#getPartialValue() partial value}
+ * is a {@code Set<InjectionPoint>} of the valid injection points.
+ */
+ Set<InjectionPoint> getInjectableMembers() throws ConfigurationException;
+
+ /*if[AOP]*/
+ /**
+ * Returns the interceptors applied to each method, in the order that they will be applied.
+ * These only apply when Guice instantiates {@code I}.
+ *
+ * @return a possibly empty map
+ */
+ Map<Method, List<MethodInterceptor>> getMethodInterceptors();
+ /*end[AOP]*/
+
+ /**
+ * Listens for Guice to encounter injectable types. If a given type has its constructor injected
+ * in one situation but only its methods and fields injected in another, Guice will notify
+ * this listener once.
+ *
+ * <p>Useful for extra type checking, {@linkplain Encounter#register(InjectionListener)
+ * registering injection listeners}, and {@linkplain Encounter#bindInterceptor(
+ * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
+ * binding method interceptors}.
+ */
+ public interface Listener {
+
+ /**
+ * Invoked when Guice encounters a new type eligible for constructor or members injection.
+ * Called during {@link Injector} creation (or afterwords if Guice encounters a type at run
+ * time and creates a JIT binding).
+ *
+ * @param injectableType encountered by Guice
+ * @param encounter context of this encounter, enables reporting errors, registering injection
+ * listeners and binding method interceptors for injectableType
+ *
+ * @param <I> the injectable type
+ */
+ <I> void hear(InjectableType<I> injectableType, Encounter<I> encounter);
+
+ }
+
+ /**
+ * Context of the injectable type encounter. Enables reporting errors, registering injection
+ * listeners and binding method interceptors for injectable type {@code I}.
+ *
+ * @param <I> the injectable type encountered
+ */
+ public interface Encounter<I> {
+
+ /**
+ * Records an error message for type {@code I} which will be presented to the user at a later
+ * time. Unlike throwing an exception, this enable us to continue configuring the Injector and
+ * discover more errors. Uses {@link String#format(String, Object[])} to insert the arguments
+ * into the message.
+ */
+ void addError(String message, Object... arguments);
+
+ /**
+ * Records an exception for type {@code I}, the full details of which will be logged, and the
+ * message of which will be presented to the user at a later time. If your
+ * InjectableTypeListener calls something that you worry may fail, you should catch the
+ * exception and pass it to this method.
+ */
+ void addError(Throwable t);
+
+ /**
+ * Records an error message to be presented to the user at a later time.
+ */
+ void addError(Message message);
+
+ /**
+ * Returns the provider used to obtain instances for the given injection key. The returned
+ * provider will not be valid until the {@link Injector} has been created. The provider will
+ * throw an {@code IllegalStateException} if you try to use it beforehand.
+ */
+ <T> Provider<T> getProvider(Key<T> key);
+
+ /**
+ * Returns the provider used to obtain instances for the given injection type. The returned
+ * provider will not be valid until the {@link Injector} has been created. The provider will
+ * throw an {@code IllegalStateException} if you try to use it beforehand.
+ */
+ <T> Provider<T> getProvider(Class<T> type);
+
+ /**
+ * Returns the members injector used to inject dependencies into methods and fields on instances
+ * of the given type {@code T}. The returned members injector will not be valid until the main
+ * {@link Injector} has been created. The members injector will throw an {@code
+ * IllegalStateException} if you try to use it beforehand.
+ *
+ * @param typeLiteral type to get members injector for
+ */
+ <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral);
+
+ /**
+ * Returns the members injector used to inject dependencies into methods and fields on instances
+ * of the given type {@code T}. The returned members injector will not be valid until the main
+ * {@link Injector} has been created. The members injector will throw an {@code
+ * IllegalStateException} if you try to use it beforehand.
+ *
+ * @param type type to get members injector for
+ */
+ <T> MembersInjector<T> getMembersInjector(Class<T> type);
+
+ /**
+ * Registers an injection listener for type {@code I}. Guice will notify the listener after
+ * injecting an instance of {@code I}. The order in which Guice will invoke listeners is
+ * unspecified.
+ *
+ * @param listener for injections into instances of type {@code I}
+ */
+ void register(InjectionListener<? super I> listener);
+
+ /*if[AOP]*/
+ /**
+ * Binds method interceptor[s] to methods matched in type {@code I} and its supertypes. A
+ * method is eligible for interception if:
+ *
+ * <ul>
+ * <li>Guice created the instance the method is on</li>
+ * <li>Neither the enclosing type nor the method is final</li>
+ * <li>And the method is package-private or more accessible</li>
+ * </ul>
+ *
+ * @param methodMatcher matches methods the interceptor should apply to. For
+ * example: {@code annotatedWith(Transactional.class)}.
+ * @param interceptors to bind
+ */
+ void bindInterceptor(Matcher<? super Method> methodMatcher,
+ org.aopalliance.intercept.MethodInterceptor... interceptors);
+ /*end[AOP]*/
+ }
+}
\ No newline at end of file
diff --git a/src/com/google/inject/spi/InjectableTypeListenerBinding.java b/src/com/google/inject/spi/InjectableTypeListenerBinding.java
new file mode 100644
index 0000000..9381e10
--- /dev/null
+++ b/src/com/google/inject/spi/InjectableTypeListenerBinding.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2009 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.spi;
+
+import com.google.inject.Binder;
+import com.google.inject.TypeLiteral;
+import com.google.inject.matcher.Matcher;
+
+/**
+ * Binds injectable types (picked using a Matcher) to an injectable type listener.
+ * Registrations are created explicitly in a module using {@link
+ * com.google.inject.Binder#bindListener(com.google.inject.matcher.Matcher,
+ * com.google.inject.spi.InjectableType.Listener)} statements:
+ *
+ * <pre>
+ * register(any(), listener);</pre>
+ */
+public final class InjectableTypeListenerBinding implements Element {
+
+ final Object source;
+ final Matcher<? super TypeLiteral<?>> typeMatcher;
+ final InjectableType.Listener listener;
+
+ InjectableTypeListenerBinding(Object source, InjectableType.Listener listener,
+ Matcher<? super TypeLiteral<?>> typeMatcher) {
+ this.source = source;
+ this.listener = listener;
+ this.typeMatcher = typeMatcher;
+ }
+
+ /** Returns the registered listener. */
+ public InjectableType.Listener getListener() {
+ return listener;
+ }
+
+ /** Returns the type matcher which chooses which types the listener should be notified of. */
+ public Matcher<? super TypeLiteral<?>> getTypeMatcher() {
+ return typeMatcher;
+ }
+
+ public Object getSource() {
+ return source;
+ }
+
+ public <T> T acceptVisitor(ElementVisitor<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).bindListener(typeMatcher, listener);
+ }
+}
diff --git a/src/com/google/inject/spi/InjectionListener.java b/src/com/google/inject/spi/InjectionListener.java
new file mode 100644
index 0000000..14cf00d
--- /dev/null
+++ b/src/com/google/inject/spi/InjectionListener.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 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.spi;
+
+/**
+ * Listens for injections into instances of type {@code I}. Useful for performing further
+ * injections, post-injection initialization, and more.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ * @author jessewilson@google.com (Jesse Wilson)
+ * @since 2.0
+ */
+public interface InjectionListener<I> {
+
+ /**
+ * Invoked by Guice after it injects the fields and methods of instance.
+ *
+ * @param injectee instance that Guice injected dependencies into
+ */
+ void afterInjection(I injectee);
+}
diff --git a/src/com/google/inject/spi/InjectionRequest.java b/src/com/google/inject/spi/InjectionRequest.java
index e1407af..d058dda 100644
--- a/src/com/google/inject/spi/InjectionRequest.java
+++ b/src/com/google/inject/spi/InjectionRequest.java
@@ -16,13 +16,15 @@
package com.google.inject.spi;
+import com.google.inject.Binder;
import com.google.inject.ConfigurationException;
+import com.google.inject.TypeLiteral;
import static com.google.inject.internal.Preconditions.checkNotNull;
import java.util.Set;
/**
* A request to inject the instance fields and methods of an instance. Requests are created
- * explicitly in a module using {@link com.google.inject.Binder#requestInjection(Object[])
+ * explicitly in a module using {@link com.google.inject.Binder#requestInjection(Object)
* requestInjection()} statements:
* <pre>
* requestInjection(serviceInstance);</pre>
@@ -30,12 +32,15 @@
* @author mikeward@google.com (Mike Ward)
* @since 2.0
*/
-public final class InjectionRequest implements Element {
- private Object source;
- private Object instance;
+public final class InjectionRequest<T> implements Element {
- public InjectionRequest(Object source, Object instance) {
+ private final Object source;
+ private final TypeLiteral<T> type;
+ private final T instance;
+
+ public InjectionRequest(Object source, TypeLiteral<T> type, T instance) {
this.source = checkNotNull(source, "source");
+ this.type = checkNotNull(type, "type");
this.instance = checkNotNull(instance, "instance");
}
@@ -43,10 +48,14 @@
return source;
}
- public Object getInstance() {
+ public T getInstance() {
return instance;
}
+ public TypeLiteral<T> getType() {
+ return type;
+ }
+
/**
* Returns the instance methods and fields of {@code instance} that will be injected to fulfill
* this request.
@@ -63,7 +72,11 @@
return InjectionPoint.forInstanceMethodsAndFields(instance.getClass());
}
- public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitInjectionRequest(this);
+ public <R> R acceptVisitor(ElementVisitor<R> visitor) {
+ return visitor.visit(this);
+ }
+
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).requestInjection(type, instance);
}
}
diff --git a/src/com/google/inject/spi/InterceptorBinding.java b/src/com/google/inject/spi/InterceptorBinding.java
index 7006d74..1b1171b 100644
--- a/src/com/google/inject/spi/InterceptorBinding.java
+++ b/src/com/google/inject/spi/InterceptorBinding.java
@@ -16,11 +16,11 @@
package com.google.inject.spi;
+import com.google.inject.Binder;
+import com.google.inject.internal.ImmutableList;
import static com.google.inject.internal.Preconditions.checkNotNull;
import com.google.inject.matcher.Matcher;
import java.lang.reflect.Method;
-import java.util.Arrays;
-import static java.util.Collections.unmodifiableList;
import java.util.List;
import org.aopalliance.intercept.MethodInterceptor;
@@ -33,6 +33,10 @@
* Matchers.annotatedWith(Transactional.class),
* new MyTransactionInterceptor());</pre>
*
+ * or from an injectable type listener using
+ * {@link com.google.inject.spi.InjectableType.Encounter#bindInterceptor(com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
+ * InjectableType.Encounter.bindInterceptor()}.
+ *
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
*/
@@ -40,7 +44,7 @@
private final Object source;
private final Matcher<? super Class<?>> classMatcher;
private final Matcher<? super Method> methodMatcher;
- private final List<MethodInterceptor> interceptors;
+ private final ImmutableList<MethodInterceptor> interceptors;
InterceptorBinding(
Object source,
@@ -50,7 +54,7 @@
this.source = checkNotNull(source, "source");
this.classMatcher = checkNotNull(classMatcher, "classMatcher");
this.methodMatcher = checkNotNull(methodMatcher, "methodMatcher");
- this.interceptors = unmodifiableList(Arrays.asList(interceptors.clone()));
+ this.interceptors = ImmutableList.of(interceptors);
}
public Object getSource() {
@@ -70,6 +74,11 @@
}
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitInterceptorBinding(this);
+ return visitor.visit(this);
+ }
+
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).bindInterceptor(classMatcher, methodMatcher,
+ interceptors.toArray(new MethodInterceptor[interceptors.size()]));
}
}
diff --git a/src/com/google/inject/spi/MembersInjectorLookup.java b/src/com/google/inject/spi/MembersInjectorLookup.java
new file mode 100644
index 0000000..67eb601
--- /dev/null
+++ b/src/com/google/inject/spi/MembersInjectorLookup.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2009 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.spi;
+
+import com.google.inject.MembersInjector;
+import com.google.inject.Binder;
+import static com.google.inject.internal.Preconditions.checkNotNull;
+import static com.google.inject.internal.Preconditions.checkState;
+
+/**
+ * A lookup of the members injector for a type. Lookups are created explicitly in a module using
+ * {@link com.google.inject.Binder#getMembersInjector(Class) getMembersInjector()} statements:
+ * <pre>
+ * MembersInjector<PaymentService> membersInjector
+ * = getMembersInjector(PaymentService.class);</pre>
+ *
+ * @author crazybob@google.com (Bob Lee)
+ * @since 2.0
+ */
+public final class MembersInjectorLookup<T> implements Element {
+
+ private final Object source;
+ private final InjectableType<T> injectableType;
+ private MembersInjector<T> delegate;
+
+ MembersInjectorLookup(Object source, InjectableType<T> injectableType) {
+ this.source = checkNotNull(source, "source");
+ this.injectableType = checkNotNull(injectableType, "injectableType");
+ }
+
+ public Object getSource() {
+ return source;
+ }
+
+ /**
+ * Gets the injectable type containing the members to be injected.
+ */
+ public InjectableType<T> getInjectableType() {
+ return injectableType;
+ }
+
+ public <T> T acceptVisitor(ElementVisitor<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ /**
+ * Sets the actual members injector.
+ *
+ * @param delegate members injector
+ * @throws IllegalStateException if the delegate is already set
+ * @throws NullPointerException if the delegate is null
+ */
+ public void initializeDelegate(MembersInjector<T> delegate) {
+ checkState(this.delegate == null, "delegate already initialized");
+ checkNotNull(delegate, "delegate");
+ this.delegate = delegate;
+ }
+
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).getMembersInjector(injectableType.getType());
+ }
+
+ /**
+ * Returns the delegate members injector, or {@code null} if it has not yet been initialized.
+ * The delegate will be initialized when this element is processed, or otherwise used to create
+ * an injector.
+ */
+ public MembersInjector<T> getDelegate() {
+ return delegate;
+ }
+}
\ No newline at end of file
diff --git a/src/com/google/inject/spi/Message.java b/src/com/google/inject/spi/Message.java
index ce4c615..3eb9395 100644
--- a/src/com/google/inject/spi/Message.java
+++ b/src/com/google/inject/spi/Message.java
@@ -21,6 +21,7 @@
import com.google.inject.internal.Objects;
import static com.google.inject.internal.Preconditions.checkNotNull;
import com.google.inject.internal.SourceProvider;
+import com.google.inject.Binder;
import java.io.Serializable;
import java.util.List;
@@ -81,7 +82,7 @@
/** @since 2.0 */
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitMessage(this);
+ return visitor.visit(this);
}
/**
@@ -109,4 +110,8 @@
Message e = (Message) o;
return message.equals(e.message) && Objects.equal(cause, e.cause) && sources.equals(e.sources);
}
+
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).addError(this);
+ }
}
\ No newline at end of file
diff --git a/src/com/google/inject/spi/ModuleWriter.java b/src/com/google/inject/spi/ModuleWriter.java
index d99aacb..466bf0d 100644
--- a/src/com/google/inject/spi/ModuleWriter.java
+++ b/src/com/google/inject/spi/ModuleWriter.java
@@ -61,49 +61,57 @@
ElementVisitor<Void> visitor = new ElementVisitor<Void>() {
- public Void visitMessage(Message message) {
+ public Void visit(Message message) {
writeMessage(binder, message);
return null;
}
/*if[AOP]*/
- public Void visitInterceptorBinding(InterceptorBinding element) {
+ public Void visit(InterceptorBinding element) {
writeBindInterceptor(binder, element);
return null;
}
/*end[AOP]*/
- public Void visitScopeBinding(ScopeBinding element) {
+ public Void visit(ScopeBinding element) {
writeBindScope(binder, element);
return null;
}
- public Void visitInjectionRequest(InjectionRequest element) {
+ public Void visit(InjectionRequest element) {
writeRequestInjection(binder, element);
return null;
}
- public Void visitStaticInjectionRequest(StaticInjectionRequest element) {
+ public Void visit(StaticInjectionRequest element) {
writeRequestStaticInjection(binder, element);
return null;
}
- public Void visitTypeConverterBinding(TypeConverterBinding element) {
+ public Void visit(TypeConverterBinding element) {
writeConvertToTypes(binder, element);
return null;
}
- public <T> Void visitBinding(Binding<T> element) {
+ public <T> Void visit(Binding<T> element) {
writeBind(binder, element);
return null;
}
- public <T> Void visitProviderLookup(ProviderLookup<T> element) {
+ public <T> Void visit(ProviderLookup<T> element) {
writeGetProvider(binder, element);
return null;
}
- public Void visitPrivateElements(PrivateElements privateElements) {
+ public <T> Void visit(MembersInjectorLookup<T> lookup) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public Void visit(InjectableTypeListenerBinding binding) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public Void visit(PrivateElements privateElements) {
writePrivateElements(binder, privateElements);
return null;
}
@@ -168,44 +176,44 @@
protected <T> ScopedBindingBuilder bindKeyToTarget(
final Binding<T> binding, final Binder binder, final Key<T> key) {
return binding.acceptTargetVisitor(new BindingTargetVisitor<T, ScopedBindingBuilder>() {
- public ScopedBindingBuilder visitInstance(InstanceBinding<? extends T> binding) {
+ public ScopedBindingBuilder visit(InstanceBinding<? extends T> binding) {
binder.bind(key).toInstance(binding.getInstance());
return null;
}
- public ScopedBindingBuilder visitProviderInstance(
+ public ScopedBindingBuilder visit(
ProviderInstanceBinding<? extends T> binding) {
return binder.bind(key).toProvider(binding.getProviderInstance());
}
- public ScopedBindingBuilder visitProviderKey(ProviderKeyBinding<? extends T> binding) {
+ public ScopedBindingBuilder visit(ProviderKeyBinding<? extends T> binding) {
return binder.bind(key).toProvider(binding.getProviderKey());
}
- public ScopedBindingBuilder visitLinkedKey(LinkedKeyBinding<? extends T> binding) {
+ public ScopedBindingBuilder visit(LinkedKeyBinding<? extends T> binding) {
return binder.bind(key).to(binding.getLinkedKey());
}
- public ScopedBindingBuilder visitUntargetted(UntargettedBinding<? extends T> binding) {
+ public ScopedBindingBuilder visit(UntargettedBinding<? extends T> binding) {
return binder.bind(key);
}
- public ScopedBindingBuilder visitExposed(ExposedBinding<? extends T> binding) {
+ public ScopedBindingBuilder visit(ExposedBinding<? extends T> binding) {
PrivateBinder privateBinder = getPrivateBinder(binding.getPrivateElements());
privateBinder.withSource(binding.getSource()).expose(key);
return null;
}
- public ScopedBindingBuilder visitConvertedConstant(
+ public ScopedBindingBuilder visit(
ConvertedConstantBinding<? extends T> binding) {
throw new IllegalArgumentException("Non-module element");
}
- public ScopedBindingBuilder visitConstructor(ConstructorBinding<? extends T> binding) {
+ public ScopedBindingBuilder visit(ConstructorBinding<? extends T> binding) {
throw new IllegalArgumentException("Non-module element");
}
- public ScopedBindingBuilder visitProviderBinding(ProviderBinding<? extends T> binding) {
+ public ScopedBindingBuilder visit(ProviderBinding<? extends T> binding) {
throw new IllegalArgumentException("Non-module element");
}
});
@@ -254,6 +262,6 @@
protected <T> void writeGetProvider(Binder binder, ProviderLookup<T> element) {
Provider<T> provider = binder.withSource(element.getSource()).getProvider(element.getKey());
- element.initDelegate(provider);
+ element.initializeDelegate(provider);
}
}
diff --git a/src/com/google/inject/spi/ProviderLookup.java b/src/com/google/inject/spi/ProviderLookup.java
index 205e778..20160d4 100644
--- a/src/com/google/inject/spi/ProviderLookup.java
+++ b/src/com/google/inject/spi/ProviderLookup.java
@@ -18,6 +18,7 @@
import com.google.inject.Key;
import com.google.inject.Provider;
+import com.google.inject.Binder;
import static com.google.inject.internal.Preconditions.checkNotNull;
import static com.google.inject.internal.Preconditions.checkState;
@@ -50,15 +51,26 @@
}
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitProviderLookup(this);
+ return visitor.visit(this);
}
- public void initDelegate(Provider<T> delegate) {
+ /**
+ * Sets the actual provider.
+ *
+ * @param delegate provider
+ * @throws IllegalStateException if the delegate is already set
+ * @throws NullPointerException if the delegate is null
+ */
+ public void initializeDelegate(Provider<T> delegate) {
checkState(this.delegate == null, "delegate already initialized");
checkNotNull(delegate, "delegate");
this.delegate = delegate;
}
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).getProvider(key);
+ }
+
/**
* Returns the delegate provider, or {@code null} if it has not yet been initialized. The delegate
* will be initialized when this element is processed, or otherwise used to create an injector.
diff --git a/src/com/google/inject/spi/ScopeBinding.java b/src/com/google/inject/spi/ScopeBinding.java
index b3fb9d8..5f7b675 100644
--- a/src/com/google/inject/spi/ScopeBinding.java
+++ b/src/com/google/inject/spi/ScopeBinding.java
@@ -17,6 +17,7 @@
package com.google.inject.spi;
import com.google.inject.Scope;
+import com.google.inject.Binder;
import static com.google.inject.internal.Preconditions.checkNotNull;
import java.lang.annotation.Annotation;
@@ -55,6 +56,10 @@
}
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitScopeBinding(this);
+ return visitor.visit(this);
+ }
+
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).bindScope(annotationType, scope);
}
}
diff --git a/src/com/google/inject/spi/StaticInjectionRequest.java b/src/com/google/inject/spi/StaticInjectionRequest.java
index 47b52fb..94e4a0e 100644
--- a/src/com/google/inject/spi/StaticInjectionRequest.java
+++ b/src/com/google/inject/spi/StaticInjectionRequest.java
@@ -17,6 +17,7 @@
package com.google.inject.spi;
import com.google.inject.ConfigurationException;
+import com.google.inject.Binder;
import static com.google.inject.internal.Preconditions.checkNotNull;
import java.util.Set;
@@ -63,7 +64,11 @@
return InjectionPoint.forStaticMethodsAndFields(type);
}
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).requestStaticInjection(type);
+ }
+
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitStaticInjectionRequest(this);
+ return visitor.visit(this);
}
}
diff --git a/src/com/google/inject/spi/TypeConverterBinding.java b/src/com/google/inject/spi/TypeConverterBinding.java
index 32d6f72..7a141d1 100644
--- a/src/com/google/inject/spi/TypeConverterBinding.java
+++ b/src/com/google/inject/spi/TypeConverterBinding.java
@@ -17,6 +17,7 @@
package com.google.inject.spi;
import com.google.inject.TypeLiteral;
+import com.google.inject.Binder;
import static com.google.inject.internal.Preconditions.checkNotNull;
import com.google.inject.matcher.Matcher;
@@ -55,6 +56,10 @@
}
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
- return visitor.visitTypeConverterBinding(this);
+ return visitor.visit(this);
+ }
+
+ public void applyTo(Binder binder) {
+ binder.withSource(getSource()).convertToTypes(typeMatcher, typeConverter);
}
}