質問

XML とリフレクションを使用して返すクラスがあります。 Object別のクラスに移動します。

通常、これらのオブジェクトは外部オブジェクトのサブフィールドですが、場合によっては、その場で生成したい場合もあります。このようなことを試しましたが、役に立ちませんでした。それはJavaがアクセスを許可していないためだと思います private 反省の方法。

Element node = outerNode.item(0);
String methodName = node.getAttribute("method");
String objectName = node.getAttribute("object");

if ("SomeObject".equals(objectName))
    object = someObject;
else
    object = this;

method = object.getClass().getMethod(methodName, (Class[]) null);

提供されたメソッドが private, 、で失敗します。 NoSuchMethodException. 。メソッドを作ることで解決できました public, 、または派生元の別のクラスを作成します。

簡単に言うと、私はただ、 private リフレクションによるメソッド。

役に立ちましたか?

解決

あなたは反射でプライベートメソッドを呼び出すことができます。投稿コードの最後のビットを変更します:

Method method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
Object r = method.invoke(object);

注意点がいくつかあります。まず、getDeclaredMethodは現在のClassで宣言されたメソッドは、スーパータイプから継承されないでしょう。必要であれば、具体的なクラス階層をトラバース。第二に、SecurityManagersetAccessibleメソッドの使用を防ぐことができます。だから、それは(PrivilegedActionまたはAccessControllerを使用して)Subjectとして実行する必要があります。

他のヒント

プライベートメソッドオブジェクトを取得し、実際にそれを呼び出すことができるようにgetDeclaredMethod()を使用するmethod.setAccessible()を使用してください。

は、この方法は、次のメソッドは、任意のクラスのプライベートメソッドを呼び出すために使用することができる非プリミティブデータタイプを受け入れる場合:

public static Object genericInvokeMethod(Object obj, String methodName,
            Object... params) {
        int paramCount = params.length;
        Method method;
        Object requiredObj = null;
        Class<?>[] classArray = new Class<?>[paramCount];
        for (int i = 0; i < paramCount; i++) {
            classArray[i] = params[i].getClass();
        }
        try {
            method = obj.getClass().getDeclaredMethod(methodName, classArray);
            method.setAccessible(true);
            requiredObj = method.invoke(obj, params);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return requiredObj;
    }

受け入れたパラメータは、OBJのmethodNameおよびパラメータです。たとえば、

public class Test {
private String concatString(String a, String b) {
    return (a+b);
}
}

方法concatStringは次のように呼び出すことができる

Test t = new Test();
    String str = (String) genericInvokeMethod(t, "concatString", "Hello", "Mr.x");

Spring の ReflectionTestUtils を使用してこれを行うことができます (org.springframework.test.util.ReflectionTestUtils)

ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument);

例 :プライベートメソッドを持つクラスがある場合 square(int x)

Calculator calculator = new Calculator();
ReflectionTestUtils.invokeMethod(calculator,"square",10);

私は反射を経由して実行保護されたメソッドの完全なコードを提供してみましょう。これは、ジェネリック医薬品、autoboxedのparamsとnull値を含むのparamsのいずれかの種類をサポートしています。

@SuppressWarnings("unchecked")
public static <T> T executeSuperMethod(Object instance, String methodName, Object... params) throws Exception {
    return executeMethod(instance.getClass().getSuperclass(), instance, methodName, params);
}

public static <T> T executeMethod(Object instance, String methodName, Object... params) throws Exception {
    return executeMethod(instance.getClass(), instance, methodName, params);
}

@SuppressWarnings("unchecked")
public static <T> T executeMethod(Class clazz, Object instance, String methodName, Object... params) throws Exception {

    Method[] allMethods = clazz.getDeclaredMethods();

    if (allMethods != null && allMethods.length > 0) {

        Class[] paramClasses = Arrays.stream(params).map(p -> p != null ? p.getClass() : null).toArray(Class[]::new);

        for (Method method : allMethods) {
            String currentMethodName = method.getName();
            if (!currentMethodName.equals(methodName)) {
                continue;
            }
            Type[] pTypes = method.getParameterTypes();
            if (pTypes.length == paramClasses.length) {
                boolean goodMethod = true;
                int i = 0;
                for (Type pType : pTypes) {
                    if (!ClassUtils.isAssignable(paramClasses[i++], (Class<?>) pType)) {
                        goodMethod = false;
                        break;
                    }
                }
                if (goodMethod) {
                    method.setAccessible(true);
                    return (T) method.invoke(instance, params);
                }
            }
        }

        throw new MethodNotFoundException("There are no methods found with name " + methodName + " and params " +
            Arrays.toString(paramClasses));
    }

    throw new MethodNotFoundException("There are no methods found with name " + methodName);
}

メソッドautoboxedのparamsの互換性をチェックするためにApache ClassUtilsを使用する

もう一つの変形は非常に強力なJOORライブラリを使用している https://github.com/jOOQ/jOOR

MyObject myObject = new MyObject()
on(myObject).get("privateField");  

これは、最終的な静的定数のような任意のフィールドを変更し、継承hierarhyに具象クラスを指定せずにYNE保護されたメソッドを呼び出すことができます。

<!-- https://mvnrepository.com/artifact/org.jooq/joor-java-8 -->
<dependency>
     <groupId>org.jooq</groupId>
     <artifactId>joor-java-8</artifactId>
     <version>0.9.7</version>
</dependency>

あなたは直接、タイプのための @Jailbreak マニホールドのに使用することができますJavaリフレクション-safeます:

@Jailbreak Foo foo = new Foo();
foo.callMe();

public class Foo {
    private void callMe();
}

@Jailbreakfooの階層内のすべてのメンバーに直接アクセスするためのコンパイラでFooローカル変数のロックを解除します。

同様に、あなたは一回限りの使用のための脱獄()の拡張メソッドを使用することができます

foo.jailbreak().callMe();

jailbreak()方法を通じて、あなたはFooの階層内の任意のメンバーにアクセスすることができます。

入力した、安全のために、公共の方法かのように、マニホールドはフードの下であなたのための効率的な反射のコードを生成しながら、

両方の場合において、コンパイラは、メソッド呼び出しを解決します。

タイプが静的に知られていない場合は、

あるいは、あなたは構造型付けを使用することができます型は、その実装を宣言しなくても満足させることができるインタフェースを定義します。この戦略は、型の安全性を維持し、反射やプロキシコードに関連するパフォーマンスとアイデンティティの問題を回避できます。

は、マニホールドの詳細を発見します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top