コード例 #1
0
    /**
     * 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;
    }
コード例 #2
0
 /**
  * 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);
   }
 }
コード例 #3
0
  /**
   * 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();
  }