天天看點

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());
            }