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
コンストラクタ
メソッド
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使用例をご参照ください。