Java : AccessibleObject - API使用例

AccessibleObject (Java SE 18 & JDK 18) の使用例まとめです。
だいたいのメソッドを網羅済みです。
API仕様のおともにどうぞ。


概要

AccessibleObjectクラスは、Field、Method、およびConstructorオブジェクト(「リフレクトされたオブジェクト」と呼ばれる)の基本クラスです。 それは、Java言語のアクセス制御が使用されているときの抑制チェックとして、リフレクトされたオブジェクトにフラグを立てる機能を提供します。

クラス構成

AccessibleObject を使うと、例えば private なフィールドにも動的にアクセスできるようになります。

public class AccessTest {
    private int num = 100;
}
final var field = AccessTest.class.getDeclaredField("num");
final var obj = new AccessTest();

System.out.println(field.canAccess(obj)); // false
//field.getInt(obj); // IllegalAccessException

System.out.println(field.trySetAccessible()); // true
System.out.println(field.canAccess(obj)); // true

System.out.println(field.getInt(obj)); // 100

コンストラクタ

AccessibleObject ()

非推奨。

非推奨です。

メソッド

final boolean canAccess (Object obj)

呼び出し元がこのリフレクトされたオブジェクトにアクセスできるかどうかをテストします。

public class AccessTest {
    private int num = 100;
}
final AccessibleObject accessibleObject = AccessTest.class.getDeclaredField("num");
final var obj = new AccessTest();

System.out.println(accessibleObject.canAccess(obj)); // false
System.out.println(accessibleObject.trySetAccessible()); // true
System.out.println(accessibleObject.canAccess(obj)); // true

<T extends Annotation> T getAnnotation (Class<T> annotationClass)

