aboutsummaryrefslogtreecommitdiff
path: root/core/src/com/google/inject/spi/InjectionPoint.java
blob: c9083141e12ffe0bbb763e34f5ebc5c5189cc158 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
/**
 * Copyright (C) 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.inject.spi;

import com.google.inject.ConfigurationException;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.Annotations;
import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
import static com.google.inject.internal.MoreTypes.getRawType;
import com.google.inject.internal.Nullability;
import com.google.inject.internal.util.Classes;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A constructor, field or method that can receive injections. Typically this is a member with the
 * {@literal @}{@link Inject} annotation. For non-private, no argument constructors, the member may
 * omit the annotation.
 *
 * @author crazybob@google.com (Bob Lee)
 * @since 2.0
 */
public final class InjectionPoint {
  
  private static final Logger logger = Logger.getLogger(InjectionPoint.class.getName());

  private final boolean optional;
  private final Member member;
  private final TypeLiteral<?> declaringType;
  private final ImmutableList<Dependency<?>> dependencies;

  InjectionPoint(TypeLiteral<?> declaringType, Method method, boolean optional) {
    this.member = method;
    this.declaringType = declaringType;
    this.optional = optional;
    this.dependencies = forMember(method, declaringType, method.getParameterAnnotations());
  }

  InjectionPoint(TypeLiteral<?> declaringType, Constructor<?> constructor) {
    this.member = constructor;
    this.declaringType = declaringType;
    this.optional = false;
    this.dependencies = forMember(
        constructor, declaringType, constructor.getParameterAnnotations());
  }

  InjectionPoint(TypeLiteral<?> declaringType, Field field, boolean optional) {
    this.member = field;
    this.declaringType = declaringType;
    this.optional = optional;

    Annotation[] annotations = field.getAnnotations();

    Errors errors = new Errors(field);
    Key<?> key = null;
    try {
      key = Annotations.getKey(declaringType.getFieldType(field), field, annotations, errors);
    } catch (ConfigurationException e) {
      errors.merge(e.getErrorMessages());
    } catch (ErrorsException e) {
      errors.merge(e.getErrors());
    }
    errors.throwConfigurationExceptionIfErrorsExist();

    this.dependencies = ImmutableList.<Dependency<?>>of(
        newDependency(key, Nullability.allowsNull(annotations), -1));
  }

  private ImmutableList<Dependency<?>> forMember(Member member, TypeLiteral<?> type,
      Annotation[][] paramterAnnotations) {
    Errors errors = new Errors(member);
    Iterator<Annotation[]> annotationsIterator = Arrays.asList(paramterAnnotations).iterator();

    List<Dependency<?>> dependencies = Lists.newArrayList();
    int index = 0;

    for (TypeLiteral<?> parameterType : type.getParameterTypes(member)) {
      try {
        Annotation[] parameterAnnotations = annotationsIterator.next();
        Key<?> key = Annotations.getKey(parameterType, member, parameterAnnotations, errors);
        dependencies.add(newDependency(key, Nullability.allowsNull(parameterAnnotations), index));
        index++;
      } catch (ConfigurationException e) {
        errors.merge(e.getErrorMessages());
      } catch (ErrorsException e) {
        errors.merge(e.getErrors());
      }
    }

    errors.throwConfigurationExceptionIfErrorsExist();
    return ImmutableList.copyOf(dependencies);
  }

  // This metohd is necessary to create a Dependency<T> with proper generic type information
  private <T> Dependency<T> newDependency(Key<T> key, boolean allowsNull, int parameterIndex) {
    return new Dependency<T>(this, key, allowsNull, parameterIndex);
  }

  /**
   * Returns the injected constructor, field, or method.
   */
  public Member getMember() {
    // TODO: Don't expose the original member (which probably has setAccessible(true)).
    return member;
  }

  /**
   * Returns the dependencies for this injection point. If the injection point is for a method or
   * constructor, the dependencies will correspond to that member's parameters. Field injection
   * points always have a single dependency for the field itself.
   *
   * @return a possibly-empty list
   */
  public List<Dependency<?>> getDependencies() {
    return dependencies;
  }

