1 /*
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 
17 package com.google.inject.internal;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.collect.HashMultimap;
22 import com.google.common.collect.ImmutableList;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Multimap;
26 import com.google.inject.Binder;
27 import com.google.inject.Key;
28 import com.google.inject.Module;
29 import com.google.inject.Provides;
30 import com.google.inject.TypeLiteral;
31 import com.google.inject.spi.InjectionPoint;
32 import com.google.inject.spi.Message;
33 import com.google.inject.spi.ModuleAnnotatedMethodScanner;
34 import com.google.inject.util.Modules;
35 import java.lang.annotation.Annotation;
36 import java.lang.reflect.Member;
37 import java.lang.reflect.Method;
38 import java.lang.reflect.Modifier;
39 import java.util.Arrays;
40 import java.util.List;
41 
42 /**
43  * Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and
44  * binding annotations on the provider method to configure the binding.
45  *
46  * @author crazybob@google.com (Bob Lee)
47  * @author jessewilson@google.com (Jesse Wilson)
48  */
49 public final class ProviderMethodsModule implements Module {
50   private final Object delegate;
51   private final TypeLiteral<?> typeLiteral;
52   private final boolean skipFastClassGeneration;
53   private final ModuleAnnotatedMethodScanner scanner;
54 
ProviderMethodsModule( Object delegate, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner)55   private ProviderMethodsModule(
56       Object delegate, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) {
57     this.delegate = checkNotNull(delegate, "delegate");
58     this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
59     this.skipFastClassGeneration = skipFastClassGeneration;
60     this.scanner = scanner;
61   }
62 
63   /** Returns a module which creates bindings for provider methods from the given module. */
forModule(Module module)64   public static Module forModule(Module module) {
65     return forObject(module, false, ProvidesMethodScanner.INSTANCE);
66   }
67 
68   /** Returns a module which creates bindings methods in the module that match the scanner. */
forModule(Object module, ModuleAnnotatedMethodScanner scanner)69   public static Module forModule(Object module, ModuleAnnotatedMethodScanner scanner) {
70     return forObject(module, false, scanner);
71   }
72 
73   /**
74    * Returns a module which creates bindings for provider methods from the given object. This is
75    * useful notably for <a href="http://code.google.com/p/google-gin/">GIN</a>
76    *
77    * <p>This will skip bytecode generation for provider methods, since it is assumed that callers
78    * are only interested in Module metadata.
79    */
forObject(Object object)80   public static Module forObject(Object object) {
81     return forObject(object, true, ProvidesMethodScanner.INSTANCE);
82   }
83 
forObject( Object object, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner)84   private static Module forObject(
85       Object object, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) {
86     // avoid infinite recursion, since installing a module always installs itself
87     if (object instanceof ProviderMethodsModule) {
88       return Modules.EMPTY_MODULE;
89     }
90 
91     return new ProviderMethodsModule(object, skipFastClassGeneration, scanner);
92   }
93 
getDelegateModule()94   public Object getDelegateModule() {
95     return delegate;
96   }
97 
98   @Override
configure(Binder binder)99   public void configure(Binder binder) {
100     for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) {
101       providerMethod.configure(binder);
102     }
103   }
104 
getProviderMethods(Binder binder)105   public List<ProviderMethod<?>> getProviderMethods(Binder binder) {
106     List<ProviderMethod<?>> result = null;
107     // The highest class in the type hierarchy that contained a provider method definition.
108     Class<?> superMostClass = delegate.getClass();
109     for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
110       for (Method method : c.getDeclaredMethods()) {
111         Annotation annotation = getAnnotation(binder, method);
112         if (annotation != null) {
113           if (result == null) {
114             result = Lists.newArrayList();
115           }
116           result.add(createProviderMethod(binder, method, annotation));
117           superMostClass = c;
118         }
119       }
120     }
121     if (result == null) {
122       // We didn't find anything
123       return ImmutableList.of();
124     }
125     // We have found some provider methods, now we need to check if any were overridden.
126     // We do this as a separate pass to avoid calculating all the signatures when there are no
127     // provides methods, or when all provides methods are defined in a single class.
128     Multimap<Signature, Method> methodsBySignature = null;
129     // We can stop scanning when we see superMostClass, since no superclass method can override
130     // a method in a subclass.  Corrollary, if superMostClass == delegate.getClass(), there can be
131     // no overrides of a provides method.
132     for (Class<?> c = delegate.getClass(); c != superMostClass; c = c.getSuperclass()) {
133       for (Method method : c.getDeclaredMethods()) {
134         if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0)
135             && !method.isBridge()
136             && !method.isSynthetic()) {
137           if (methodsBySignature == null) {
138             methodsBySignature = HashMultimap.create();
139           }
140           methodsBySignature.put(new Signature(typeLiteral, method), method);
141         }
142       }
143     }
144     if (methodsBySignature != null) {
145       // we have found all the signatures and now need to identify if any were overridden
146       // In the worst case this will have O(n^2) in the number of @Provides methods, but that is
147       // only assuming that every method is an override, in general it should be very quick.
148       for (ProviderMethod<?> provider : result) {
149         Method method = provider.getMethod();
150         for (Method matchingSignature :
151             methodsBySignature.get(new Signature(typeLiteral, method))) {
152           // matching signature is in the same class or a super class, therefore method cannot be
153           // overridding it.
154           if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) {
155             continue;
156           }
157           // now we know matching signature is in a subtype of method.getDeclaringClass()
158           if (overrides(matchingSignature, method)) {
159             String annotationString =
160                 provider.getAnnotation().annotationType() == Provides.class
161                     ? "@Provides"
162                     : "@" + provider.getAnnotation().annotationType().getCanonicalName();
163             binder.addError(
164                 "Overriding "
165                     + annotationString
166                     + " methods is not allowed."
167                     + "\n\t"
168                     + annotationString
169                     + " method: %s\n\toverridden by: %s",
170                 method,
171                 matchingSignature);
172             break;
173           }
174         }
175       }
176     }
177     return result;
178   }
179 
180   /** Returns the annotation that is claimed by the scanner, or null if there is none. */
getAnnotation(Binder binder, Method method)181   private Annotation getAnnotation(Binder binder, Method method) {
182     if (method.isBridge() || method.isSynthetic()) {
183       return null;
184     }
185     Annotation annotation = null;
186     for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) {
187       Annotation foundAnnotation = method.getAnnotation(annotationClass);
188       if (foundAnnotation != null) {
189         if (annotation != null) {
190           binder.addError(
191               "More than one annotation claimed by %s on method %s."
192                   + " Methods can only have one annotation claimed per scanner.",
193               scanner, method);
194           return null;
195         }
196         annotation = foundAnnotation;
197       }
198     }
199     return annotation;
200   }
201 
202   private static final class Signature {
203     final Class<?>[] parameters;
204     final String name;
205     final int hashCode;
206 
Signature(TypeLiteral<?> typeLiteral, Method method)207     Signature(TypeLiteral<?> typeLiteral, Method method) {
208       this.name = method.getName();
209       // We need to 'resolve' the parameters against the actual class type in case this method uses
210       // type parameters.  This is so we can detect overrides of generic superclass methods where
211       // the subclass specifies the type parameter.  javac implements these kinds of overrides via
212       // bridge methods, but we don't want to give errors on bridge methods (but rather the target
213       // of the bridge).
214       List<TypeLiteral<?>> resolvedParameterTypes = typeLiteral.getParameterTypes(method);
215       this.parameters = new Class<?>[resolvedParameterTypes.size()];
216       int i = 0;
217       for (TypeLiteral<?> type : resolvedParameterTypes) {
218         parameters[i] = type.getRawType();
219       }
220       this.hashCode = name.hashCode() + 31 * Arrays.hashCode(parameters);
221     }
222 
223     @Override
equals(Object obj)224     public boolean equals(Object obj) {
225       if (obj instanceof Signature) {
226         Signature other = (Signature) obj;
227         return other.name.equals(name) && Arrays.equals(parameters, other.parameters);
228       }
229       return false;
230     }
231 
232     @Override
hashCode()233     public int hashCode() {
234       return hashCode;
235     }
236   }
237 
238   /** Returns true if a overrides b, assumes that the signatures match */
overrides(Method a, Method b)239   private static boolean overrides(Method a, Method b) {
240     // See JLS section 8.4.8.1
241     int modifiers = b.getModifiers();
242     if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
243       return true;
244     }
245     if (Modifier.isPrivate(modifiers)) {
246       return false;
247     }
248     // b must be package-private
249     return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
250   }
251 
createProviderMethod( Binder binder, Method method, Annotation annotation)252   private <T> ProviderMethod<T> createProviderMethod(
253       Binder binder, Method method, Annotation annotation) {
254     binder = binder.withSource(method);
255     Errors errors = new Errors(method);
256 
257     // prepare the parameter providers
258     InjectionPoint point = InjectionPoint.forMethod(method, typeLiteral);
259     @SuppressWarnings("unchecked") // Define T as the method's return type.
260     TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method);
261     Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
262     try {
263       key = scanner.prepareMethod(binder, annotation, key, point);
264     } catch (Throwable t) {
265       binder.addError(t);
266     }
267     Class<? extends Annotation> scopeAnnotation =
268         Annotations.findScopeAnnotation(errors, method.getAnnotations());
269     for (Message message : errors.getMessages()) {
270       binder.addError(message);
271     }
272     return ProviderMethod.create(
273         key,
274         method,
275         delegate,
276         ImmutableSet.copyOf(point.getDependencies()),
277         scopeAnnotation,
278         skipFastClassGeneration,
279         annotation);
280   }
281 
getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations)282   <T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) {
283     Annotation bindingAnnotation = Annotations.findBindingAnnotation(errors, member, annotations);
284     return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation);
285   }
286 
287   @Override
equals(Object o)288   public boolean equals(Object o) {
289     return o instanceof ProviderMethodsModule
290         && ((ProviderMethodsModule) o).delegate == delegate
291         && ((ProviderMethodsModule) o).scanner == scanner;
292   }
293 
294   @Override
hashCode()295   public int hashCode() {
296     return delegate.hashCode();
297   }
298 }
299