JavaのリフレクションAPIでフィールド取得

JavaのリフレクションAPIでフィールドの取得を試してみたメモです。

前回の続きで、JavaのリフレクションAPIを利用して、フィールドの取得を試してみました。

java.lang.reflect.Field

JavaのリフレクションAPIを利用することで、メタデータにアクセスできます。
java.lang.reflect.Fieldクラスを利用してフィールドの取得を試したいと思います。

テスト用クラス

Mavenプロジェクトを作成し、pom.xmljunitとhamcrestだけdependencyに追加しました。

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit-dep</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

テスト対象のクラスは下記のようなクラスを作りました。

ReflectFieldExample.java

package reflect;

public class ReflectFieldExample {
    public String pub = "public";
    protected String pro = "protected";
    String def = "default";
    private String pri = "private";

    String name;

    public ReflectFieldExample() {
        this("no args");
    }

    public ReflectFieldExample(String name) {
        this.name = name;
    }
}

public、protected、修飾子なし、private
のアクセス修飾子でそれぞれフィールドを定義しました。

Fieldオブジェクト

Fieldオブジェクトを取得するためのメソッドは下記です。
すべてClassクラスのメソッドです。

メソッド 戻り値 取得可能なアクセス修飾子
getField Field public
getFields Field[] public
getDeclaredField Field すべて
getDeclaredFields Field[] すべて
getField()

getField()では、自クラスまたはインターフェースのフィールドが取得できます。
取得できるのはpublicフィールドのみです。
引数にはフィールド名の文字列を指定します。

    Field field = ReflectFieldExample.class.getField("pub");

privateフィールドは取得できません。

    // エラー
    Field field = ReflectFieldExample.class.getField("pri");

テストコード。

    public static class getFieldの確認 {
        @Test
        public void getTypeでpublicフィールドの型が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            Class type = field.getType();
            assertThat(type, is(equalTo(String.class)));
        }

        @Test(expected = java.lang.NoSuchFieldException.class)
        public void getTypeでprotectedフィールドの型が取得できないこと() throws Exception {
            Field field = ReflectFieldExample.class.getField("pro");
        }

        @Test(expected = java.lang.NoSuchFieldException.class)
        public void getTypeでdefaultフィールドの型が取得できないこと() throws Exception {
            Field field = ReflectFieldExample.class.getField("def");
        }

        @Test(expected = java.lang.NoSuchFieldException.class)
        public void getTypeでprivateフィールドの型が取得できないこと() throws Exception {
            Field field = ReflectFieldExample.class.getField("pri");
        }
    }
getFields()

getFields()では、自クラスまたはインターフェースのフィールドがFieldクラスの配列で取得できます。
取得できるのはpublicフィールドのみです。

テストコード。

    public static class getFieldsの確認 {
        @Test
        public void getFieldsでフィールドオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectFieldExample.class;
            Field[] fields = clazz.getFields();
            Field[] expected = {
                    clazz.getField("pub")
            };
            assertThat(fields, is(arrayContainingInAnyOrder(expected)));
        }
    }
getDeclaredField()

getDeclaredField()では、getFieldと同様にフィールドが取得できますが、
すべてのアクセス修飾子(public、protected、デフォルト、private)のフィールドが取得できます。

    // publicフィールド
    Field field = ReflectFieldExample.class.getDeclaredField("pub");

    // protectedフィールド
    Field field = ReflectFieldExample.class.getDeclaredField("pro");

    // defaultフィールド
    Field field = ReflectFieldExample.class.getDeclaredField("def");

    // privateフィールド
    Field field = ReflectFieldExample.class.getDeclaredField("pri");

テストコード。

    public static class getDeclaredFieldの確認 {
        @Test
        public void getModifiersでpublicフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("pub");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test
        public void getModifiersでprotectedフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("pro");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PROTECTED));
        }

        @Test
        public void getModifiersでdefaultフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("def");
            int mod = field.getModifiers();
            assertThat(mod, is(0));
        }

        @Test
        public void getModifiersでprivateフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("pri");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PRIVATE));
        }
    }
getDeclaredFields()

getDeclaredFields()では、getFields同様にFieldクラスの配列で取得できますが、
getFields()と異なり、すべてのアクセス修飾子(public、protected、デフォルト、private)のフィールドが取得できます。

