content: package com.alibaba.qlexpress4.runtime.data.lambda;
  
  import com.alibaba.qlexpress4.exception.UserDefineException;
  import com.alibaba.qlexpress4.member.MethodHandler;
  import com.alibaba.qlexpress4.runtime.IMethod;
  import com.alibaba.qlexpress4.runtime.MetaClass;
  import com.alibaba.qlexpress4.runtime.QLambda;
  import com.alibaba.qlexpress4.runtime.QResult;
  import com.alibaba.qlexpress4.runtime.ReflectLoader;
  import com.alibaba.qlexpress4.runtime.data.DataValue;
  import com.alibaba.qlexpress4.runtime.data.convert.ParametersTypeConvertor;
  import com.alibaba.qlexpress4.runtime.function.CustomFunction;
  import com.alibaba.qlexpress4.utils.BasicUtil;
  
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.Map;
  
  /**
   * Author: TaoKan
   */
  public class QLambdaMethod implements QLambda {
      
      private final String methodName;
      
      private final ReflectLoader reflectLoader;
      
      private final Object bean;
      
      public QLambdaMethod(String methodName, ReflectLoader reflectLoader, Object obj) {
          this.methodName = methodName;
          this.reflectLoader = reflectLoader;
          this.bean = obj;
      }
      
      @Override
      public QResult call(Object... params)
          throws Exception {
          if (bean instanceof MetaClass) {
              Class<?>[] type = BasicUtil.getTypeOfObject(params);
              IMethod method = reflectLoader.loadMethod(bean, methodName, type);
              if (method != null) {
                  // static method
                  Object[] convertResult =
                      ParametersTypeConvertor.cast(params, method.getParameterTypes(), method.isVarArgs());
                  Object value = MethodHandler.Access.accessMethodValue(method, bean, convertResult);
                  return new QResult(new DataValue(value), QResult.ResultType.RETURN);
              }
              if (params.length < 1) {
                  throw createMethodNotFoundException(type);
              }
              if (((MetaClass)bean).getClz() != params[0].getClass()) {
                  throw createMethodNotFoundException(type);
              }
              Class<?>[] restParamsType = Arrays.copyOfRange(type, 1, type.length);
              method = reflectLoader.loadMethod(params[0], methodName, restParamsType);
              if (method == null) {
                  throw createMethodNotFoundException(restParamsType);
              }
              Object paramBean = params[0];
              Object[] restParams = Arrays.copyOfRange(params, 1, params.length);
              Object[] convertResult =
                  ParametersTypeConvertor.cast(restParams, method.getParameterTypes(), method.isVarArgs());
              Object value = MethodHandler.Access.accessMethodValue(method, paramBean, convertResult);
              return new QResult(new DataValue(value), QResult.ResultType.RETURN);
          }
          else {
              Class<?>[] type = BasicUtil.getTypeOfObject(params);
              IMethod method = reflectLoader.loadMethod(bean, methodName, type);
              if (method == null) {
                  throw createMethodNotFoundException(type);
              }
              Object[] convertResult =
                  ParametersTypeConvertor.cast(params, method.getParameterTypes(), method.isVarArgs());
              Object value = MethodHandler.Access.accessMethodValue(method, bean, convertResult);
              return new QResult(new DataValue(value), QResult.ResultType.RETURN);
          }
      }
      
      /**
       * Create method not found exception
       * @param type parameter type array
       * @return UserDefineException exception object
       */
      private UserDefineException createMethodNotFoundException(Class<?>[] type) {
          return new UserDefineException(UserDefineException.ExceptionType.INVALID_ARGUMENT,
              "method reference '" + methodName + "' not found for argument types " + Arrays.toString(type));
      }
  }
  