docs: InjectionTarget[] getInjectionTargets(Map<Class<?>, List<InjectionTarget>> declaredTargets,
                                            Class<?> instanceClass,
                                            boolean checkAppConfig)
                      throws InjectionException
      {
          final boolean isTraceOn = TraceComponent.isAnyTracingEnabled();
          if (isTraceOn && tc.isEntryEnabled())
              Tr.entry(tc, "getInjectionTargets: " + instanceClass + "/" + AccessController.doPrivileged(new GetClassLoaderPrivileged(instanceClass)));
  
          // d622258.1 - A field or method should only be injected once.  If
          // multiple annotations (or injection-target) are applied to the same
          // member, then we will instantiate multiple objects and call setters
          // multiple times.  The last injection will "win", but the order is
          // undefined.  To warn the user, we maintain a map of members to targets.
          Map<Member, InjectionTarget> injectionTargets = null;
  
          // Lazily initialized set of non-private, non-overridden methods in the
          // class hierarchy.                                                d719917
          Set<Method> nonPrivateMethods = null;
  
          // Create a list of classes in the hierarchy from Object to superclass
          // to instanceClass.  This ensures that we inject into superclass methods
          // before subclass methods.                                        d719917
          List<Class<?>> classHierarchy = new ArrayList<Class<?>>();
          for (Class<?> superclass = instanceClass; superclass != null && superclass != Object.class; // d721081
          superclass = superclass.getSuperclass())
          {
              classHierarchy.add(superclass);
          }
          Collections.reverse(classHierarchy);
  
          // Fields must be injected before methods, so we make two passes over
          // the injection targets: first fields, then methods.
          for (int memberRound = 0; memberRound < 2; memberRound++)
          {
              boolean wantFields = memberRound == 0;
  
              if (isTraceOn && tc.isDebugEnabled())
                  Tr.debug(tc, wantFields ? "collecting fields" : "collecting methods");
  
              for (Class<?> superclass : classHierarchy)
              {
                  List<InjectionTarget> classTargets = declaredTargets.get(superclass);
                  if (classTargets == null)
                  {
                      if (isTraceOn && tc.isDebugEnabled())
                          Tr.debug(tc, "no members for " + superclass + "/" + AccessController.doPrivileged(new GetClassLoaderPrivileged(superclass)));
                      continue;
                  }
  
                  for (InjectionTarget injectionTarget : classTargets)
                  {
                      Member member = injectionTarget.getMember();
  
                      boolean isField = member instanceof Field;
                      if (wantFields != isField)
                      {
                          continue;
                      }
  
                      // Only consider fields and non-overridden methods.  Private
                      // methods and methods on the class itself are trivially not
                      // overridden.                                            d719917
                      if (!isField &&
                          !Modifier.isPrivate(member.getModifiers()) &&
                          member.getDeclaringClass() != instanceClass)
                      {
                          if (nonPrivateMethods == null)
                          {
                              // Compute the set of "overriding" non-private methods in
                              // the hierarchy.
                              nonPrivateMethods = new HashSet<Method>();
                              for (MethodMap.MethodInfo methodInfo : MethodMap.getAllNonPrivateMethods(instanceClass))
                              {
                                  nonPrivateMethods.add(methodInfo.getMethod());
                              }
                          }
  
                          if (!nonPrivateMethods.contains(member))
                          {
                              // The method was overridden.
                              if (isTraceOn && tc.isDebugEnabled())
                                  Tr.debug(tc, "skipping overridden " + member + " for " +
                                               Util.identity(injectionTarget.getInjectionBinding()) +
                                               '[' + injectionTarget.getInjectionBinding().getDisplayName() + ']');
                              continue;
                          }
                      }
  
                      if (injectionTargets == null)
                      {
                          injectionTargets = new LinkedHashMap<Member, InjectionTarget>();
                      }
  
                      if (isTraceOn && tc.isDebugEnabled())
                          Tr.debug(tc, "adding " + member + " for " +
                                       Util.identity(injectionTarget.getInjectionBinding()) +
                                       '[' + injectionTarget.getInjectionBinding().getDisplayName() + ']');
  
                      InjectionTarget previousTarget = injectionTargets.put(member, injectionTarget);
  
                      if (previousTarget != null)
                      {
                          String memberName = member.getDeclaringClass().getName() + "." + member.getName();
                          Tr.warning(tc, "DUPLICATE_INJECTION_TARGETS_SPECIFIED_CWNEN0040W", memberName); //d447011
                          if (isValidationFailable(checkAppConfig)) // F50309.6
                          {
                              memberName += isField ? " field" : " method";
                              String curRefName = injectionTarget.getInjectionBinding().getDisplayName();
                              String preRefName = previousTarget.getInjectionBinding().getDisplayName();
                              throw new InjectionConfigurationException("The " + memberName + " was configured to be injected multiple times." +
                                                                        " The same injection target is associated with both the " + curRefName +
                                                                        " and " + preRefName + " references. The object injected is undefined.");
                          }
                      }
                  }
              }
          }
  
          InjectionTarget[] result;
          if (injectionTargets == null)
          {
              result = EMPTY_INJECTION_TARGETS;
          }
          else
          {
              result = new InjectionTarget[injectionTargets.size()];
              injectionTargets.values().toArray(result);
          }
  
          if (isTraceOn && tc.isEntryEnabled())
              Tr.exit(tc, "getInjectionTargets: " + result.length);
          return result;
      }