テストコード。

    public static class getDeclaredFieldsの確認 {
        @Test
        public void getDeclaredFieldsでフィールドオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectFieldExample.class;
            Field[] fields = clazz.getDeclaredFields();
            Field[] expected = {
                    clazz.getDeclaredField("pub"),
                    clazz.getDeclaredField("pro"),
                    clazz.getDeclaredField("def"),
                    clazz.getDeclaredField("pri"),
                    clazz.getDeclaredField("name")
            };
            assertThat(fields, is(arrayContainingInAnyOrder(expected)));
        }
    }

Fieldクラス

フィールド情報取得

Fieldクラスのメソッドを利用してフィールドの情報が取得できます。

    Field field = ReflectFieldExample.class.getField("pub");
    // フィールド名取得
    String name = field.getName();

    // フィールドのアクセス修飾子取得
    int mod = field.getModifiers();

    // フィールドを表す文字列を取得
    String generic = field.toGenericString();

テストコード。

    public static class Fieldクラスでフィールド情報取得 {
        @Test
        public void getNameでフィールドの名前が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            String name = field.getName();
            assertThat(name, is("pub"));
        }

        @Test
        public void getModifiersでフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test
        public void toGenericStringでフィールドを表す文字列が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            String generic = field.toGenericString();
            assertThat(generic, is("public java.lang.String reflect.ReflectFieldExample.pub"));
        }
    }

テストコード

今回のテストコードの全体です。

ReflectFieldExampleTest.java

package reflect;

import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.junit.Assert.*;

/**
 * Created by pppurple on 2016/07/23.
 */
@RunWith(Enclosed.class)
public class ReflectFieldExampleTest {
    public static class getFieldの確認 {
        @Test
        public void getTypeでpublicフィールドの型が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            Class type = field.getType();
            assertThat(type, is(equalTo(String.class)));
        }

        @Test(expected = java.lang.NoSuchFieldException.class)
        public void getTypeでprotectedフィールドの型が取得できないこと() throws Exception {
            Field field = ReflectFieldExample.class.getField("pro");
        }

        @Test(expected = java.lang.NoSuchFieldException.class)
        public void getTypeでdefaultフィールドの型が取得できないこと() throws Exception {
            Field field = ReflectFieldExample.class.getField("def");
        }

        @Test(expected = java.lang.NoSuchFieldException.class)
        public void getTypeでprivateフィールドの型が取得できないこと() throws Exception {
            Field field = ReflectFieldExample.class.getField("pri");
        }
    }

    public static class getFieldsの確認 {
        @Test
        public void getFieldsでフィールドオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectFieldExample.class;
            Field[] fields = clazz.getFields();
            Field[] expected = {
                    clazz.getField("pub")
            };
            assertThat(fields, is(arrayContainingInAnyOrder(expected)));
        }
    }

    public static class getDeclaredFieldの確認 {
        @Test
        public void getModifiersでpublicフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("pub");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test
        public void getModifiersでprotectedフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("pro");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PROTECTED));
        }

        @Test
        public void getModifiersでdefaultフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("def");
            int mod = field.getModifiers();
            assertThat(mod, is(0));
        }

        @Test
        public void getModifiersでprivateフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getDeclaredField("pri");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PRIVATE));
        }
    }

    public static class getDeclaredFieldsの確認 {
        @Test
        public void getDeclaredFieldsでフィールドオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectFieldExample.class;
            Field[] fields = clazz.getDeclaredFields();
            Field[] expected = {
                    clazz.getDeclaredField("pub"),
                    clazz.getDeclaredField("pro"),
                    clazz.getDeclaredField("def"),
                    clazz.getDeclaredField("pri"),
                    clazz.getDeclaredField("name")
            };
            assertThat(fields, is(arrayContainingInAnyOrder(expected)));
        }
    }

    public static class Fieldクラスでフィールド情報取得 {
        @Test
        public void getNameでフィールドの名前が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            String name = field.getName();
            assertThat(name, is("pub"));
        }

        @Test
        public void getModifiersでフィールドのアクセス修飾子が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            int mod = field.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test
        public void toGenericStringでフィールドを表す文字列が取得できること() throws Exception {
            Field field = ReflectFieldExample.class.getField("pub");
            String generic = field.toGenericString();
            assertThat(generic, is("public java.lang.String reflect.ReflectFieldExample.pub"));
        }
    }
}

ソースはあげておきました。
github.com

終わり。