Java 8 使用 lambda 访问私有成员?
Java 8 access private member with lambda?
Invoke private method with java.lang.invoke.MethodHandle gives an answer to private member access, while Java access bean methods with LambdaMetafactory 给出了基于 lambda 的成员访问的答案。但是,通过结合两者,我仍然找不到通过 lambda 访问私有成员的方法。错误:
Caused by: java.lang.IllegalAccessException: member is private: XXX from ZZZ
at java.lang.invoke.MethodHandles$Lookup.revealDirect(MethodHandles.java:1353)
at java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:131)
at java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:155)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:299)
指向 revealDirect which is part of metafactory 调用站点构建器。如何自定义构建器以控制其访问检查?
更新:Working Solution Option #3 per Holger
的例子
关键部分是传递给 LambdaMetafactory
的 Lookup
对象,然后调用 revealDirect
。
Security and access checks are performed to ensure that this lookup object is capable of reproducing the target method handle. This means that the cracking may fail if target is a direct method handle but was created by an unrelated lookup object.
因此,lambda 表达式只能访问包含 lambda 表达式的 class 可访问的方法,因为 JVM 提供的 Lookup
对象将准确反映这些访问权限。
这也适用于 Java Beans 方法,因为按照惯例这些方法是 public
。
因此,如果您想调用 private
方法,您有以下三种选择:
从有权访问它的 private
方法的声明 class 中生成 lambda 实例。当此 class 调用 MethodHandles.lookup()
时,它将获得适当的 Lookup
实例
A class 也可以创建这样一个具有所需功能的 Lookup
实例,并将其移交给另一个(受信任的)class,后者可以使用它来执行此类反射操作。这正是执行 invokedynamic
指令时隐式发生的情况。 class 包含指向 LambdaMetaFactory
中的 bootstrap 方法的 invokedynamic
指令意味着这种信任。
因此,使用所有普通操作,它总是 class 具有访问权限,必须为另一个 class
启用访问权限
- 从Java9开始,使用
MethodHandles.privateLookupIn(Class, MethodHandles.Lookup)
获取指定目标class上具有私有访问权限的方法句柄。这是根据模块访问规则检查的。对于同一模块内的访问,这应该总是成功的。
- 使用更多黑魔法来获得合适的
Lookup
实例。您链接的问题提到了非 public
Lookup.IMPL_LOOKUP
。如果您接触到此实例并调用 in(declaringClass)
on it, you get an instance with the desired properties. Alternatively you can create a restricted lookup object via MethodHandles.publicLookup()
.in(declaringClass)
and overwrite its access modifiers (the ones reported by lookupModes()
以启用完全访问权限。显然,两者都需要对不属于 public
Java API. 的字段进行访问覆盖
Invoke private method with java.lang.invoke.MethodHandle gives an answer to private member access, while Java access bean methods with LambdaMetafactory 给出了基于 lambda 的成员访问的答案。但是,通过结合两者,我仍然找不到通过 lambda 访问私有成员的方法。错误:
Caused by: java.lang.IllegalAccessException: member is private: XXX from ZZZ
at java.lang.invoke.MethodHandles$Lookup.revealDirect(MethodHandles.java:1353)
at java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:131)
at java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:155)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:299)
指向 revealDirect which is part of metafactory 调用站点构建器。如何自定义构建器以控制其访问检查?
更新:Working Solution Option #3 per Holger
的例子关键部分是传递给 LambdaMetafactory
的 Lookup
对象,然后调用 revealDirect
。
Security and access checks are performed to ensure that this lookup object is capable of reproducing the target method handle. This means that the cracking may fail if target is a direct method handle but was created by an unrelated lookup object.
因此,lambda 表达式只能访问包含 lambda 表达式的 class 可访问的方法,因为 JVM 提供的 Lookup
对象将准确反映这些访问权限。
这也适用于 Java Beans 方法,因为按照惯例这些方法是 public
。
因此,如果您想调用 private
方法,您有以下三种选择:
从有权访问它的
private
方法的声明 class 中生成 lambda 实例。当此 class 调用MethodHandles.lookup()
时,它将获得适当的Lookup
实例A class 也可以创建这样一个具有所需功能的
Lookup
实例,并将其移交给另一个(受信任的)class,后者可以使用它来执行此类反射操作。这正是执行invokedynamic
指令时隐式发生的情况。 class 包含指向LambdaMetaFactory
中的 bootstrap 方法的invokedynamic
指令意味着这种信任。因此,使用所有普通操作,它总是 class 具有访问权限,必须为另一个 class
启用访问权限
- 从Java9开始,使用
MethodHandles.privateLookupIn(Class, MethodHandles.Lookup)
获取指定目标class上具有私有访问权限的方法句柄。这是根据模块访问规则检查的。对于同一模块内的访问,这应该总是成功的。 - 使用更多黑魔法来获得合适的
Lookup
实例。您链接的问题提到了非public
Lookup.IMPL_LOOKUP
。如果您接触到此实例并调用in(declaringClass)
on it, you get an instance with the desired properties. Alternatively you can create a restricted lookup object viaMethodHandles.publicLookup()
.in(declaringClass)
and overwrite its access modifiers (the ones reported bylookupModes()
以启用完全访问权限。显然,两者都需要对不属于public
Java API. 的字段进行访问覆盖