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