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
17package com.google.inject.internal;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.base.Optional;
22import com.google.common.collect.HashMultimap;
23import com.google.common.collect.ImmutableSet;
24import com.google.common.collect.Lists;
25import com.google.common.collect.Multimap;
26import 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;
32import com.google.inject.spi.Dependency;
33import com.google.inject.spi.InjectionPoint;
34import com.google.inject.spi.Message;
35import com.google.inject.spi.ModuleAnnotatedMethodScanner;
36import com.google.inject.util.Modules;
37
38import java.lang.annotation.Annotation;
39import java.lang.reflect.Member;
40import java.lang.reflect.Method;
41import java.lang.reflect.Modifier;
42import java.util.Arrays;
43import java.util.List;
44import 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 */
53public 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
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   */
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   */
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   */
103  public static Module forObject(Object object) {
104    return forObject(object, true, PROVIDES_BUILDER);
105  }
106
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
117  public Object getDelegateModule() {
118    return delegate;
119  }
120
121  @Override
122  public synchronized void configure(Binder binder) {
123    for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) {
124      providerMethod.configure(binder);
125    }
126  }
127
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   */
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
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
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
230    @Override public int hashCode() {
231      return hashCode;
232    }
233  }
234
235  /** Returns true if a overrides b, assumes that the signatures match */
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
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
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
284  @Override public boolean equals(Object o) {
285    return o instanceof ProviderMethodsModule
286        && ((ProviderMethodsModule) o).delegate == delegate
287        && ((ProviderMethodsModule) o).scanner == scanner;
288  }
289
290  @Override public int hashCode() {
291    return delegate.hashCode();
292  }
293}
294