  /**
   * Returns true if this injection point shall be skipped if the injector cannot resolve bindings
   * for all required dependencies. Both explicit bindings (as specified in a module), and implicit
   * bindings ({@literal @}{@link com.google.inject.ImplementedBy ImplementedBy}, default
   * constructors etc.) may be used to satisfy optional injection points.
   */
  public boolean isOptional() {
    return optional;
  }
  
  /**
   * Returns true if the element is annotated with {@literal @}{@link Toolable}.
   * 
   * @since 3.0
   */
  public boolean isToolable() {
    return ((AnnotatedElement)member).isAnnotationPresent(Toolable.class);
  }

  /**
   * Returns the generic type that defines this injection point. If the member exists on a
   * parameterized type, the result will include more type information than the member's {@link
   * Member#getDeclaringClass() raw declaring class}.
   * 
   * @since 3.0
   */
  public TypeLiteral<?> getDeclaringType() {
    return declaringType;
  }

  @Override public boolean equals(Object o) {
    return o instanceof InjectionPoint
        && member.equals(((InjectionPoint) o).member)
        && declaringType.equals(((InjectionPoint) o).declaringType);
  }

  @Override public int hashCode() {
    return member.hashCode() ^ declaringType.hashCode();
  }

  @Override public String toString() {
    return Classes.toString(member);
  }

  /**
   * Returns a new injection point for the specified constructor. If the declaring type of {@code
   * constructor} is parameterized (such as {@code List<T>}), prefer the overload that includes a
   * type literal.
   *
   * @param constructor any single constructor present on {@code type}.
   * 
   * @since 3.0
   */
  public static <T> InjectionPoint forConstructor(Constructor<T> constructor) {
    return new InjectionPoint(TypeLiteral.get(constructor.getDeclaringClass()), constructor);
  }

  /**
   * Returns a new injection point for the specified constructor of {@code type}.
   *
   * @param constructor any single constructor present on {@code type}.
   * @param type the concrete type that defines {@code constructor}.
   * 
   * @since 3.0
   */
  public static <T> InjectionPoint forConstructor(
      Constructor<T> constructor, TypeLiteral<? extends T> type) {
    if (type.getRawType() != constructor.getDeclaringClass()) {
      new Errors(type)
          .constructorNotDefinedByType(constructor, type)
          .throwConfigurationExceptionIfErrorsExist();
    }

    return new InjectionPoint(type, constructor);
  }

  /**
   * Returns a new injection point for the injectable constructor of {@code type}.
   *
   * @param type a concrete type with exactly one constructor annotated {@literal @}{@link Inject},
   *     or a no-arguments constructor that is not private.
   * @throws ConfigurationException if there is no injectable constructor, more than one injectable
   *     constructor, or if parameters of the injectable constructor are malformed, such as a
   *     parameter with multiple binding annotations.
   */
  public static InjectionPoint forConstructorOf(TypeLiteral<?> type) {
    Class<?> rawType = getRawType(type.getType());
    Errors errors = new Errors(rawType);

    Constructor<?> injectableConstructor = null;
    for (Constructor<?> constructor : rawType.getDeclaredConstructors()) {

      boolean optional;
      Inject guiceInject = constructor.getAnnotation(Inject.class);
      if (guiceInject == null) {
        javax.inject.Inject javaxInject = constructor.getAnnotation(javax.inject.Inject.class);
        if (javaxInject == null) {
          continue;
        }
        optional = false;
      } else {
        optional = guiceInject.optional();
      }

      if (optional) {
        errors.optionalConstructor(constructor);
      }

      if (injectableConstructor != null) {
        errors.tooManyConstructors(rawType);
      }

      injectableConstructor = constructor;
      checkForMisplacedBindingAnnotations(injectableConstructor, errors);
    }

    errors.throwConfigurationExceptionIfErrorsExist();

    if (injectableConstructor != null) {
      return new InjectionPoint(type, injectableConstructor);
    }

    // If no annotated constructor is found, look for a no-arg constructor instead.
    try {
      Constructor<?> noArgConstructor = rawType.getDeclaredConstructor();

      // Disallow private constructors on non-private classes (unless they have @Inject)
      if (Modifier.isPrivate(noArgConstructor.getModifiers())
          && !Modifier.isPrivate(rawType.getModifiers())) {
        errors.missingConstructor(rawType);
        throw new ConfigurationException(errors.getMessages());
      }

      checkForMisplacedBindingAnnotations(noArgConstructor, errors);
      return new InjectionPoint(type, noArgConstructor);
    } catch (NoSuchMethodException e) {
      errors.missingConstructor(rawType);
      throw new ConfigurationException(errors.getMessages());
    }
  }

