blob: 98eb45d32da14d92ad8eb9c1fbd41033f1b96214 [file] [log] [blame]
limpbizkit86cb3bb2008-10-15 21:25:50 +00001/**
2 * Copyright (C) 2008 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.inject.internal;
18
sberlinb7a02b02011-07-08 00:34:16 +000019import static com.google.common.base.Preconditions.checkNotNull;
20
samebe18906a2015-02-02 14:07:53 -080021import com.google.common.base.Optional;
Sam Berlin76be88e2014-07-01 16:56:13 -040022import com.google.common.collect.HashMultimap;
sberlinb7a02b02011-07-08 00:34:16 +000023import com.google.common.collect.ImmutableSet;
24import com.google.common.collect.Lists;
Sam Berlin76be88e2014-07-01 16:56:13 -040025import com.google.common.collect.Multimap;
limpbizkit86cb3bb2008-10-15 21:25:50 +000026import com.google.inject.Binder;
27import com.google.inject.Key;
28import com.google.inject.Module;
29import com.google.inject.Provider;
30import com.google.inject.Provides;
31import com.google.inject.TypeLiteral;
samebe18906a2015-02-02 14:07:53 -080032import com.google.inject.spi.ModuleAnnotatedMethodScanner;
limpbizkit76c24b12008-12-25 04:32:41 +000033import com.google.inject.spi.Dependency;
sameb9867f9c2015-02-02 12:45:25 -080034import com.google.inject.spi.InjectionPoint;
limpbizkit86cb3bb2008-10-15 21:25:50 +000035import com.google.inject.spi.Message;
36import com.google.inject.util.Modules;
sberlinb7a02b02011-07-08 00:34:16 +000037
limpbizkit86cb3bb2008-10-15 21:25:50 +000038import java.lang.annotation.Annotation;
39import java.lang.reflect.Member;
40import java.lang.reflect.Method;
Sam Berlin76be88e2014-07-01 16:56:13 -040041import java.lang.reflect.Modifier;
42import java.util.Arrays;
limpbizkit86cb3bb2008-10-15 21:25:50 +000043import java.util.List;
samebe18906a2015-02-02 14:07:53 -080044import java.util.Set;
limpbizkit86cb3bb2008-10-15 21:25:50 +000045
46/**
47 * Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and
48 * binding annotations on the provider method to configure the binding.
49 *
50 * @author crazybob@google.com (Bob Lee)
limpbizkitd38d16d2008-10-17 17:25:00 +000051 * @author jessewilson@google.com (Jesse Wilson)
limpbizkit86cb3bb2008-10-15 21:25:50 +000052 */
53public final class ProviderMethodsModule implements Module {
lukes117b2a62014-09-10 13:36:04 -070054
samebe18906a2015-02-02 14:07:53 -080055 private static ModuleAnnotatedMethodScanner PROVIDES_BUILDER =
56 new ModuleAnnotatedMethodScanner() {
57 @Override
58 public <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key,
59 InjectionPoint injectionPoint) {
60 return key;
61 }
62
63 @Override
64 public Set<? extends Class<? extends Annotation>> annotationClasses() {
65 return ImmutableSet.of(Provides.class);
66 }
67 };
68
limpbizkit714df3c2009-01-08 02:40:04 +000069 private final Object delegate;
limpbizkit4f5d1f72008-11-14 08:43:40 +000070 private final TypeLiteral<?> typeLiteral;
Sam Berlin58d60742014-07-21 17:13:22 -040071 private final boolean skipFastClassGeneration;
samebe18906a2015-02-02 14:07:53 -080072 private final ModuleAnnotatedMethodScanner scanner;
limpbizkit86cb3bb2008-10-15 21:25:50 +000073
samebe18906a2015-02-02 14:07:53 -080074 private ProviderMethodsModule(Object delegate, boolean skipFastClassGeneration,
75 ModuleAnnotatedMethodScanner scanner) {
limpbizkit86cb3bb2008-10-15 21:25:50 +000076 this.delegate = checkNotNull(delegate, "delegate");
limpbizkit4f5d1f72008-11-14 08:43:40 +000077 this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
Sam Berlin58d60742014-07-21 17:13:22 -040078 this.skipFastClassGeneration = skipFastClassGeneration;
samebe18906a2015-02-02 14:07:53 -080079 this.scanner = scanner;
limpbizkit86cb3bb2008-10-15 21:25:50 +000080 }
81
82 /**
83 * Returns a module which creates bindings for provider methods from the given module.
84 */
85 public static Module forModule(Module module) {
samebe18906a2015-02-02 14:07:53 -080086 return forObject(module, false, PROVIDES_BUILDER);
87 }
88
89 /**
90 * Returns a module which creates bindings methods in the module that match the scanner.
91 */
92 public static Module forModule(Module module, ModuleAnnotatedMethodScanner scanner) {
93 return forObject(module, false, scanner);
limpbizkit714df3c2009-01-08 02:40:04 +000094 }
95
96 /**
97 * Returns a module which creates bindings for provider methods from the given object.
98 * This is useful notably for <a href="http://code.google.com/p/google-gin/">GIN</a>
Sam Berlin58d60742014-07-21 17:13:22 -040099 *
100 * <p>This will skip bytecode generation for provider methods, since it is assumed that callers
101 * are only interested in Module metadata.
limpbizkit714df3c2009-01-08 02:40:04 +0000102 */
103 public static Module forObject(Object object) {
samebe18906a2015-02-02 14:07:53 -0800104 return forObject(object, true, PROVIDES_BUILDER);
Sam Berlin58d60742014-07-21 17:13:22 -0400105 }
106
samebe18906a2015-02-02 14:07:53 -0800107 private static Module forObject(Object object, boolean skipFastClassGeneration,
108 ModuleAnnotatedMethodScanner scanner) {
limpbizkit86cb3bb2008-10-15 21:25:50 +0000109 // avoid infinite recursion, since installing a module always installs itself
limpbizkit714df3c2009-01-08 02:40:04 +0000110 if (object instanceof ProviderMethodsModule) {
limpbizkit86cb3bb2008-10-15 21:25:50 +0000111 return Modules.EMPTY_MODULE;
112 }
113
samebe18906a2015-02-02 14:07:53 -0800114 return new ProviderMethodsModule(object, skipFastClassGeneration, scanner);
limpbizkit86cb3bb2008-10-15 21:25:50 +0000115 }
Sam Berlin76be88e2014-07-01 16:56:13 -0400116
samebe18906a2015-02-02 14:07:53 -0800117 @Override
limpbizkit86cb3bb2008-10-15 21:25:50 +0000118 public synchronized void configure(Binder binder) {
119 for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) {
120 providerMethod.configure(binder);
121 }
122 }
123
124 public List<ProviderMethod<?>> getProviderMethods(Binder binder) {
125 List<ProviderMethod<?>> result = Lists.newArrayList();
Sam Berlin76be88e2014-07-01 16:56:13 -0400126 Multimap<Signature, Method> methodsBySignature = HashMultimap.create();
limpbizkitd38d16d2008-10-17 17:25:00 +0000127 for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
limpbizkit86cb3bb2008-10-15 21:25:50 +0000128 for (Method method : c.getDeclaredMethods()) {
Sam Berlin76be88e2014-07-01 16:56:13 -0400129 // private/static methods cannot override or be overridden by other methods, so there is no
130 // point in indexing them.
131 // Skip synthetic methods and bridge methods since java will automatically generate
132 // synthetic overrides in some cases where we don't want to generate an error (e.g.
133 // increasing visibility of a subclass).
134 if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0)
135 && !method.isBridge() && !method.isSynthetic()) {
136 methodsBySignature.put(new Signature(method), method);
137 }
samebe18906a2015-02-02 14:07:53 -0800138 Optional<Annotation> annotation = isProvider(binder, method);
139 if (annotation.isPresent()) {
140 result.add(createProviderMethod(binder, method, annotation.get()));
limpbizkit86cb3bb2008-10-15 21:25:50 +0000141 }
142 }
143 }
Sam Berlin76be88e2014-07-01 16:56:13 -0400144 // we have found all the providers and now need to identify if any were overridden
145 // In the worst case this will have O(n^2) in the number of @Provides methods, but that is only
146 // assuming that every method is an override, in general it should be very quick.
147 for (ProviderMethod<?> provider : result) {
148 Method method = provider.getMethod();
149 for (Method matchingSignature : methodsBySignature.get(new Signature(method))) {
150 // matching signature is in the same class or a super class, therefore method cannot be
151 // overridding it.
152 if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) {
153 continue;
154 }
155 // now we know matching signature is in a subtype of method.getDeclaringClass()
156 if (overrides(matchingSignature, method)) {
samebe18906a2015-02-02 14:07:53 -0800157 String annotationString = provider.getAnnotation().annotationType() == Provides.class
158 ? "@Provides" : "@" + provider.getAnnotation().annotationType().getCanonicalName();
Sam Berlin76be88e2014-07-01 16:56:13 -0400159 binder.addError(
samebe18906a2015-02-02 14:07:53 -0800160 "Overriding " + annotationString + " methods is not allowed."
161 + "\n\t" + annotationString + " method: %s\n\toverridden by: %s",
Sam Berlin76be88e2014-07-01 16:56:13 -0400162 method,
163 matchingSignature);
164 break;
165 }
166 }
167 }
limpbizkit86cb3bb2008-10-15 21:25:50 +0000168 return result;
169 }
170
Sam Berlin53a59362014-05-23 18:19:12 -0400171 /**
172 * Returns true if the method is a provider.
173 *
174 * Synthetic bridge methods are excluded. Starting with JDK 8, javac copies annotations onto
175 * bridge methods (which always have erased signatures).
176 */
samebe18906a2015-02-02 14:07:53 -0800177 private Optional<Annotation> isProvider(Binder binder, Method method) {
178 if (method.isBridge() || method.isSynthetic()) {
179 return Optional.absent();
180 }
181 Annotation annotation = null;
182 for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) {
183 Annotation foundAnnotation = method.getAnnotation(annotationClass);
184 if (foundAnnotation != null) {
185 if (annotation != null) {
186 binder.addError("More than one annotation claimed by %s on method %s."
187 + " Methods can only have one annotation claimed per scanner.",
188 scanner, method);
189 return Optional.absent();
190 }
191 annotation = foundAnnotation;
192 }
193 }
194 return Optional.fromNullable(annotation);
Sam Berlin53a59362014-05-23 18:19:12 -0400195 }
196
Sam Berlin76be88e2014-07-01 16:56:13 -0400197 private final class Signature {
198 final Class<?>[] parameters;
199 final String name;
200 final int hashCode;
201
202 Signature(Method method) {
203 this.name = method.getName();
204 // We need to 'resolve' the parameters against the actual class type in case this method uses
205 // type parameters. This is so we can detect overrides of generic superclass methods where
206 // the subclass specifies the type parameter. javac implements these kinds of overrides via
207 // bridge methods, but we don't want to give errors on bridge methods (but rather the target
208 // of the bridge).
209 List<TypeLiteral<?>> resolvedParameterTypes = typeLiteral.getParameterTypes(method);
210 this.parameters = new Class<?>[resolvedParameterTypes.size()];
211 int i = 0;
212 for (TypeLiteral<?> type : resolvedParameterTypes) {
213 parameters[i] = type.getRawType();
214 }
215 this.hashCode = name.hashCode() + 31 * Arrays.hashCode(parameters);
216 }
217
218 @Override public boolean equals(Object obj) {
219 if (obj instanceof Signature) {
220 Signature other = (Signature) obj;
221 return other.name.equals(name) && Arrays.equals(parameters, other.parameters);
222 }
223 return false;
224 }
225
226 @Override public int hashCode() {
227 return hashCode;
228 }
229 }
230
231 /** Returns true if a overrides b, assumes that the signatures match */
232 private static boolean overrides(Method a, Method b) {
233 // See JLS section 8.4.8.1
234 int modifiers = b.getModifiers();
235 if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
236 return true;
237 }
238 if (Modifier.isPrivate(modifiers)) {
239 return false;
240 }
241 // b must be package-private
242 return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
243 }
244
samebe18906a2015-02-02 14:07:53 -0800245 private <T> ProviderMethod<T> createProviderMethod(Binder binder, Method method,
246 Annotation annotation) {
limpbizkit86cb3bb2008-10-15 21:25:50 +0000247 binder = binder.withSource(method);
248 Errors errors = new Errors(method);
249
250 // prepare the parameter providers
sameb9867f9c2015-02-02 12:45:25 -0800251 InjectionPoint point = InjectionPoint.forMethod(method, typeLiteral);
252 List<Dependency<?>> dependencies = point.getDependencies();
limpbizkit86cb3bb2008-10-15 21:25:50 +0000253 List<Provider<?>> parameterProviders = Lists.newArrayList();
sameb9867f9c2015-02-02 12:45:25 -0800254 for (Dependency<?> dependency : point.getDependencies()) {
255 parameterProviders.add(binder.getProvider(dependency));
limpbizkit86cb3bb2008-10-15 21:25:50 +0000256 }
257
limpbizkit4272aef2008-11-23 08:10:09 +0000258 @SuppressWarnings("unchecked") // Define T as the method's return type.
259 TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method);
limpbizkit86cb3bb2008-10-15 21:25:50 +0000260 Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
samebe18906a2015-02-02 14:07:53 -0800261 key = scanner.prepareMethod(binder, annotation, key, point);
limpbizkit86cb3bb2008-10-15 21:25:50 +0000262 Class<? extends Annotation> scopeAnnotation
263 = Annotations.findScopeAnnotation(errors, method.getAnnotations());
limpbizkit86cb3bb2008-10-15 21:25:50 +0000264 for (Message message : errors.getMessages()) {
265 binder.addError(message);
266 }
Sam Berlin409e0f52014-05-10 10:34:16 -0400267 return ProviderMethod.create(key, method, delegate, ImmutableSet.copyOf(dependencies),
samebe18906a2015-02-02 14:07:53 -0800268 parameterProviders, scopeAnnotation, skipFastClassGeneration, annotation);
limpbizkit86cb3bb2008-10-15 21:25:50 +0000269 }
270
271 <T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) {
272 Annotation bindingAnnotation = Annotations.findBindingAnnotation(errors, member, annotations);
273 return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation);
274 }
275
276 @Override public boolean equals(Object o) {
277 return o instanceof ProviderMethodsModule
278 && ((ProviderMethodsModule) o).delegate == delegate;
279 }
280
281 @Override public int hashCode() {
282 return delegate.hashCode();
283 }
limpbizkit86cb3bb2008-10-15 21:25:50 +0000284}