• 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.spi;
18 
19 import static com.google.inject.internal.MoreTypes.getRawType;
20 
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableSet;
23 import com.google.common.collect.Lists;
24 import com.google.inject.ConfigurationException;
25 import com.google.inject.Inject;
26 import com.google.inject.Key;
27 import com.google.inject.TypeLiteral;
28 import com.google.inject.internal.Annotations;
29 import com.google.inject.internal.Errors;
30 import com.google.inject.internal.ErrorsException;
31 import com.google.inject.internal.Nullability;
32 import com.google.inject.internal.util.Classes;
33 
34 import java.lang.annotation.Annotation;
35 import java.lang.reflect.AnnotatedElement;
36 import java.lang.reflect.Constructor;
37 import java.lang.reflect.Field;
38 import java.lang.reflect.Member;
39 import java.lang.reflect.Method;
40 import java.lang.reflect.Modifier;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.HashMap;
45 import java.util.Iterator;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.logging.Level;
50 import java.util.logging.Logger;
51 
52 /**
53  * A constructor, field or method that can receive injections. Typically this is a member with the
54  * {@literal @}{@link Inject} annotation. For non-private, no argument constructors, the member may
55  * omit the annotation.
56  *
57  * @author crazybob@google.com (Bob Lee)
58  * @since 2.0
59  */
60 public final class InjectionPoint {
61 
62   private static final Logger logger = Logger.getLogger(InjectionPoint.class.getName());
63 
64   private final boolean optional;
65   private final Member member;
66   private final TypeLiteral<?> declaringType;
67   private final ImmutableList<Dependency<?>> dependencies;
68 
InjectionPoint(TypeLiteral<?> declaringType, Method method, boolean optional)69   InjectionPoint(TypeLiteral<?> declaringType, Method method, boolean optional) {
70     this.member = method;
71     this.declaringType = declaringType;
72     this.optional = optional;
73     this.dependencies = forMember(method, declaringType, method.getParameterAnnotations());
74   }
75 
InjectionPoint(TypeLiteral<?> declaringType, Constructor<?> constructor)76   InjectionPoint(TypeLiteral<?> declaringType, Constructor<?> constructor) {
77     this.member = constructor;
78     this.declaringType = declaringType;
79     this.optional = false;
80     this.dependencies = forMember(
81         constructor, declaringType, constructor.getParameterAnnotations());
82   }
83 
InjectionPoint(TypeLiteral<?> declaringType, Field field, boolean optional)84   InjectionPoint(TypeLiteral<?> declaringType, Field field, boolean optional) {
85     this.member = field;
86     this.declaringType = declaringType;
87     this.optional = optional;
88 
89     Annotation[] annotations = field.getAnnotations();
90 
91     Errors errors = new Errors(field);
92     Key<?> key = null;
93     try {
94       key = Annotations.getKey(declaringType.getFieldType(field), field, annotations, errors);
95     } catch (ConfigurationException e) {
96       errors.merge(e.getErrorMessages());
97     } catch (ErrorsException e) {
98       errors.merge(e.getErrors());
99     }
100     errors.throwConfigurationExceptionIfErrorsExist();
101 
102     this.dependencies = ImmutableList.<Dependency<?>>of(
103         newDependency(key, Nullability.allowsNull(annotations), -1));
104   }
105 
forMember(Member member, TypeLiteral<?> type, Annotation[][] paramterAnnotations)106   private ImmutableList<Dependency<?>> forMember(Member member, TypeLiteral<?> type,
107       Annotation[][] paramterAnnotations) {
108     Errors errors = new Errors(member);
109     Iterator<Annotation[]> annotationsIterator = Arrays.asList(paramterAnnotations).iterator();
110 
111     List<Dependency<?>> dependencies = Lists.newArrayList();
112     int index = 0;
113 
114     for (TypeLiteral<?> parameterType : type.getParameterTypes(member)) {
115       try {
116         Annotation[] parameterAnnotations = annotationsIterator.next();
117         Key<?> key = Annotations.getKey(parameterType, member, parameterAnnotations, errors);
118         dependencies.add(newDependency(key, Nullability.allowsNull(parameterAnnotations), index));
119         index++;
120       } catch (ConfigurationException e) {
121         errors.merge(e.getErrorMessages());
122       } catch (ErrorsException e) {
123         errors.merge(e.getErrors());
124       }
125     }
126 
127     errors.throwConfigurationExceptionIfErrorsExist();
128     return ImmutableList.copyOf(dependencies);
129   }
130 
131   // This metohd is necessary to create a Dependency<T> with proper generic type information
newDependency(Key<T> key, boolean allowsNull, int parameterIndex)132   private <T> Dependency<T> newDependency(Key<T> key, boolean allowsNull, int parameterIndex) {
133     return new Dependency<T>(this, key, allowsNull, parameterIndex);
134   }
135 
136   /**
137    * Returns the injected constructor, field, or method.
138    */
getMember()139   public Member getMember() {
140     // TODO: Don't expose the original member (which probably has setAccessible(true)).
141     return member;
142   }
143 
144   /**
145    * Returns the dependencies for this injection point. If the injection point is for a method or
146    * constructor, the dependencies will correspond to that member's parameters. Field injection
147    * points always have a single dependency for the field itself.
148    *
149    * @return a possibly-empty list
150    */
getDependencies()151   public List<Dependency<?>> getDependencies() {
152     return dependencies;
153   }
154 
155   /**
156    * Returns true if this injection point shall be skipped if the injector cannot resolve bindings
157    * for all required dependencies. Both explicit bindings (as specified in a module), and implicit
158    * bindings ({@literal @}{@link com.google.inject.ImplementedBy ImplementedBy}, default
159    * constructors etc.) may be used to satisfy optional injection points.
160    */
isOptional()161   public boolean isOptional() {
162     return optional;
163   }
164 
165   /**
166    * Returns true if the element is annotated with {@literal @}{@link Toolable}.
167    *
168    * @since 3.0
169    */
isToolable()170   public boolean isToolable() {
171     return ((AnnotatedElement)member).isAnnotationPresent(Toolable.class);
172   }
173 
174   /**
175    * Returns the generic type that defines this injection point. If the member exists on a
176    * parameterized type, the result will include more type information than the member's {@link
177    * Member#getDeclaringClass() raw declaring class}.
178    *
179    * @since 3.0
180    */
getDeclaringType()181   public TypeLiteral<?> getDeclaringType() {
182     return declaringType;
183   }
184 
equals(Object o)185   @Override public boolean equals(Object o) {
186     return o instanceof InjectionPoint
187         && member.equals(((InjectionPoint) o).member)
188         && declaringType.equals(((InjectionPoint) o).declaringType);
189   }
190 
hashCode()191   @Override public int hashCode() {
192     return member.hashCode() ^ declaringType.hashCode();
193   }
194 
toString()195   @Override public String toString() {
196     return Classes.toString(member);
197   }
198 
199   /**
200    * Returns a new injection point for the specified constructor. If the declaring type of {@code
201    * constructor} is parameterized (such as {@code List<T>}), prefer the overload that includes a
202    * type literal.
203    *
204    * @param constructor any single constructor present on {@code type}.
205    *
206    * @since 3.0
207    */
forConstructor(Constructor<T> constructor)208   public static <T> InjectionPoint forConstructor(Constructor<T> constructor) {
209     return new InjectionPoint(TypeLiteral.get(constructor.getDeclaringClass()), constructor);
210   }
211 
212   /**
213    * Returns a new injection point for the specified constructor of {@code type}.
214    *
215    * @param constructor any single constructor present on {@code type}.
216    * @param type the concrete type that defines {@code constructor}.
217    *
218    * @since 3.0
219    */
forConstructor( Constructor<T> constructor, TypeLiteral<? extends T> type)220   public static <T> InjectionPoint forConstructor(
221       Constructor<T> constructor, TypeLiteral<? extends T> type) {
222     if (type.getRawType() != constructor.getDeclaringClass()) {
223       new Errors(type)
224           .constructorNotDefinedByType(constructor, type)
225           .throwConfigurationExceptionIfErrorsExist();
226     }
227 
228     return new InjectionPoint(type, constructor);
229   }
230 
231   /**
232    * Returns a new injection point for the injectable constructor of {@code type}.
233    *
234    * @param type a concrete type with exactly one constructor annotated {@literal @}{@link Inject},
235    *     or a no-arguments constructor that is not private.
236    * @throws ConfigurationException if there is no injectable constructor, more than one injectable
237    *     constructor, or if parameters of the injectable constructor are malformed, such as a
238    *     parameter with multiple binding annotations.
239    */
forConstructorOf(TypeLiteral<?> type)240   public static InjectionPoint forConstructorOf(TypeLiteral<?> type) {
241     Class<?> rawType = getRawType(type.getType());
242     Errors errors = new Errors(rawType);
243 
244     Constructor<?> injectableConstructor = null;
245     for (Constructor<?> constructor : rawType.getDeclaredConstructors()) {
246 
247       boolean optional;
248       Inject guiceInject = constructor.getAnnotation(Inject.class);
249       if (guiceInject == null) {
250         javax.inject.Inject javaxInject = constructor.getAnnotation(javax.inject.Inject.class);
251         if (javaxInject == null) {
252           continue;
253         }
254         optional = false;
255       } else {
256         optional = guiceInject.optional();
257       }
258 
259       if (optional) {
260         errors.optionalConstructor(constructor);
261       }
262 
263       if (injectableConstructor != null) {
264         errors.tooManyConstructors(rawType);
265       }
266 
267       injectableConstructor = constructor;
268       checkForMisplacedBindingAnnotations(injectableConstructor, errors);
269     }
270 
271     errors.throwConfigurationExceptionIfErrorsExist();
272 
273     if (injectableConstructor != null) {
274       return new InjectionPoint(type, injectableConstructor);
275     }
276 
277     // If no annotated constructor is found, look for a no-arg constructor instead.
278     try {
279       Constructor<?> noArgConstructor = rawType.getDeclaredConstructor();
280 
281       // Disallow private constructors on non-private classes (unless they have @Inject)
282       if (Modifier.isPrivate(noArgConstructor.getModifiers())
283           && !Modifier.isPrivate(rawType.getModifiers())) {
284         errors.missingConstructor(rawType);
285         throw new ConfigurationException(errors.getMessages());
286       }
287 
288       checkForMisplacedBindingAnnotations(noArgConstructor, errors);
289       return new InjectionPoint(type, noArgConstructor);
290     } catch (NoSuchMethodException e) {
291       errors.missingConstructor(rawType);
292       throw new ConfigurationException(errors.getMessages());
293     }
294   }
295 
296   /**
297    * Returns a new injection point for the injectable constructor of {@code type}.
298    *
299    * @param type a concrete type with exactly one constructor annotated {@literal @}{@link Inject},
300    *     or a no-arguments constructor that is not private.
301    * @throws ConfigurationException if there is no injectable constructor, more than one injectable
302    *     constructor, or if parameters of the injectable constructor are malformed, such as a
303    *     parameter with multiple binding annotations.
304    */
forConstructorOf(Class<?> type)305   public static InjectionPoint forConstructorOf(Class<?> type) {
306     return forConstructorOf(TypeLiteral.get(type));
307   }
308 
309   /**
310    * Returns a new injection point for the specified method of {@code type}.
311    * This is useful for extensions that need to build dependency graphs from
312    * arbitrary methods.
313    *
314    * @param method any single method present on {@code type}.
315    * @param type the concrete type that defines {@code method}.
316    *
317    * @since 4.0
318    */
forMethod(Method method, TypeLiteral<T> type)319   public static <T> InjectionPoint forMethod(Method method, TypeLiteral<T> type) {
320     return new InjectionPoint(type, method, false);
321   }
322 
323   /**
324    * Returns all static method and field injection points on {@code type}.
325    *
326    * @return a possibly empty set of injection points. The set has a specified iteration order. All
327    *      fields are returned and then all methods. Within the fields, supertype fields are returned
328    *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
329    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
330    *      a field with multiple binding annotations. The exception's {@link
331    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
332    *      of the valid injection points.
333    */
forStaticMethodsAndFields(TypeLiteral<?> type)334   public static Set<InjectionPoint> forStaticMethodsAndFields(TypeLiteral<?> type) {
335     Errors errors = new Errors();
336 
337     Set<InjectionPoint> result;
338 
339     if (type.getRawType().isInterface()) {
340       errors.staticInjectionOnInterface(type.getRawType());
341       result = null;
342     } else {
343       result = getInjectionPoints(type, true, errors);
344     }
345 
346     if (errors.hasErrors()) {
347       throw new ConfigurationException(errors.getMessages()).withPartialValue(result);
348     }
349     return result;
350   }
351 
352   /**
353    * Returns all static method and field injection points on {@code type}.
354    *
355    * @return a possibly empty set of injection points. The set has a specified iteration order. All
356    *      fields are returned and then all methods. Within the fields, supertype fields are returned
357    *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
358    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
359    *      a field with multiple binding annotations. The exception's {@link
360    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
361    *      of the valid injection points.
362    */
forStaticMethodsAndFields(Class<?> type)363   public static Set<InjectionPoint> forStaticMethodsAndFields(Class<?> type) {
364     return forStaticMethodsAndFields(TypeLiteral.get(type));
365   }
366 
367   /**
368    * Returns all instance method and field injection points on {@code type}.
369    *
370    * @return a possibly empty set of injection points. The set has a specified iteration order. All
371    *      fields are returned and then all methods. Within the fields, supertype fields are returned
372    *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
373    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
374    *      a field with multiple binding annotations. The exception's {@link
375    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
376    *      of the valid injection points.
377    */
forInstanceMethodsAndFields(TypeLiteral<?> type)378   public static Set<InjectionPoint> forInstanceMethodsAndFields(TypeLiteral<?> type) {
379     Errors errors = new Errors();
380     Set<InjectionPoint> result = getInjectionPoints(type, false, errors);
381     if (errors.hasErrors()) {
382       throw new ConfigurationException(errors.getMessages()).withPartialValue(result);
383     }
384     return result;
385   }
386 
387   /**
388    * Returns all instance method and field injection points on {@code type}.
389    *
390    * @return a possibly empty set of injection points. The set has a specified iteration order. All
391    *      fields are returned and then all methods. Within the fields, supertype fields are returned
392    *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
393    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
394    *      a field with multiple binding annotations. The exception's {@link
395    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
396    *      of the valid injection points.
397    */
forInstanceMethodsAndFields(Class<?> type)398   public static Set<InjectionPoint> forInstanceMethodsAndFields(Class<?> type) {
399     return forInstanceMethodsAndFields(TypeLiteral.get(type));
400   }
401 
402   /**
403    * Returns true if the binding annotation is in the wrong place.
404    */
checkForMisplacedBindingAnnotations(Member member, Errors errors)405   private static boolean checkForMisplacedBindingAnnotations(Member member, Errors errors) {
406     Annotation misplacedBindingAnnotation = Annotations.findBindingAnnotation(
407         errors, member, ((AnnotatedElement) member).getAnnotations());
408     if (misplacedBindingAnnotation == null) {
409       return false;
410     }
411 
412     // don't warn about misplaced binding annotations on methods when there's a field with the same
413     // name. In Scala, fields always get accessor methods (that we need to ignore). See bug 242.
414     if (member instanceof Method) {
415       try {
416         if (member.getDeclaringClass().getDeclaredField(member.getName()) != null) {
417           return false;
418         }
419       } catch (NoSuchFieldException ignore) {
420       }
421     }
422 
423     errors.misplacedBindingAnnotation(member, misplacedBindingAnnotation);
424     return true;
425   }
426 
427   /**
428    * Node in the doubly-linked list of injectable members (fields and methods).
429    */
430   static abstract class InjectableMember {
431     final TypeLiteral<?> declaringType;
432     final boolean optional;
433     final boolean jsr330;
434     InjectableMember previous;
435     InjectableMember next;
436 
InjectableMember(TypeLiteral<?> declaringType, Annotation atInject)437     InjectableMember(TypeLiteral<?> declaringType, Annotation atInject) {
438       this.declaringType = declaringType;
439 
440       if (atInject.annotationType() == javax.inject.Inject.class) {
441         optional = false;
442         jsr330 = true;
443         return;
444       }
445 
446       jsr330 = false;
447       optional = ((Inject) atInject).optional();
448     }
449 
toInjectionPoint()450     abstract InjectionPoint toInjectionPoint();
451   }
452 
453   static class InjectableField extends InjectableMember {
454     final Field field;
InjectableField(TypeLiteral<?> declaringType, Field field, Annotation atInject)455     InjectableField(TypeLiteral<?> declaringType, Field field,
456         Annotation atInject) {
457       super(declaringType, atInject);
458       this.field = field;
459     }
460 
461     @Override
toInjectionPoint()462     InjectionPoint toInjectionPoint() {
463       return new InjectionPoint(declaringType, field, optional);
464     }
465   }
466 
467   static class InjectableMethod extends InjectableMember {
468     final Method method;
469     /**
470      * true if this method overrode a method that was annotated
471      * with com.google.inject.Inject.  used to allow different
472      * override behavior for guice inject vs javax.inject.Inject
473      */
474     boolean overrodeGuiceInject;
InjectableMethod(TypeLiteral<?> declaringType, Method method, Annotation atInject)475     InjectableMethod(TypeLiteral<?> declaringType, Method method,
476         Annotation atInject) {
477       super(declaringType, atInject);
478       this.method = method;
479     }
480 
481     @Override
toInjectionPoint()482     InjectionPoint toInjectionPoint() {
483       return new InjectionPoint(declaringType, method, optional);
484     }
485 
isFinal()486     public boolean isFinal() {
487       return Modifier.isFinal(method.getModifiers());
488     }
489   }
490 
getAtInject(AnnotatedElement member)491   static Annotation getAtInject(AnnotatedElement member) {
492     Annotation a = member.getAnnotation(javax.inject.Inject.class);
493     return a == null ? member.getAnnotation(Inject.class) : a;
494   }
495 
496   /**
497    * Linked list of injectable members.
498    */
499   static class InjectableMembers {
500     InjectableMember head;
501     InjectableMember tail;
502 
add(InjectableMember member)503     void add(InjectableMember member) {
504       if (head == null) {
505         head = tail = member;
506       } else {
507         member.previous = tail;
508         tail.next = member;
509         tail = member;
510       }
511     }
512 
remove(InjectableMember member)513     void remove(InjectableMember member) {
514       if (member.previous != null) {
515         member.previous.next = member.next;
516       }
517       if (member.next != null) {
518         member.next.previous = member.previous;
519       }
520       if (head == member) {
521         head = member.next;
522       }
523       if (tail == member) {
524         tail = member.previous;
525       }
526     }
527 
isEmpty()528     boolean isEmpty() {
529       return head == null;
530     }
531   }
532 
533   /** Position in type hierarchy. */
534   enum Position {
535     TOP, // No need to check for overridden methods
536     MIDDLE,
537     BOTTOM // Methods won't be overridden
538   }
539 
540   /**
541    * Keeps track of injectable methods so we can remove methods that get overridden in O(1) time.
542    * Uses our position in the type hierarchy to perform optimizations.
543    */
544   static class OverrideIndex {
545     final InjectableMembers injectableMembers;
546     Map<Signature, List<InjectableMethod>> bySignature;
547     Position position = Position.TOP;
548 
OverrideIndex(InjectableMembers injectableMembers)549     OverrideIndex(InjectableMembers injectableMembers) {
550       this.injectableMembers = injectableMembers;
551     }
552 
553     /* Caches the signature for the last method. */
554     Method lastMethod;
555     Signature lastSignature;
556 
557     /**
558      * Removes a method overridden by the given method, if present. In order to
559      * remain backwards compatible with prior Guice versions, this will *not*
560      * remove overridden methods if 'alwaysRemove' is false and the overridden
561      * signature was annotated with a com.google.inject.Inject.
562      *
563      * @param method
564      *          The method used to determine what is overridden and should be
565      *          removed.
566      * @param alwaysRemove
567      *          true if overridden methods should be removed even if they were
568      *          guice @Inject
569      * @param injectableMethod
570      *          if this method overrode any guice @Inject methods,
571      *          {@link InjectableMethod#overrodeGuiceInject} is set to true
572      */
removeIfOverriddenBy(Method method, boolean alwaysRemove, InjectableMethod injectableMethod)573     boolean removeIfOverriddenBy(Method method, boolean alwaysRemove,
574         InjectableMethod injectableMethod) {
575       if (position == Position.TOP) {
576         // If we're at the top of the hierarchy, there's nothing to override.
577         return false;
578       }
579 
580       if (bySignature == null) {
581         // We encountered a method in a subclass. Time to index the
582         // methods in the parent class.
583         bySignature = new HashMap<Signature, List<InjectableMethod>>();
584         for (InjectableMember member = injectableMembers.head; member != null;
585             member = member.next) {
586           if (!(member instanceof InjectableMethod)) continue;
587           InjectableMethod im = (InjectableMethod) member;
588           if (im.isFinal()) continue;
589           List<InjectableMethod> methods = new ArrayList<InjectableMethod>();
590           methods.add(im);
591           bySignature.put(new Signature(im.method), methods);
592         }
593       }
594 
595       lastMethod = method;
596       Signature signature = lastSignature = new Signature(method);
597       List<InjectableMethod> methods = bySignature.get(signature);
598       boolean removed = false;
599       if (methods != null) {
600         for (Iterator<InjectableMethod> iterator = methods.iterator();
601             iterator.hasNext();) {
602           InjectableMethod possiblyOverridden = iterator.next();
603           if (overrides(method, possiblyOverridden.method)) {
604             boolean wasGuiceInject =
605               !possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject;
606             if(injectableMethod != null) {
607               injectableMethod.overrodeGuiceInject = wasGuiceInject;
608             }
609             // Only actually remove the methods if we want to force
610             // remove or if the signature never specified @com.google.inject.Inject
611             // somewhere.
612             if(alwaysRemove || !wasGuiceInject) {
613               removed = true;
614               iterator.remove();
615               injectableMembers.remove(possiblyOverridden);
616             }
617           }
618         }
619       }
620       return removed;
621     }
622 
623     /**
624      * Adds the given method to the list of injection points. Keeps track of it in this index
625      * in case it gets overridden.
626      */
add(InjectableMethod injectableMethod)627     void add(InjectableMethod injectableMethod) {
628       injectableMembers.add(injectableMethod);
629       if (position == Position.BOTTOM
630           || injectableMethod.isFinal()) {
631         // This method can't be overridden, so there's no need to index it.
632         return;
633       }
634       if (bySignature != null) {
635         // Try to reuse the signature we created during removal
636         Signature signature = injectableMethod.method == lastMethod
637             ? lastSignature : new Signature(injectableMethod.method);
638         List<InjectableMethod> methods = bySignature.get(signature);
639         if (methods == null) {
640           methods = new ArrayList<InjectableMethod>();
641           bySignature.put(signature, methods);
642         }
643         methods.add(injectableMethod);
644       }
645     }
646   }
647 
648   /**
649    * Returns an ordered, immutable set of injection points for the given type. Members in
650    * superclasses come before members in subclasses. Within a class, fields come before methods.
651    * Overridden methods are filtered out.
652    *
653    * @param statics true is this method should return static members, false for instance members
654    * @param errors used to record errors
655    */
getInjectionPoints(final TypeLiteral<?> type, boolean statics, Errors errors)656   private static Set<InjectionPoint> getInjectionPoints(final TypeLiteral<?> type,
657       boolean statics, Errors errors) {
658     InjectableMembers injectableMembers = new InjectableMembers();
659     OverrideIndex overrideIndex = null;
660 
661     List<TypeLiteral<?>> hierarchy = hierarchyFor(type);
662     int topIndex = hierarchy.size() - 1;
663     for (int i = topIndex; i >= 0; i--) {
664       if (overrideIndex != null && i < topIndex) {
665         // Knowing the position within the hierarchy helps us make optimizations.
666         if (i == 0) {
667           overrideIndex.position = Position.BOTTOM;
668         } else {
669           overrideIndex.position = Position.MIDDLE;
670         }
671       }
672 
673       TypeLiteral<?> current = hierarchy.get(i);
674 
675       for (Field field : current.getRawType().getDeclaredFields()) {
676         if (Modifier.isStatic(field.getModifiers()) == statics) {
677           Annotation atInject = getAtInject(field);
678           if (atInject != null) {
679             InjectableField injectableField = new InjectableField(current, field, atInject);
680             if (injectableField.jsr330 && Modifier.isFinal(field.getModifiers())) {
681               errors.cannotInjectFinalField(field);
682             }
683             injectableMembers.add(injectableField);
684           }
685         }
686       }
687 
688       for (Method method : current.getRawType().getDeclaredMethods()) {
689         if (isEligibleForInjection(method, statics)) {
690           Annotation atInject = getAtInject(method);
691           if (atInject != null) {
692             InjectableMethod injectableMethod = new InjectableMethod(
693                 current, method, atInject);
694             if (checkForMisplacedBindingAnnotations(method, errors)
695                 || !isValidMethod(injectableMethod, errors)) {
696               if (overrideIndex != null) {
697                 boolean removed = overrideIndex.removeIfOverriddenBy(method, false, injectableMethod);
698                 if(removed) {
699                   logger.log(Level.WARNING, "Method: {0} is not a valid injectable method ("
700                       + "because it either has misplaced binding annotations "
701                       + "or specifies type parameters) but is overriding a method that is valid. "
702                       + "Because it is not valid, the method will not be injected. "
703                       + "To fix this, make the method a valid injectable method.", method);
704                 }
705               }
706               continue;
707             }
708             if (statics) {
709               injectableMembers.add(injectableMethod);
710             } else {
711               if (overrideIndex == null) {
712                 /*
713                  * Creating the override index lazily means that the first type in the hierarchy
714                  * with injectable methods (not necessarily the top most type) will be treated as
715                  * the TOP position and will enjoy the same optimizations (no checks for overridden
716                  * methods, etc.).
717                  */
718                 overrideIndex = new OverrideIndex(injectableMembers);
719               } else {
720                 // Forcibly remove the overriden method, otherwise we'll inject
721                 // it twice.
722                 overrideIndex.removeIfOverriddenBy(method, true, injectableMethod);
723               }
724               overrideIndex.add(injectableMethod);
725             }
726           } else {
727             if(overrideIndex != null) {
728               boolean removed = overrideIndex.removeIfOverriddenBy(method, false, null);
729               if(removed) {
730                 logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but "
731                     + "is overriding a method that is annotated with @javax.inject.Inject.  Because "
732                     + "it is not annotated with @Inject, the method will not be injected. "
733                     + "To fix this, annotate the method with @Inject.", method);
734               }
735             }
736           }
737         }
738       }
739     }
740 
741     if (injectableMembers.isEmpty()) {
742       return Collections.emptySet();
743     }
744 
745     ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
746     for (InjectableMember im = injectableMembers.head; im != null;
747         im = im.next) {
748       try {
749         builder.add(im.toInjectionPoint());
750       } catch (ConfigurationException ignorable) {
751         if (!im.optional) {
752           errors.merge(ignorable.getErrorMessages());
753         }
754       }
755     }
756     return builder.build();
757   }
758 
759   /**
760    * Returns true if the method is eligible to be injected.  This is different than
761    * {@link #isValidMethod}, because ineligibility will not drop a method
762    * from being injected if a superclass was eligible & valid.
763    * Bridge & synthetic methods are excluded from eligibility for two reasons:
764    *
765    * <p>Prior to Java8, javac would generate these methods in subclasses without
766    * annotations, which means this would accidentally stop injecting a method
767    * annotated with {@link javax.inject.Inject}, since the spec says to stop
768    * injecting if a subclass isn't annotated with it.
769    *
770    * <p>Starting at Java8, javac copies the annotations to the generated subclass
771    * method, except it leaves out the generic types.  If this considered it a valid
772    * injectable method, this would eject the parent's overridden method that had the
773    * proper generic types, and would use invalid injectable parameters as a result.
774    *
775    * <p>The fix for both is simply to ignore these synthetic bridge methods.
776    */
isEligibleForInjection(Method method, boolean statics)777   private static boolean isEligibleForInjection(Method method, boolean statics) {
778     return Modifier.isStatic(method.getModifiers()) == statics
779         && !method.isBridge()
780         && !method.isSynthetic();
781   }
782 
isValidMethod(InjectableMethod injectableMethod, Errors errors)783   private static boolean isValidMethod(InjectableMethod injectableMethod,
784       Errors errors) {
785     boolean result = true;
786     if (injectableMethod.jsr330) {
787       Method method = injectableMethod.method;
788       if (Modifier.isAbstract(method.getModifiers())) {
789         errors.cannotInjectAbstractMethod(method);
790         result = false;
791       }
792       if (method.getTypeParameters().length > 0) {
793         errors.cannotInjectMethodWithTypeParameters(method);
794         result = false;
795       }
796     }
797     return result;
798   }
799 
hierarchyFor(TypeLiteral<?> type)800   private static List<TypeLiteral<?>> hierarchyFor(TypeLiteral<?> type) {
801     List<TypeLiteral<?>> hierarchy = new ArrayList<TypeLiteral<?>>();
802     TypeLiteral<?> current = type;
803     while (current.getRawType() != Object.class) {
804       hierarchy.add(current);
805       current = current.getSupertype(current.getRawType().getSuperclass());
806     }
807     return hierarchy;
808   }
809 
810   /**
811    * Returns true if a overrides b. Assumes signatures of a and b are the same and a's declaring
812    * class is a subclass of b's declaring class.
813    */
overrides(Method a, Method b)814   private static boolean overrides(Method a, Method b) {
815     // See JLS section 8.4.8.1
816     int modifiers = b.getModifiers();
817     if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
818       return true;
819     }
820     if (Modifier.isPrivate(modifiers)) {
821       return false;
822     }
823     // b must be package-private
824     return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
825   }
826 
827   /**
828    * A method signature. Used to handle method overridding.
829    */
830   static class Signature {
831 
832     final String name;
833     final Class[] parameterTypes;
834     final int hash;
835 
Signature(Method method)836     Signature(Method method) {
837       this.name = method.getName();
838       this.parameterTypes = method.getParameterTypes();
839 
840       int h = name.hashCode();
841       h = h * 31 + parameterTypes.length;
842       for (Class parameterType : parameterTypes) {
843         h = h * 31 + parameterType.hashCode();
844       }
845       this.hash = h;
846     }
847 
hashCode()848     @Override public int hashCode() {
849       return this.hash;
850     }
851 
equals(Object o)852     @Override public boolean equals(Object o) {
853       if (!(o instanceof Signature)) {
854         return false;
855       }
856 
857       Signature other = (Signature) o;
858       if (!name.equals(other.name)) {
859         return false;
860       }
861 
862       if (parameterTypes.length != other.parameterTypes.length) {
863         return false;
864       }
865 
866       for (int i = 0; i < parameterTypes.length; i++) {
867         if (parameterTypes[i] != other.parameterTypes[i]) {
868           return false;
869         }
870       }
871 
872       return true;
873     }
874   }
875 }
876