  /**
   * Returns a new injection point for the injectable constructor of {@code type}.
   *
   * @param type a concrete type with exactly one constructor annotated {@literal @}{@link Inject},
   *     or a no-arguments constructor that is not private.
   * @throws ConfigurationException if there is no injectable constructor, more than one injectable
   *     constructor, or if parameters of the injectable constructor are malformed, such as a
   *     parameter with multiple binding annotations.
   */
  public static InjectionPoint forConstructorOf(Class<?> type) {
    return forConstructorOf(TypeLiteral.get(type));
  }

  /**
   * Returns all static method and field injection points on {@code type}.
   *
   * @return a possibly empty set of injection points. The set has a specified iteration order. All
   *      fields are returned and then all methods. Within the fields, supertype fields are returned
   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
   * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
   *      a field with multiple binding annotations. The exception's {@link
   *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
   *      of the valid injection points.
   */
  public static Set<InjectionPoint> forStaticMethodsAndFields(TypeLiteral<?> type) {
    Errors errors = new Errors();

    Set<InjectionPoint> result = getInjectionPoints(type, true, errors);
    if (errors.hasErrors()) {
      throw new ConfigurationException(errors.getMessages()).withPartialValue(result);
    }
    return result;
  }

  /**
   * Returns all static method and field injection points on {@code type}.
   *
   * @return a possibly empty set of injection points. The set has a specified iteration order. All
   *      fields are returned and then all methods. Within the fields, supertype fields are returned
   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
   * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
   *      a field with multiple binding annotations. The exception's {@link
   *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
   *      of the valid injection points.
   */
  public static Set<InjectionPoint> forStaticMethodsAndFields(Class<?> type) {
    return forStaticMethodsAndFields(TypeLiteral.get(type));
  }

  /**
   * Returns all instance method and field injection points on {@code type}.
   *
   * @return a possibly empty set of injection points. The set has a specified iteration order. All
   *      fields are returned and then all methods. Within the fields, supertype fields are returned
   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
   * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
   *      a field with multiple binding annotations. The exception's {@link
   *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
   *      of the valid injection points.
   */
  public static Set<InjectionPoint> forInstanceMethodsAndFields(TypeLiteral<?> type) {
    Errors errors = new Errors();
    Set<InjectionPoint> result = getInjectionPoints(type, false, errors);
    if (errors.hasErrors()) {
      throw new ConfigurationException(errors.getMessages()).withPartialValue(result);
    }
    return result;
  }

  /**
   * Returns all instance method and field injection points on {@code type}.
   *
   * @return a possibly empty set of injection points. The set has a specified iteration order. All
   *      fields are returned and then all methods. Within the fields, supertype fields are returned
   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
   * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
   *      a field with multiple binding annotations. The exception's {@link
   *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
   *      of the valid injection points.
   */
  public static Set<InjectionPoint> forInstanceMethodsAndFields(Class<?> type) {
    return forInstanceMethodsAndFields(TypeLiteral.get(type));
  }

  /**
   * Returns true if the binding annotation is in the wrong place.
   */
  private static boolean checkForMisplacedBindingAnnotations(Member member, Errors errors) {
    Annotation misplacedBindingAnnotation = Annotations.findBindingAnnotation(
        errors, member, ((AnnotatedElement) member).getAnnotations());
    if (misplacedBindingAnnotation == null) {
      return false;
    }

    // don't warn about misplaced binding annotations on methods when there's a field with the same
    // name. In Scala, fields always get accessor methods (that we need to ignore). See bug 242.
    if (member instanceof Method) {
      try {
        if (member.getDeclaringClass().getDeclaredField(member.getName()) != null) {
          return false;
        }
      } catch (NoSuchFieldException ignore) {
      }
    }

    errors.misplacedBindingAnnotation(member, misplacedBindingAnnotation);
    return true;
  }

