void add(InjectableMember member) { if (head == null) { head = tail = member; } else { member.previous = tail; tail.next = member; tail = member; } }
/** * 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 (isEligibleForInjection(method, 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(); }