前端传参到后端反射类的方法调用? ?

我想从前端传一个完整的类的方法信息到后台, 然后让后端可以直接反射调用

目前是这样设计的, 传的参数结构大概是这样子

classloaderName : 类加载器名称
className: 类名称
methodName : 方法名

params: 参数列表 List

参数结构为: 
type: 参数类型 String
name: 参数名称 String
value : 参数值 jsonString , 当是普通类型时为 {"value": 参数值} , 复杂类型时为 {"value": 参数JSON}

但现在遇到的问题是

  1. 泛型怎么传到后端
  2. 后端对于普通类型的转换问题

目前我的核心代码如下

/**
     * 调用上传类的方法
     * @param invokeMethodRequest
     * @return
     * @throws ClassNotFoundException
     */
    public InvokeMethodResponse invokeMethod(InvokeMethodRequest invokeMethodRequest) throws ClassNotFoundException {
        final ClassLoader classloader = classloaderService.getClassloader(invokeMethodRequest.getClassloaderName());

        // 查找方法信息
        List<Class<?>> paramTypes = new ArrayList<>();
        for (InvokeMethodRequest.MethodParam param : invokeMethodRequest.getParams()) {
            final String paramType = param.getParamType();
            final Class<?> type = TypeSupport.getType(paramType, classloader);
            paramTypes.add(type);
        }

        final Class<?> invokeClass = classloader.loadClass(invokeMethodRequest.getClassName());
        final Method method = ReflectionUtils.findMethod(invokeClass, invokeMethodRequest.getMethodName(), paramTypes.toArray(new Class<?>[0]));
        if (method == null){
            final String paramTypeSimpleNames = paramTypes.stream().map(Class::getSimpleName).collect(Collectors.joining(","));
            log.error("类[{}]调用方法[{}],参数类型列表[{}], 未找到方法",invokeClass.getSimpleName(),invokeMethodRequest.getMethodName(), paramTypeSimpleNames);
            throw new ToolException("调用方法 "+ invokeMethodRequest.getMethodName()+ " 不存在");
        }

        // 组装参数信息
        Object[] paramValues = new Object[invokeMethodRequest.getParams().size()];
        for (int i = 0; i < invokeMethodRequest.getParams().size(); i++) {
            InvokeMethodRequest.MethodParam param = invokeMethodRequest.getParams().get(i);
            final String paramType = param.getParamType();
            final String paramValueJson = param.getParamValueJson();
            final JSONObject jsonObject = JSON.parseObject(paramValueJson);

            final Class<?> paramTypeClass = TypeSupport.getType(paramType,classloader);
            if (ClassUtils.isPrimitiveOrWrapper(paramTypeClass)){
//                paramValues[i] = jsonObject.get("value");
                paramValues[i] = Long.parseLong((String) jsonObject.get("value"));
            }else if (paramTypeClass == String.class  || paramTypeClass == BigDecimal.class){
                paramValues[i] = jsonObject.get("value");
            }else if (paramTypeClass == Date.class){
                paramValues[i] = jsonObject.getDate("value");
            }else {
                if (paramTypeClass == List.class){
//                    paramValues[i] = .toJavaObject(paramTypeClass);
                    List list  = new ArrayList<>();
                    paramValues[i] = list;

                    final JSONArray value = jsonObject.getJSONArray("value");
                    for (int j = 0; j < value.size(); j++) {
                        list.add(value.get(j));
                    }
                }else {
                    paramValues[i] = jsonObject.getJSONObject("value").toJavaObject(paramTypeClass);
                }
            }
        }

        // 发起调用
        long startTime = System.currentTimeMillis();
        final Object o = ReflectUtils.newInstance(invokeClass);
        final Object invokeResult = ReflectionUtils.invokeMethod(method, o, paramValues);
        long spendTime = System.currentTimeMillis() - startTime;
        log.info("[{}]方法调用耗时[{}ms]",method.getName(),spendTime);

        final Class<?> returnType = method.getReturnType();
        InvokeMethodRequest.MethodParam result = null;
        if (returnType == Void.class){
            result = new InvokeMethodRequest.MethodParam(returnType.getName());
        }else {
            result = new InvokeMethodRequest.MethodParam(returnType.getName(),JSON.toJSONString(invokeResult));
        }

        final InvokeMethodResponse invokeMethodResponse = new InvokeMethodResponse(spendTime,result);
        return invokeMethodResponse;
    }

