docs: private void processAutomaticTimerMetaData(BeanMetaData bmd) throws EJBConfigurationException, ContainerException {
          final boolean isTraceOn = TraceComponent.isAnyTracingEnabled();
          if (isTraceOn && tc.isEntryEnabled())
              Tr.entry(tc, "processAutomaticTimerMetaData: " + bmd.j2eeName);
  
          // There are several considerations for how to obtain this metadata:
          //
          // 1.  Schedule/Schedules annotations can exist on super classes, so we
          //     cannot exclusively rely on ASM scanning.
          // 2.  Schedule/Schedules annotations can exist on private methods, and
          //     there is no way to unambiguously specify in XML which class in the
          //     hierarchy contains the method, so we cannot exclusively rely on
          //     the merged view.
          // 3.  We must have a complete view of annotations at application start
          //     time so we can create those timers.  However, we do not want to
          //     load bean classes or super-classes unless absolutely necessary.
          //
          // In order to accurately reason about annotations, we load bean classes.
          // However, to avoid loading every bean class at application startup, we
          // only do so if the merged view tells us we should expect to find
          // automatic timers.
  
          if (bmd.ivInitData.ivHasScheduleTimers == null) {
              if (isTraceOn && tc.isEntryEnabled())
                  Tr.exit(tc, "processAutomaticTimerMetaData: class scan data not found");
              // If there's no merged view data, then just keep going.
          } else if (!bmd.ivInitData.ivHasScheduleTimers) {
              if (isTraceOn && tc.isEntryEnabled())
                  Tr.exit(tc, "processAutomaticTimerMetaData: no class scan scheduler timers");
              return;
          }
  
          // The following rules are used for timers:
          //
          // 1.  @Schedule, @Schedules, and <timer/> are all additive when applied
          //     to the same method.
          // 2.  For non-private methods, @Schedule and @Schedules are only
          //     applicable for lowest sub-class (ala transaction attributes).
          // 3.  For private methods, @Schedule and @Schedules are applicable for
          //     any method in the class hierarchy.
          // 4.  For <timer/>, the method is located on the lowest sub-class,
          //     regardless of its visibility.
  
          //F743-15870
          // Timers can be specified in xml with three types of parm lists:
          //       1) <method-parm>javax.ejb.Timer</method-parm> (ie, 1 parm)
          //       2) <method-parm><method-parm>                 (ie, 0 parm)
          //       3) omitting <method-params> and/or <method-parm> (ie, unspecified parm)
          //
          // Timers with 1 parm can only map to Methods with 1 parm.
          // Timers with 0 parm can only map to Methods with 0 parm.
          // Timers with unspecified parms can map to Methods with 1 or 0 parm.
          List<com.ibm.ws.javaee.dd.ejb.Timer> timers = getAutomaticTimersFromXML(bmd.wccm.enterpriseBean);
          Map<String, List<com.ibm.ws.javaee.dd.ejb.Timer>> timers0ParmByMethodName = new HashMap<String, List<com.ibm.ws.javaee.dd.ejb.Timer>>();
          Map<String, List<com.ibm.ws.javaee.dd.ejb.Timer>> timers1ParmByMethodName = new HashMap<String, List<com.ibm.ws.javaee.dd.ejb.Timer>>();
          Map<String, List<com.ibm.ws.javaee.dd.ejb.Timer>> timersUnspecifiedParmByMethodName = new HashMap<String, List<com.ibm.ws.javaee.dd.ejb.Timer>>();
  
          // Add each timer specified in xml to the correct list, based on its parms.
          for (com.ibm.ws.javaee.dd.ejb.Timer timer : timers) {
              NamedMethod namedMethod = timer.getTimeoutMethod();
              String methodName = timer.getTimeoutMethod().getMethodName();
              List<String> methodParams = namedMethod.getMethodParamList();
              int parmCount = verifyXMLTimerParmList(methodParams, //F743-15870
                                                     bmd,
                                                     methodName,
                                                     false);
  
              addTimerToCorrectMap(timers1ParmByMethodName, //F743-15870
                                   timers0ParmByMethodName,
                                   timersUnspecifiedParmByMethodName,
                                   parmCount,
                                   methodName,
                                   timer);
          }
  
          // Load the bean class.
          Class<?> beanClass = loadCustomerProvidedBeanClass(bmd);
  
          // Determine if the unspecified timers map to 0 or 1 parm Methods
          if (!timersUnspecifiedParmByMethodName.isEmpty()) {
              mapUnspecifiedTimers(timers0ParmByMethodName,
                                   timers1ParmByMethodName,
                                   timersUnspecifiedParmByMethodName,
                                   beanClass,
                                   bmd);
          }
  
          // Process timeout metadata.  If we have a timeout method, create a
          // TimerMethodData with a special depth of -1.  This will ensure it is
          // sorted as the first timer method.  This TimerMethodData will be
          // reused below if an automatic timer also exists for the method.
          processTimeoutMetaData(bmd);
  
          List<TimerMethodData> timerMethods = new ArrayList<TimerMethodData>();
          Method timeoutMethod = getTimeoutMethod(bmd);
  
          if (timeoutMethod != null) {
              boolean oneParm = timeoutMethod.getParameterTypes().length == 1; //F743-15870
              timerMethods.add(new TimerMethodData(timeoutMethod, -1, oneParm)); //F743-15780
          }
  
          // Iterate over all methods declared in all classes, and build a list of
          // AutomaticTimerMethod objects for this bean.
          for (MethodMap.MethodInfo methodInfo : MethodMap.getAllDeclaredMethods(beanClass)) {
              Method method = methodInfo.getMethod();
              int depth = methodInfo.getClassDepth();
              String methodName = method.getName();
  
              TimerMethodData timerMethod = null;
              boolean createdTimerMethod = false;
  
              if (method.equals(timeoutMethod)) {
                  timerMethod = timerMethods.get(0);
  
                  if (isTraceOn && tc.isDebugEnabled())
                      Tr.debug(tc, "using timeout method ID for " + method);
              }
  
              // Process XML timers.  By removing the list of timers from
              // the map, we are ensuring the timers apply to methods on
              // the lowest sub-class only.
  
              List<com.ibm.ws.javaee.dd.ejb.Timer> timerList;
              boolean methodHas1Parm = false;
  
              if (hasTimeoutCallbackParameters(methodInfo)) {
                  if (methodInfo.getNumParameters() == 0) {
                      timerList = timers0ParmByMethodName.remove(methodName);
                  } else {
                      timerList = timers1ParmByMethodName.remove(methodName);
                      methodHas1Parm = true;
                  }
              } else {
                  timerList = null;
              }
  
              if (timerList != null) {
                  if (isTraceOn && tc.isDebugEnabled())
                      Tr.debug(tc, "processing XML timer for " + method);
  
                  if (timerMethod == null) {
                      timerMethod = new TimerMethodData(method, depth, methodHas1Parm); //F743-15870
                      timerMethods.add(timerMethod);
                      createdTimerMethod = true; // d666251
                  }
  
                  for (com.ibm.ws.javaee.dd.ejb.Timer timer : timerList) {
                      timerMethod.addAutomaticTimer(processAutomaticTimerFromXML(timer));
                  }
              }
              // Check annoations if metadata is NOT complete, and we did NOT
              // have any xml defined timer (0, 1, or undefined parms) mapping
              // to this Method
              else if (!bmd.metadataComplete) {
                  // Process the @Schedules annotation, if any.
                  Schedules schedulesAnnotation = method.getAnnotation(Schedules.class);
                  if (schedulesAnnotation != null) {
                      if (isTraceOn && tc.isDebugEnabled())
                          Tr.debug(tc, "processing @Schedules for " + method);
  
                      for (Schedule scheduleAnnotation : schedulesAnnotation.value()) {
                          if (timerMethod == null) {
                              timerMethod = new TimerMethodData(method, depth, methodHas1Parm);
                              timerMethods.add(timerMethod);
                              createdTimerMethod = true; // d666251
                          }
  
                          timerMethod.addAutomaticTimer(processScheduleAnnotation(timerMethod, method, timerMethods, scheduleAnnotation));
                      }
                  }
  
                  // Process the @Schedule annotation, if any.
                  Schedule scheduleAnnotation = method.getAnnotation(Schedule.class);
                  if (scheduleAnnotation != null) {
                      if (isTraceOn && tc.isDebugEnabled())
                          Tr.debug(tc, "processing @Schedule for " + method);
  
                      if (timerMethod == null) {
                          timerMethod = new TimerMethodData(method, depth, methodHas1Parm); //F743-15870
                          timerMethods.add(timerMethod);
                          createdTimerMethod = true; // d666251
                      }
  
                      timerMethod.addAutomaticTimer(processScheduleAnnotation(timerMethod, method, timerMethods, scheduleAnnotation));
                  }
              }
  
              // d666251 - Validate method signature.
              if (createdTimerMethod) {
                  validateTimeoutCallbackMethod(bmd, methodInfo);
              }
          }
  
          // Diagnose any unsatisfied automatic timers from XML.
          dealWithUnsatisifedXMLTimers(timers1ParmByMethodName, //F743-15870
                                       timers0ParmByMethodName,
                                       bmd);
  
          if (!timerMethods.isEmpty()) {
              if (bmd.type == InternalConstants.TYPE_STATEFUL_SESSION ||
                  bmd.type == InternalConstants.TYPE_MANAGED_BEAN) {
                  Tr.error(tc, "AUTOMATIC_TIMER_ON_STATEFUL_SESSION_CNTR0207E",
                           new Object[] { bmd.j2eeName.getComponent(), bmd.j2eeName.getModule() });
                  throw new EJBConfigurationException("CNTR0207E: The " + bmd.j2eeName.getComponent()
                                                      + " stateful session bean in the " + bmd.j2eeName.getModule()
                                                      + " module has an automatic timer.");
              }
  
              // Sort the timer methods, and then assign method IDs.  We must sort
              // methods so that method IDs remain stable for persistent timers even
              // if the JVM changes the order of methods returned by getMethods().
              Collections.sort(timerMethods);
  
              int methodId = 0;
              for (TimerMethodData timerMethod : timerMethods) {
                  timerMethod.ivMethodId = methodId++;
              }
  
              // Add the timer methods to module metadata so they will be created
              // once all the automatic timers for the module have been processed.
              bmd._moduleMetaData.addAutomaticTimerBean(new AutomaticTimerBean(bmd, timerMethods));
  
              // Check now if the runtime environment supports timers
              // rather than waiting until the automatic timers are created.
              bmd.container.getEJBRuntime().setupTimers(bmd);
          }
  
          // Always insert so finishBMDInit does not do extra work by calling
          // processTimeoutMetaData during deferred EJB initialization.
          bmd.ivInitData.ivTimerMethods = timerMethods;
  
          if (isTraceOn && tc.isEntryEnabled())
              Tr.exit(tc, "processAutomaticTimerMetaData: " + timerMethods.size());
      }