  /**
   * Node in the doubly-linked list of injectable members (fields and methods).
   */
  static abstract class InjectableMember {
    final TypeLiteral<?> declaringType;
    final boolean optional;
    final boolean jsr330;
    InjectableMember previous;
    InjectableMember next;

    InjectableMember(TypeLiteral<?> declaringType, Annotation atInject) {
      this.declaringType = declaringType;

      if (atInject.annotationType() == javax.inject.Inject.class) {
        optional = false;
        jsr330 = true;
        return;
      }

      jsr330 = false;
      optional = ((Inject) atInject).optional();
    }

    abstract InjectionPoint toInjectionPoint();
  }

  static class InjectableField extends InjectableMember {
    final Field field;
    InjectableField(TypeLiteral<?> declaringType, Field field,
        Annotation atInject) {
      super(declaringType, atInject);
      this.field = field;
    }

    InjectionPoint toInjectionPoint() {
      return new InjectionPoint(declaringType, field, optional);
    }
  }

  static class InjectableMethod extends InjectableMember {
    final Method method;
    /**
     * true if this method overrode a method that was annotated
     * with com.google.inject.Inject.  used to allow different
     * override behavior for guice inject vs javax.inject.Inject
     */
    boolean overrodeGuiceInject;
    InjectableMethod(TypeLiteral<?> declaringType, Method method,
        Annotation atInject) {
      super(declaringType, atInject);
      this.method = method;
    }

    InjectionPoint toInjectionPoint() {
      return new InjectionPoint(declaringType, method, optional);
    }

    public boolean isFinal() {
      return Modifier.isFinal(method.getModifiers());
    }
  }

  static Annotation getAtInject(AnnotatedElement member) {
    Annotation a = member.getAnnotation(javax.inject.Inject.class);
    return a == null ? member.getAnnotation(Inject.class) : a;
  }

  /**
   * Linked list of injectable members.
   */
  static class InjectableMembers {
    InjectableMember head;
    InjectableMember tail;

    void add(InjectableMember member) {
      if (head == null) {
        head = tail = member;
      } else {
        member.previous = tail;
        tail.next = member;
        tail = member;
      }
    }

    void remove(InjectableMember member) {
      if (member.previous != null) {
        member.previous.next = member.next;
      }
      if (member.next != null) {
        member.next.previous = member.previous;
      }
      if (head == member) {
        head = member.next;
      }
      if (tail == member) {
        tail = member.previous;
      }
    }

    boolean isEmpty() {
      return head == null;
    }
  }

  /** Position in type hierarchy. */
  enum Position {
    TOP, // No need to check for overridden methods
    MIDDLE,
    BOTTOM // Methods won't be overridden
  }

  /**
   * Keeps track of injectable methods so we can remove methods that get overridden in O(1) time.
   * Uses our position in the type hierarchy to perform optimizations.
   */
  static class OverrideIndex {
    final InjectableMembers injectableMembers;
    Map<Signature, List<InjectableMethod>> bySignature;
    Position position = Position.TOP;

    OverrideIndex(InjectableMembers injectableMembers) {
      this.injectableMembers = injectableMembers;
    }

    /* Caches the signature for the last method. */
    Method lastMethod;
    Signature lastSignature;

