public final Object invokeHandlerMethod(
      Method handlerMethod,
      Object handler,
      NativeWebRequest webRequest,
      ExtendedModelMap implicitModel)
      throws Exception {

    Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
    try {
      boolean debug = logger.isDebugEnabled();
      for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
        Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
        if (attrValue != null) {
          implicitModel.addAttribute(attrName, attrValue);
        }
      }
      for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
        Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
        Object[] args =
            resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
        if (debug) {
          logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
        }
        String attrName =
            AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
        if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
          continue;
        }
        ReflectionUtils.makeAccessible(attributeMethodToInvoke);
        Object attrValue = attributeMethodToInvoke.invoke(handler, args);
        if ("".equals(attrName)) {
          Class<?> resolvedType =
              GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
          attrName =
              Conventions.getVariableNameForReturnType(
                  attributeMethodToInvoke, resolvedType, attrValue);
        }
        if (!implicitModel.containsAttribute(attrName)) {
          implicitModel.addAttribute(attrName, attrValue);
        }
      }
      Object[] args =
          resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
      if (debug) {
        logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
      }
      ReflectionUtils.makeAccessible(handlerMethodToInvoke);
      return handlerMethodToInvoke.invoke(handler, args);
    } catch (IllegalStateException ex) {
      // Internal assertion failed (e.g. invalid signature):
      // throw exception with full handler method context...
      throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
    } catch (InvocationTargetException ex) {
      // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
      ReflectionUtils.rethrowException(ex.getTargetException());
      return null;
    }
  }
  protected final void addReturnValueAsModelAttribute(
      Method handlerMethod, Class handlerType, Object returnValue, ExtendedModelMap implicitModel) {

    ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class);
    String attrName = (attr != null ? attr.value() : "");
    if ("".equals(attrName)) {
      Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType);
      attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue);
    }
    implicitModel.addAttribute(attrName, returnValue);
  }
  public final Object invokeHandlerMethod(
      Method handlerMethod,
      Object handler,
      NativeWebRequest webRequest,
      ExtendedModelMap implicitModel)
      throws Exception {

    Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
    try {
      boolean debug = logger.isDebugEnabled();
      for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
        Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
        if (attrValue != null) {
          implicitModel.addAttribute(attrName, attrValue);
        }
      }
      for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
        Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
        Object[] args =
            resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
        if (debug) {
          logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
        }
        String attrName =
            AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value();
        if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
          continue;
        }
        Object attrValue = doInvokeMethod(attributeMethodToInvoke, handler, args);
        if ("".equals(attrName)) {
          Class resolvedType =
              GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
          attrName =
              Conventions.getVariableNameForReturnType(
                  attributeMethodToInvoke, resolvedType, attrValue);
        }
        if (!implicitModel.containsAttribute(attrName)) {
          implicitModel.addAttribute(attrName, attrValue);
        }
      }
      Object[] args =
          resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
      if (debug) {
        logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
      }
      return doInvokeMethod(handlerMethodToInvoke, handler, args);
    } catch (IllegalStateException ex) {
      // Throw exception with full handler method context...
      throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
    }
  }