Java 8访问lambda的私有成员?

时间:2015-01-28 03:21:30

标签: java lambda java-8

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 #3Holger

的示例

1 个答案:

答案 0 :(得分:9)

关键部分是传递给Lookup的{​​{1}}对象,然后调用LambdaMetafactory

来自documententation

  

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

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

这也适用于Java Beans方法,因为它们按惯例为Lookup


因此,如果您想调用public方法,您有三种选择:

  • private方法的声明类中生成lambda实例,该方法可以访问它。当此类调用MethodHandles.lookup()时,它将获得适当的private实例

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

    因此,使用所有普通操作,它始终是具有访问权限的类,必须启用对另一个类的访问

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