    /**
     * Removes a method overridden by the given method, if present. In order to
     * remain backwards compatible with prior Guice versions, this will *not*
     * remove overridden methods if 'alwaysRemove' is false and the overridden
     * signature was annotated with a com.google.inject.Inject.
     * 
     * @param method
     *          The method used to determine what is overridden and should be
     *          removed.
     * @param alwaysRemove
     *          true if overridden methods should be removed even if they were
     *          guice @Inject
     * @param injectableMethod
     *          if this method overrode any guice @Inject methods,
     *          {@link InjectableMethod#overrodeGuiceInject} is set to true
     */
    boolean removeIfOverriddenBy(Method method, boolean alwaysRemove, 
        InjectableMethod injectableMethod) {
      if (position == Position.TOP) {
        // If we're at the top of the hierarchy, there's nothing to override.
        return false;
      }

      if (bySignature == null) {
        // We encountered a method in a subclass. Time to index the
        // methods in the parent class.
        bySignature = new HashMap<Signature, List<InjectableMethod>>();
        for (InjectableMember member = injectableMembers.head; member != null;
            member = member.next) {
          if (!(member instanceof InjectableMethod)) continue;
          InjectableMethod im = (InjectableMethod) member;
          if (im.isFinal()) continue;
          List<InjectableMethod> methods = new ArrayList<InjectableMethod>();
          methods.add(im);
          bySignature.put(new Signature(im.method), methods);
        }
      }

      lastMethod = method;
      Signature signature = lastSignature = new Signature(method);
      List<InjectableMethod> methods = bySignature.get(signature);
      boolean removed = false;
      if (methods != null) {
        for (Iterator<InjectableMethod> iterator = methods.iterator();
            iterator.hasNext();) {
          InjectableMethod possiblyOverridden = iterator.next();
          if (overrides(method, possiblyOverridden.method)) {
            boolean wasGuiceInject =
              !possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject;
            if(injectableMethod != null) {
              injectableMethod.overrodeGuiceInject = wasGuiceInject;
            }
            // Only actually remove the methods if we want to force
            // remove or if the signature never specified @com.google.inject.Inject
            // somewhere.
            if(alwaysRemove || !wasGuiceInject) {
              removed = true;
              iterator.remove();
              injectableMembers.remove(possiblyOverridden);
            }
          }
        }
      }
      return removed;
    }

    /**
     * Adds the given method to the list of injection points. Keeps track of it in this index
     * in case it gets overridden.
     */
    void add(InjectableMethod injectableMethod) {
      injectableMembers.add(injectableMethod);
      if (position == Position.BOTTOM
          || injectableMethod.isFinal()) {
        // This method can't be overridden, so there's no need to index it.
        return;
      }
      if (bySignature != null) {
        // Try to reuse the signature we created during removal
        Signature signature = injectableMethod.method == lastMethod
            ? lastSignature : new Signature(injectableMethod.method);
        List<InjectableMethod> methods = bySignature.get(signature);
        if (methods == null) {
          methods = new ArrayList<InjectableMethod>();
          bySignature.put(signature, methods);
        }
        methods.add(injectableMethod);
      }
    }
  }

  /**
   * Returns an ordered, immutable set of injection points for the given type. Members in
   * superclasses come before members in subclasses. Within a class, fields come before methods.
   * Overridden methods are filtered out.
   *
   * @param statics true is this method should return static members, false for instance members
   * @param errors used to record errors
   */
  private static Set<InjectionPoint> getInjectionPoints(final TypeLiteral<?> type,
      boolean statics, Errors errors) {
    InjectableMembers injectableMembers = new InjectableMembers();
    OverrideIndex overrideIndex = null;

    List<TypeLiteral<?>> hierarchy = hierarchyFor(type);
    int topIndex = hierarchy.size() - 1;
    for (int i = topIndex; i >= 0; i--) {
      if (overrideIndex != null && i < topIndex) {
        // Knowing the position within the hierarchy helps us make optimizations.
        if (i == 0) {
          overrideIndex.position = Position.BOTTOM;
        } else {
          overrideIndex.position = Position.MIDDLE;
        }
      }

      TypeLiteral<?> current = hierarchy.get(i);

      for (Field field : current.getRawType().getDeclaredFields()) {
        if (Modifier.isStatic(field.getModifiers()) == statics) {
          Annotation atInject = getAtInject(field);
          if (atInject != null) {
            InjectableField injectableField = new InjectableField(current, field, atInject);
            if (injectableField.jsr330 && Modifier.isFinal(field.getModifiers())) {
              errors.cannotInjectFinalField(field);
            }
            injectableMembers.add(injectableField);
          }
        }
      }

      for (Method method : current.getRawType().getDeclaredMethods()) {
        if (Modifier.isStatic(method.getModifiers()) == statics) {
          Annotation atInject = getAtInject(method);
          if (atInject != null) {
            InjectableMethod injectableMethod = new InjectableMethod(
                current, method, atInject);
            if (checkForMisplacedBindingAnnotations(method, errors)
                | !isValidMethod(injectableMethod, errors)) {
              if (overrideIndex != null) {
                boolean removed = overrideIndex.removeIfOverriddenBy(method, false, injectableMethod);
                if(removed) {
                  logger.log(Level.WARNING, "Method: {0} is not a valid injectable method ("
                      + "because it either has misplaced binding annotations "
                      + "or specifies type parameters) but is overriding a method that is valid. "
                      + "Because it is not valid, the method will not be injected. "
                      + "To fix this, make the method a valid injectable method.", method);
                }
              }
              continue;
            }
            if (statics) {
              injectableMembers.add(injectableMethod);
            } else {
              if (overrideIndex == null) {
                /*
                 * Creating the override index lazily means that the first type in the hierarchy
                 * with injectable methods (not necessarily the top most type) will be treated as
                 * the TOP position and will enjoy the same optimizations (no checks for overridden
                 * methods, etc.).
                 */
                overrideIndex = new OverrideIndex(injectableMembers);
              } else {
                // Forcibly remove the overriden method, otherwise we'll inject
                // it twice.
                overrideIndex.removeIfOverriddenBy(method, true, injectableMethod);
              }
              overrideIndex.add(injectableMethod);
            }
          } else {
            if(overrideIndex != null) {
              boolean removed = overrideIndex.removeIfOverriddenBy(method, false, null);
              if(removed) {
                logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but "
                    + "is overriding a method that is annotated with @javax.inject.Inject.  Because "
                    + "it is not annotated with @Inject, the method will not be injected. "
                    + "To fix this, annotate the method with @Inject.", method);
              }
            }
          }
        }
      }
    }

