aboutsummaryrefslogtreecommitdiff
path: root/core/src/com/google/inject/internal/ProviderMethodsModule.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/com/google/inject/internal/ProviderMethodsModule.java')
-rw-r--r--core/src/com/google/inject/internal/ProviderMethodsModule.java116
1 files changed, 68 insertions, 48 deletions
diff --git a/core/src/com/google/inject/internal/ProviderMethodsModule.java b/core/src/com/google/inject/internal/ProviderMethodsModule.java
index 214039d0..98eb45d3 100644
--- a/core/src/com/google/inject/internal/ProviderMethodsModule.java
+++ b/core/src/com/google/inject/internal/ProviderMethodsModule.java
@@ -18,6 +18,7 @@ package com.google.inject.internal;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.Optional;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
@@ -28,7 +29,9 @@ import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
+import com.google.inject.spi.ModuleAnnotatedMethodScanner;
import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
import com.google.inject.util.Modules;
@@ -38,7 +41,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
-import java.util.logging.Logger;
+import java.util.Set;
/**
* Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and
@@ -48,23 +51,46 @@ import java.util.logging.Logger;
* @author jessewilson@google.com (Jesse Wilson)
*/
public final class ProviderMethodsModule implements Module {
- private static final Key<Logger> LOGGER_KEY = Key.get(Logger.class);
+
+ private static ModuleAnnotatedMethodScanner PROVIDES_BUILDER =
+ new ModuleAnnotatedMethodScanner() {
+ @Override
+ public <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key,
+ InjectionPoint injectionPoint) {
+ return key;
+ }
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotationClasses() {
+ return ImmutableSet.of(Provides.class);
+ }
+ };
private final Object delegate;
private final TypeLiteral<?> typeLiteral;
private final boolean skipFastClassGeneration;
+ private final ModuleAnnotatedMethodScanner scanner;
- private ProviderMethodsModule(Object delegate, boolean skipFastClassGeneration) {
+ private ProviderMethodsModule(Object delegate, boolean skipFastClassGeneration,
+ ModuleAnnotatedMethodScanner scanner) {
this.delegate = checkNotNull(delegate, "delegate");
this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
this.skipFastClassGeneration = skipFastClassGeneration;
+ this.scanner = scanner;
}
/**
* Returns a module which creates bindings for provider methods from the given module.
*/
public static Module forModule(Module module) {
- return forObject(module, false);
+ return forObject(module, false, PROVIDES_BUILDER);
+ }
+
+ /**
+ * Returns a module which creates bindings methods in the module that match the scanner.
+ */
+ public static Module forModule(Module module, ModuleAnnotatedMethodScanner scanner) {
+ return forObject(module, false, scanner);
}
/**
@@ -75,18 +101,20 @@ public final class ProviderMethodsModule implements Module {
* are only interested in Module metadata.
*/
public static Module forObject(Object object) {
- return forObject(object, true);
+ return forObject(object, true, PROVIDES_BUILDER);
}
- private static Module forObject(Object object, boolean skipFastClassGeneration) {
+ private static Module forObject(Object object, boolean skipFastClassGeneration,
+ ModuleAnnotatedMethodScanner scanner) {
// avoid infinite recursion, since installing a module always installs itself
if (object instanceof ProviderMethodsModule) {
return Modules.EMPTY_MODULE;
}
- return new ProviderMethodsModule(object, skipFastClassGeneration);
+ return new ProviderMethodsModule(object, skipFastClassGeneration, scanner);
}
+ @Override
public synchronized void configure(Binder binder) {
for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) {
providerMethod.configure(binder);
@@ -107,8 +135,9 @@ public final class ProviderMethodsModule implements Module {
&& !method.isBridge() && !method.isSynthetic()) {
methodsBySignature.put(new Signature(method), method);
}
- if (isProvider(method)) {
- result.add(createProviderMethod(binder, method));
+ Optional<Annotation> annotation = isProvider(binder, method);
+ if (annotation.isPresent()) {
+ result.add(createProviderMethod(binder, method, annotation.get()));
}
}
}
@@ -125,9 +154,11 @@ public final class ProviderMethodsModule implements Module {
}
// now we know matching signature is in a subtype of method.getDeclaringClass()
if (overrides(matchingSignature, method)) {
+ String annotationString = provider.getAnnotation().annotationType() == Provides.class
+ ? "@Provides" : "@" + provider.getAnnotation().annotationType().getCanonicalName();
binder.addError(
- "Overriding @Provides methods is not allowed."
- + "\n\t@Provides method: %s\n\toverridden by: %s",
+ "Overriding " + annotationString + " methods is not allowed."
+ + "\n\t" + annotationString + " method: %s\n\toverridden by: %s",
method,
matchingSignature);
break;
@@ -143,10 +174,24 @@ public final class ProviderMethodsModule implements Module {
* Synthetic bridge methods are excluded. Starting with JDK 8, javac copies annotations onto
* bridge methods (which always have erased signatures).
*/
- private static boolean isProvider(Method method) {
- return !method.isBridge()
- && !method.isSynthetic()
- && method.isAnnotationPresent(Provides.class);
+ private Optional<Annotation> isProvider(Binder binder, Method method) {
+ if (method.isBridge() || method.isSynthetic()) {
+ return Optional.absent();
+ }
+ Annotation annotation = null;
+ for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) {
+ Annotation foundAnnotation = method.getAnnotation(annotationClass);
+ if (foundAnnotation != null) {
+ if (annotation != null) {
+ binder.addError("More than one annotation claimed by %s on method %s."
+ + " Methods can only have one annotation claimed per scanner.",
+ scanner, method);
+ return Optional.absent();
+ }
+ annotation = foundAnnotation;
+ }
+ }
+ return Optional.fromNullable(annotation);
}
private final class Signature {
@@ -197,42 +242,30 @@ public final class ProviderMethodsModule implements Module {
return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
}
- private <T> ProviderMethod<T> createProviderMethod(Binder binder, Method method) {
+ private <T> ProviderMethod<T> createProviderMethod(Binder binder, Method method,
+ Annotation annotation) {
binder = binder.withSource(method);
Errors errors = new Errors(method);
// prepare the parameter providers
- List<Dependency<?>> dependencies = Lists.newArrayList();
+ InjectionPoint point = InjectionPoint.forMethod(method, typeLiteral);
+ List<Dependency<?>> dependencies = point.getDependencies();
List<Provider<?>> parameterProviders = Lists.newArrayList();
- List<TypeLiteral<?>> parameterTypes = typeLiteral.getParameterTypes(method);
- Annotation[][] parameterAnnotations = method.getParameterAnnotations();
- for (int i = 0; i < parameterTypes.size(); i++) {
- Key<?> key = getKey(errors, parameterTypes.get(i), method, parameterAnnotations[i]);
- if (key.equals(LOGGER_KEY)) {
- // If it was a Logger, change the key to be unique & bind it to a
- // provider that provides a logger with a proper name.
- // This solves issue 482 (returning a new anonymous logger on every call exhausts memory)
- Key<Logger> loggerKey = Key.get(Logger.class, UniqueAnnotations.create());
- binder.bind(loggerKey).toProvider(new LogProvider(method));
- key = loggerKey;
- }
- dependencies.add(Dependency.get(key));
- parameterProviders.add(binder.getProvider(key));
+ for (Dependency<?> dependency : point.getDependencies()) {
+ parameterProviders.add(binder.getProvider(dependency));
}
@SuppressWarnings("unchecked") // Define T as the method's return type.
TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method);
-
Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
+ key = scanner.prepareMethod(binder, annotation, key, point);
Class<? extends Annotation> scopeAnnotation
= Annotations.findScopeAnnotation(errors, method.getAnnotations());
-
for (Message message : errors.getMessages()) {
binder.addError(message);
}
-
return ProviderMethod.create(key, method, delegate, ImmutableSet.copyOf(dependencies),
- parameterProviders, scopeAnnotation, skipFastClassGeneration);
+ parameterProviders, scopeAnnotation, skipFastClassGeneration, annotation);
}
<T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) {
@@ -248,17 +281,4 @@ public final class ProviderMethodsModule implements Module {
@Override public int hashCode() {
return delegate.hashCode();
}
-
- /** A provider that returns a logger based on the method name. */
- private static final class LogProvider implements Provider<Logger> {
- private final String name;
-
- public LogProvider(Method method) {
- this.name = method.getDeclaringClass().getName() + "." + method.getName();
- }
-
- public Logger get() {
- return Logger.getLogger(name);
- }
- }
}