S_a_k_Uの日記みたいなDB

~サクゥーと呼ばないで~

継承されたprotecedなAccessibleObject(Filed, Method, Constructor)が取得できない、の回避策

昨日のやりたかったことの回避策。
継承元のクラスオブジェクトからgetDeclared*メソッドで取得すりゃえんじゃねん?とか。
ボードからの帰り道で思う浮かんだんで。
こんな感じで確認。
getDeclared*メソッドで取得しても、オーバーライドしてるメソッドはサブクラスのメソッドがちゃんと動いてる。

import java.io.Serializable;
import java.lang.reflect.Method;

public class ReflectTest implements Serializable {
    private static final long serialVersionUID = -1571667747937548537L;
    protected void writeX() {
        System.out.println("ReflectTest#writeX");
    }
    protected void writeY() {
        System.out.println("ReflectTest#writeY");
    }
    public static void main(String[] args) {
        new ReflectTest().test();
    }
    public void test() {
        try {
      // ReflectTestAはReflectTestを継承してる
            ReflectTestA testA = new ReflectTestA();
            // ReflectTestBはReflectTestを継承してないけど、同じメソッドを持っている
            ReflectTestB testB = new ReflectTestB();

            // ReflectTestクラスからwriteXメソッドを取得する
            Method writeXMethod = ReflectTest.class.getDeclaredMethod("writeX", (Class[]) null);
            // ReflectTestクラスからwriteXメソッドを取得する
            Method writeYMethod = ReflectTest.class.getDeclaredMethod("writeY", (Class[]) null);
            // ReflectTestのwriteXが呼ばれる
            writeXMethod.invoke(this, (Object[]) null);
            // ReflectTestのwriteYが呼ばれる
            writeYMethod.invoke(this, (Object[]) null);
            // ReflectTestAのwriteXが呼ばれる
            writeXMethod.invoke(testA, (Object[]) null);
            // ReflectTestのwriteYが呼ばれる(これで解決できるっぽい)
            writeYMethod.invoke(testA, (Object[]) null);
            // ReflectTestBは型が異なるため例外
            writeXMethod.invoke(testB, (Object[]) null);
            writeYMethod.invoke(testB, (Object[]) null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public class ReflectTestA extends ReflectTest {
        private static final long serialVersionUID = 5297693222741604495L;
        public ReflectTestA() {
            super();
        }
        protected void writeX() {
            System.out.println("ReflectTestA#writeX");
        }
    }
    public class ReflectTestB implements Serializable {
        private static final long serialVersionUID = -2721698177073421574L;
        public ReflectTestB() {
            super();
        }
        protected void writeX() {
            System.out.println("ReflectTestB#writeX");
        }
        protected void writeY() {
            System.out.println("ReflectTestB#writeY");
        }
    }
}

コンソールには下記のように出力される。

ReflectTest#writeX
ReflectTest#writeY
ReflectTestA#writeX
ReflectTest#writeY
java.lang.IllegalArgumentException: object is not an instance of declaring class
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at hogehoge.ReflectTest.test(ReflectTest.java:27)
	at hogehoge.ReflectTest.main(ReflectTest.java:15)