Home | History | Annotate | Download | only in internal
      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 (at) google.com (Bob Lee)
     51  * @author jessewilson (at) 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 
     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