天天看点

java泛型反射调用方法体内类型引用问题

自己在写自动化测试工具有关thrift服务自动化测试遇到的问题

首先给大家看一段代码

public static void test(List<Long> list){
        System.out.println(list.get(0));
        System.out.println(list.get(0) + 123);
        System.out.println(list.get(0).getClass());
    }

    public static void bugTest1(){
        String json = "[50004172,926513792]";
        for(Method m :ThriftGenUtils.class.getMethods()){
            if("test".equals(m.getName())){
                for(Class<?> pClass : m.getParameterTypes()){
                    Object argCasted = Json.strToObj(json, pClass);
                    try {
                        m.invoke(new ThriftGenUtils(),argCasted);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }

            }
        }

    }
           

运行bugTest1

问题:

1 argCasted具体类型为List,其中的泛型具体类型为什么类型?为什么?

2 invoke是否能成功?

3 若invoke成功了,list的泛型具体类型是什么类型?test是否可以成功运行?若不能成功运行,到哪一行出错?报什么错误?为什么?

答案:

1 Integer,m.getParameterTypes()获取到的泛型类型是不包括具体类型的,也就是Json.strToOb调用的时候pClass只是传了List,Json转换的时候只知道是数据类型,默认转成Integer,浮点数转为Double。

2 是

3 Integer,不能成功,到+123那一行报类型转换异常Integer不能转换为Long类型,原因是泛型类型擦除。(泛型类型擦除:http://blog.csdn.net/caihaijiang/article/details/6403349 )

目前的解决方案为获取到泛型类型及具体类型,通过ObjectMapper.getTypeFactory().constructParametricType(clazz,genericClazzes)来获取javaType再来转换成Object对象

改造后,实现的相关代码如下

Method method = null;
            List<Object> argList = new ArrayList<>();
            for (Method m : clientClazz.getMethods()){
                if(!methodName.equals(m.getName())){continue;}
                method = m;
                Type[] types = m.getGenericParameterTypes();
                Class[] classes = m.getParameterTypes();
                int i = 0;
                for ( Type c: types) {
                    int index = i++;
                    String arg = args[index];
                    if(!(c instanceof ParameterizedType)){
                        String jsonStr = Json.ObjToStr(arg);
                        argList.add(Json.strToObj(jsonStr,classes[index]));
                        continue;
                    }

                    ParameterizedType pt = (ParameterizedType) c;
                    ObjectMapper mapper = new ObjectMapper();
                    Class<?>[] genericClazzes = new Class<?>[pt.getActualTypeArguments().length];
                    int j = 0;
                    for(Type type : pt.getActualTypeArguments()){
                        genericClazzes[j ++] = (Class) type;
                    }
                    JavaType javaType = mapper.getTypeFactory().constructParametricType(classes[index],genericClazzes);
                    Object argCasted = mapper.readValue(arg,javaType);
                    argList.add(argCasted);

                }
                break;

            }
            if ( method != null){
                res = method.invoke(obj,argList.toArray());
            }