【问题标题】:Java 8 access private member with lambda?Java 8 使用 lambda 访问私有成员?
【发布时间】:2018-06-13 15:08:29
【问题描述】:

Invoke private method with java.lang.invoke.MethodHandle 给出了私有成员访问的答案,而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,它是metafactory 呼叫站点构建器的一部分。如何自定义构建器以控制其访问检查?

更新:Working Solution Option #3 per Holger 的示例

【问题讨论】:

  • 您应该提供引发异常的具体代码。一般来说,如果事实证明您可以自定义 lambda 行为的任何方面,我会感到惊讶。 lambda 语法的语义受 JLS 中的精确规范的约束。

标签: java lambda java-8


【解决方案1】:

关键部分是传递给LambdaMetafactory 的Lookup 对象,然后在该对象上调用revealDirect。

来自documententation:

执行安全和访问检查以确保此查找对象能够再现目标方法句柄。这意味着如果目标是直接方法句柄但由不相关的查找对象创建,则破解可能会失败。

因此,lambda 表达式只能访问包含 lambda 表达式的类可访问的方法,因为 JVM 提供的 Lookup 对象将准确反映这些访问权限。

这也适用于 Java Bean 方法,因为这些方法按照约定是 public。


所以如果你想调用private 方法,你有三个选择:

  • 从可以访问它的private 方法的声明类中生成 lambda 实例。当这个类调用MethodHandles.lookup() 时,它会得到一个合适的Lookup 实例

    一个类也可以创建一个具有所需功能的Lookup 实例,并将其交给另一个(受信任的)类,该类可以使用它来执行此类反射操作。这正是执行invokedynamic 指令时隐含的情况。包含指向LambdaMetaFactory 内的引导方法的invokedynamic 指令的类意味着这种信任。

    所以使用所有普通操作,它总是具有访问权限的类必须启用另一个类的访问权限

  • 从 Java 9 开始,使用 MethodHandles.privateLookupIn(Class, MethodHandles.Lookup) 获取对指定目标类具有私有访问权限的方法句柄。这是根据模块访问规则进行检查的。对于同一模块内的访问,这应该总是成功的。
  • 使用更多的黑魔法来获得合适的Lookup 实例。您链接的问题提到了非publicLookup.IMPL_LOOKUP。如果您获得此实例并在其上调用in(declaringClass),您将获得一个具有所需属性的实例。或者,您可以通过 MethodHandles.publicLookup() .in(declaringClass) 创建受限查找对象并覆盖其访问修饰符(lookupModes() 报告的访问修饰符以启用完全访问权限。显然,两者都需要对不属于 public 的字段进行访问覆盖Java API。

【讨论】:

  • 感谢@holger 的指点。我们无法控制目标类,因此您的选项 1 不适用。选项 2 效果很好,在此转载:PrivateTargetLambda.java 你认为有办法避免“黑魔法”还是选项 2 是最终答案?
猜你喜欢
  • 1970-01-01
  • 2012-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多