存在する場合は、この要素の指定された型の注釈を返し、そうでない場合はnullを返します。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Foo {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Bar {
}

public class A {
    @Foo
    public int num;

    @Bar
    public void aaa() {
    }
}
final AccessibleObject field = A.class.getDeclaredField("num");
System.out.println(field); // public int A.num

System.out.println(field.isAnnotationPresent(Foo.class)); // true

final var ret1 = field.getAnnotation(Foo.class);
System.out.println(ret1.annotationType().getSimpleName()); // Foo

System.out.println(field.isAnnotationPresent(Bar.class)); // false

final var ret2 = field.getAnnotation(Bar.class);
System.out.println(ret2); // null
final AccessibleObject method = A.class.getDeclaredMethod("aaa");
System.out.println(method); // public void A.aaa()

System.out.println(method.isAnnotationPresent(Foo.class)); // false

final var ret1 = method.getAnnotation(Foo.class);
System.out.println(ret1); // null

System.out.println(method.isAnnotationPresent(Bar.class)); // true

final var ret2 = method.getAnnotation(Bar.class);
System.out.println(ret2.annotationType().getSimpleName()); // Bar

Annotation[] getAnnotations ()

この要素に存在する注釈を返します。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Foo {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Bar {
}

public class A {
    @Foo
    @Bar
    public int num;
}
final var accessibleObject = A.class.getDeclaredField("num");
System.out.println(accessibleObject);

System.out.println("-- annotations --");
for (final var a : accessibleObject.getAnnotations()) {
    System.out.println(a.annotationType().getSimpleName());
}

// 結果
// ↓
//public int A.num
//-- annotations --
//Foo
//Bar

<T extends Annotation> T[] getAnnotationsByType (Class<T> annotationClass)

この要素に関連付けられている注釈を返します。

@Repeatable(FooArray.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Foo {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FooArray {
    Foo[] value();
}

public class A {
    @Foo("a1")
    @Foo("a2")
    public int num;
}
final AccessibleObject accessibleObject = A.class.getDeclaredField("num");
System.out.println(accessibleObject);

System.out.println("-- annotations --");
for (final var a : accessibleObject.getAnnotationsByType(Foo.class)) {
    System.out.println(a.annotationType().getSimpleName() + " : " + a.value());
}

// 結果
// ↓
//public int A.num
//-- annotations --
//Foo : a1
//Foo : a2

<T extends Annotation> T getDeclaredAnnotation (Class<T> annotationClass)

直接存在する場合は、この要素の指定された型の注釈を返し、そうでない場合はnullを返します。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Foo {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Bar {
}

public class A {
    @Foo
    public int num;

    @Bar
    public void aaa() {
    }
}
final AccessibleObject field = A.class.getDeclaredField("num");
System.out.println(field); // public int A.num

final var ret1 = field.getDeclaredAnnotation(Foo.class);
System.out.println(ret1.annotationType().getSimpleName()); // Foo

final var ret2 = field.getDeclaredAnnotation(Bar.class);
System.out.println(ret2); // null
final AccessibleObject method = A.class.getDeclaredMethod("aaa");
System.out.println(method); // public void A.aaa()

final var ret1 = method.getDeclaredAnnotation(Foo.class);
System.out.println(ret1); // null

final var ret2 = method.getDeclaredAnnotation(Bar.class);
System.out.println(ret2.annotationType().getSimpleName()); // Bar

Annotation[] getDeclaredAnnotations ()

この要素に直接存在する注釈を返します。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Foo {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Bar {
}

public class A {
    @Foo
    @Bar
    public int num;
}
final var accessibleObject = A.class.getDeclaredField("num");
System.out.println(accessibleObject);

System.out.println("-- annotations --");
for (final var a : accessibleObject.getDeclaredAnnotations()) {
    System.out.println(a.annotationType().getSimpleName());
}

// 結果
// ↓
//public int A.num
//-- annotations --
//Foo
//Bar

<T extends Annotation> T[] getDeclaredAnnotationsByType (Class<T> annotationClass)

直接存在するか間接的に存在する場合は、この要素の指定された型の注釈を返します。

@Repeatable(FooArray.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Foo {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FooArray {
    Foo[] value();
}

public class A {
    @Foo("a1")
    @Foo("a2")
    public int num;
}
final AccessibleObject accessibleObject = A.class.getDeclaredField("num");
System.out.println(accessibleObject);

System.out.println("-- annotations --");
for (final var a : accessibleObject.getDeclaredAnnotationsByType(Foo.class)) {
    System.out.println(a.annotationType().getSimpleName() + " : " + a.value());
}

// 結果
// ↓
//public int A.num
//-- annotations --
//Foo : a1
//Foo : a2

boolean isAccessible ()

非推奨。 このメソッドは、Java言語のアクセス制御のチェックが抑制されているかどうかを実際に示しているときに、反映されたオブジェクトにアクセス可能かどうかを調べるというヒントを持つため、非推奨です。

非推奨です。

boolean isAnnotationPresent (Class<? extends Annotation> annotationClass)

指定された型の注釈がこの要素に存在する場合はtrueを返し、そうでない場合はfalseを返します。

このメソッドの使用例は、getAnnotation(Class<T> annotationClass) にまとめて記載しました。
そちらのAPI使用例をご参照ください。

void setAccessible (boolean flag)

このリフレクトされたオブジェクトのaccessibleフラグを、指定されたブール値に設定します。

public class AccessTest {
    private int num = 100;
}
final AccessibleObject accessibleObject = AccessTest.class.getDeclaredField("num");
final var obj = new AccessTest();

System.out.println(accessibleObject.canAccess(obj)); // false

accessibleObject.setAccessible(true);
System.out.println(accessibleObject.canAccess(obj)); // true

accessibleObject.setAccessible(false);
System.out.println(accessibleObject.canAccess(obj)); // false

static void setAccessible (AccessibleObject[] array, boolean flag)

単一のセキュリティ・チェック(効率化のため)でリフレクトされたオブジェクトの配列のaccessibleフラグを設定する便利なメソッド。

public class AccessTest2 {
    private int num = 100;
    private String str = "abcd";
}
final var cls = AccessTest2.class;

final AccessibleObject[] array = {
        cls.getDeclaredField("num"),
        cls.getDeclaredField("str")
};

System.out.println("-- AccessibleObject --");
for (final var accessibleObject : array) {
    System.out.println(accessibleObject);
}

final var obj = new AccessTest2();

System.out.println("-- canAccess --");
for (final var accessibleObject : array) {
    System.out.println(accessibleObject.canAccess(obj));
}

AccessibleObject.setAccessible(array, true);

System.out.println("-- canAccess --");
for (final var accessibleObject : array) {
    System.out.println(accessibleObject.canAccess(obj));
}

AccessibleObject.setAccessible(array, false);

System.out.println("-- canAccess --");
for (final var accessibleObject : array) {
    System.out.println(accessibleObject.canAccess(obj));
}

// 結果
// ↓
//-- AccessibleObject --
//private int AccessTest2.num
//private java.lang.String AccessTest2.str
//-- canAccess --
//false
//false
//-- canAccess --
//true
//true
//-- canAccess --
//false
//false

final boolean trySetAccessible ()

可能であれば、このリフレクトされたオブジェクトのaccessibleフラグをtrueに設定します。

このメソッドの使用例は、canAccess(Object obj) にまとめて記載しました。
そちらのAPI使用例をご参照ください。


関連記事

ページの先頭へ