InvokeMethodRequest


@Data
public class InvokeMethodRequest {
    private String classloaderName;
    @NotBlank
    private String className;
    @NotBlank
    private String methodName;
    private List<MethodParam> params = new ArrayList<>();

    @Data
    public static final class MethodParam{
        /**
         * 参数名称, 可以为空
         */
        private String paramName;

        /**
         * 参数类型
         */
        private String paramType;
        /**
         * 参数值 json 串
         * {"value": 参数数据}
         */
        private String paramValueJson;

        public MethodParam() {
        }

        public MethodParam(String paramType) {
            this.paramType = paramType;
        }

        public MethodParam(String paramType, String paramValueJson) {
            this.paramType = paramType;
            this.paramValueJson = paramValueJson;
        }

        public MethodParam(String paramName, String paramType, String paramValueJson) {
            this.paramName = paramName;
            this.paramType = paramType;
            this.paramValueJson = paramValueJson;
        }
    }
}
阅读 1.7k
1 个回答

1、泛型以数组形式使用其它参数另外传递
用 jackson 处理,以 Map<String, Integer> 为例

    public static void main(String[] args) throws JsonProcessingException, ClassNotFoundException {
        Class mainClass = Class.forName("java.util.Map");
        // 泛型部分,组装成数组
        Class g1 = Class.forName("java.lang.String");
        Class g2 = Class.forName("java.lang.Integer");

        JavaType javaType = TypeFactory.defaultInstance().constructParametricType(mainClass, g1, g2);
        ObjectMapper objectMapper = new ObjectMapper();

        String json = "{\"xxx\":123,\"yyy\":345}";

        Object value = objectMapper.readValue(json, javaType);
        System.out.println(value);
    }

2、多层嵌套 Map<String, List<String>>

    public static void main(String[] args) throws JsonProcessingException, ClassNotFoundException {
        Class mainClass = Class.forName("java.util.Map");
        Class g1 = Class.forName("java.lang.String");

        Class listClass = Class.forName("java.util.List");
        Class listClassG1 = Class.forName("java.lang.String");

        JavaType type = TypeFactory.defaultInstance().constructParametricType(listClass, listClassG1);

        JavaType javaType = TypeFactory.defaultInstance().constructParametricType(mainClass, g1, type.getRawClass());
        ObjectMapper objectMapper = new ObjectMapper();

        String json = "{\"xxx\":[\"123\"],\"yyy\":[\"456\"]}";

        Object value = objectMapper.readValue(json, javaType);
        System.out.println(value);
    }

3、普通类型另做判断
例如

if (type == "java.lang.String") {
    // code
}

4、直接使用的标准答案

public class Test {

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String classInfo = "{\n" +
                "    \"className\":\"java.util.Map\",\n" +
                "    \"genericClass\":[\n" +
                "        {\n" +
                "            \"className\":\"java.lang.String\"\n" +
                "        },\n" +
                "        {\n" +
                "            \"className\":\"java.util.List\",\n" +
                "            \"genericClass\":[\n" +
                "                {\n" +
                "                    \"className\":\"java.lang.String\"\n" +
                "                }\n" +
                "            ]\n" +
                "        }\n" +
                "    ]\n" +
                "}";

        NestClass nestClass = objectMapper.readValue(classInfo, NestClass.class);
        JavaType javaType = nestClass.toClass();
        System.out.println(javaType);

        String json = "{\"456\":[\"789\"]}";

        Object value = objectMapper.readValue(json, javaType);
        System.out.println(value);
    }

    static class NestClass {
        private String className;
        private List<NestClass> genericClass;

        public JavaType toClass() {
            Class<?> mainClass;
            try {
                mainClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            if (genericClass != null && genericClass.size() != 0) {
                List<JavaType> collect = genericClass.stream().map(NestClass::toClass).collect(Collectors.toList());
                return TypeFactory.defaultInstance().constructParametricType(mainClass, collect.toArray(new JavaType[]{}));
            }
            return TypeFactory.defaultInstance().constructType(mainClass);
        }

        public void setClassName(String className) {
            this.className = className;
        }

        public void setGenericClass(List<NestClass> genericClass) {
            this.genericClass = genericClass;
        }
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题