content: package com.alibaba.qlexpress4.runtime.util;
  
  import com.alibaba.qlexpress4.exception.ErrorReporter;
  import com.alibaba.qlexpress4.exception.QLErrorCodes;
  import com.alibaba.qlexpress4.exception.UserDefineException;
  import com.alibaba.qlexpress4.member.MethodHandler;
  import com.alibaba.qlexpress4.runtime.IMethod;
  import com.alibaba.qlexpress4.runtime.QLambda;
  import com.alibaba.qlexpress4.runtime.QResult;
  import com.alibaba.qlexpress4.runtime.ReflectLoader;
  import com.alibaba.qlexpress4.runtime.Value;
  import com.alibaba.qlexpress4.runtime.data.DataValue;
  import com.alibaba.qlexpress4.runtime.data.convert.ParametersTypeConvertor;
  
  import java.util.Arrays;
  import java.util.Map;
  
  /**
   * Author: DQinYuan
   */
  public class MethodInvokeUtils {
      
      public static Value findMethodAndInvoke(Object bean, String methodName, Object[] params, Class<?>[] type,
          ReflectLoader reflectLoader, ErrorReporter errorReporter) {
          IMethod method = reflectLoader.loadMethod(bean, methodName, type);
          if (method == null) {
              QLambda qLambdaInnerMethod = findQLambdaInstance(bean, methodName);
              if (qLambdaInnerMethod != null) {
                  try {
                      QResult qResult = qLambdaInnerMethod.call(params);
                      return ValueUtils.toImmutable(qResult.getResult());
                  }
                  catch (UserDefineException e) {
                      throw ThrowUtils.reportUserDefinedException(errorReporter, e);
                  }
                  catch (Throwable t) {
                      throw ThrowUtils.wrapThrowable(t,
                          errorReporter,
                          QLErrorCodes.INVOKE_LAMBDA_ERROR.name(),
                          QLErrorCodes.INVOKE_LAMBDA_ERROR.getErrorMsg());
                  }
              }
              else {
                  throw errorReporter.report(QLErrorCodes.METHOD_NOT_FOUND.name(),
                      String.format(QLErrorCodes.METHOD_NOT_FOUND.getErrorMsg(), methodName, Arrays.toString(params)));
              }
          }
          else {
              // method invoke
              Object[] convertResult =
                  ParametersTypeConvertor.cast(params, method.getParameterTypes(), method.isVarArgs());
              try {
                  Object value = MethodHandler.Access.accessMethodValue(method, bean, convertResult);
                  return new DataValue(value);
              }
              catch (Exception e) {
                  throw ReflectLoader.unwrapMethodInvokeEx(errorReporter, methodName, e);
              }
          }
      }
      
      private static QLambda findQLambdaInstance(Object bean, String methodName) {
          if (bean instanceof Map) {
              Map map = (Map)bean;
              Object mapValue = map.get(methodName);
              if (mapValue instanceof QLambda) {
                  return (QLambda)mapValue;
              }
          }
          return null;
      }
      
  }
  