    if (injectableMembers.isEmpty()) {
      return Collections.emptySet();
    }

    ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
    for (InjectableMember im = injectableMembers.head; im != null;
        im = im.next) {
      try {
        builder.add(im.toInjectionPoint());
      } catch (ConfigurationException ignorable) {
        if (!im.optional) {
          errors.merge(ignorable.getErrorMessages());
        }
      }
    }
    return builder.build();
  }

  private static boolean isValidMethod(InjectableMethod injectableMethod,
      Errors errors) {
    boolean result = true;
    if (injectableMethod.jsr330) {
      Method method = injectableMethod.method;
      if (Modifier.isAbstract(method.getModifiers())) {
        errors.cannotInjectAbstractMethod(method);
        result = false;
      }
      if (method.getTypeParameters().length > 0) {
        errors.cannotInjectMethodWithTypeParameters(method);
        result = false;
      }
    }
    return result;
  }

  private static List<TypeLiteral<?>> hierarchyFor(TypeLiteral<?> type) {
    List<TypeLiteral<?>> hierarchy = new ArrayList<TypeLiteral<?>>();
    TypeLiteral<?> current = type;
    while (current.getRawType() != Object.class) {
      hierarchy.add(current);
      current = current.getSupertype(current.getRawType().getSuperclass());
    }
    return hierarchy;
  }

  /**
   * Returns true if a overrides b. Assumes signatures of a and b are the same and a's declaring
   * class is a subclass of b's declaring class.
   */
  private static boolean overrides(Method a, Method b) {
    // See JLS section 8.4.8.1
    int modifiers = b.getModifiers();
    if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
      return true;
    }
    if (Modifier.isPrivate(modifiers)) {
      return false;
    }
    // b must be package-private
    return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
  }

  /**
   * A method signature. Used to handle method overridding.
   */
  static class Signature {

    final String name;
    final Class[] parameterTypes;
    final int hash;

    Signature(Method method) {
      this.name = method.getName();
      this.parameterTypes = method.getParameterTypes();

      int h = name.hashCode();
      h = h * 31 + parameterTypes.length;
      for (Class parameterType : parameterTypes) {
        h = h * 31 + parameterType.hashCode();
      }
      this.hash = h;
    }

    @Override public int hashCode() {
      return this.hash;
    }

    @Override public boolean equals(Object o) {
      if (!(o instanceof Signature)) {
        return false;
      }

      Signature other = (Signature) o;
      if (!name.equals(other.name)) {
        return false;
      }

      if (parameterTypes.length != other.parameterTypes.length) {
        return false;
      }

      for (int i = 0; i < parameterTypes.length; i++) {
        if (parameterTypes[i] != other.parameterTypes[i]) {
          return false;
        }
      }

      return true;
    }
  }
}