5

後方互換性テストのために、以前のバージョンからコードの一部をロードするための独自のクラスローダーを作成しています。(古いカスタムクラスからの)カスタムオブジェクトを取得した後、リフレクションを使用してそのAPIを呼び出しています。ただし、そのようなAPIメソッドにカスタム引数がある場合(Javaライブラリの一部ではない場合)、たとえば次のようになります。

public void MyMethod(MyObj a) {}

リフレクションを使用してこのメ​​ソッドを呼び出すと、次のようになります。

java.lang.IllegalArgumentException:引数タイプの不一致

メソッドがカスタムクラスローダーからMyObjを取得することを期待しているのに、デフォルトのクラスローダーからMyObjを渡しているためです。

メソッドを呼び出すために使用しているコード(エージェントがカスタムクラスローダーによってロードされ、エージェントのapiメソッドへの引数がデフォルトのクラスローダーによってロードされたテストクラスから到着した場合)

        private Object invoke(Object... args) {
            try {
                final String methodName = getMethodName();
                final Class<?>[] methodArgs = getMethodArgs(methodName);
                return agent.getClass().getMethod(methodName, methodArgs).invoke(agent, args);

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }

        private Class<?>[] getMethodArgs(String methodName) {
            final Method[] declaredMethods = agent.getClass().getDeclaredMethods();
            for (Method method : declaredMethods) {
                if (method.getName().equals(methodName)) {
                    return method.getParameterTypes();
                }
            }
            return new Class<?>[0];
        }

        private String getMethodName() {
            StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
            StackTraceElement e = stacktrace[3];
            return e.getMethodName();
        }

この問題を回避するにはどうすればよいですか?(myCustomObjectは共有モジュールに存在するインターフェースを実装していないため、メソッドに共通インターフェースを渡すことができません。また、古いjarがそれを認識しないため、今は追加できません)

4

1 に答える 1

2

カスタムクラスローダーを使用して、MyObjを拡張するクラス「DefaultCtorMyObjWrapper」をロードできます(カスタムクラスローダーによってロードされます)。DefaultCtorMyObjWrapperは、デフォルトのコンストラクターによってロードされた「MyObj」のインスタンスをラップします(参照はオブジェクトとして保持する必要があります)。DefaultCtorMyObjWrapperは、MyObjのすべてのメソッドをオーバーライドし、リフレクションを使用して呼び出しをラップされたMyObjに委任します。

このように見えるはずです:

class DefaultCtorMyObjWrapper{

    Object _defaultCtorMyObj;

    public DefaultCtorMyObjWrapper(Object defaultCtorMyObj){
        _defaultCtorMyObj = defaultCtorMyObj;
    }   

    public method1(){
        // invoke method1 on _defaultCtorMyObj using reflcetion
    }

}

MyObjのメソッドがオブジェクトをパラメーターとして受け取る場合は、さらに微調整が必​​要になる場合があります。

于 2013-03-10T10:45:46.500 に答える