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