3

我有这个工作正常的代码:

Method getterMethod = Person.class.getDeclaredMethod("getName");

MethodHandles.Lookup lookup = MethodHandles.publicLookup();
Class<?> declaringClass = getterMethod.getDeclaringClass();
Class<?> returnType = getterMethod.getReturnType();
CallSite getterSite = LambdaMetafactory.metafactory(lookup,
    "apply",
    MethodType.methodType(Function.class),
    MethodType.methodType(Object.class, Object.class),
    lookup.findVirtual(declaringClass, getterMethod.getName(), MethodType.methodType(returnType)),
    MethodType.methodType(propertyType, declaringClass));

Function getterFunction = (Function) getterSite.getTarget().invokeExact();

但是如果getterMethod是从不同的 ClassLoader 加载的类的方法,它会抛出:

Caused by: java.lang.invoke.LambdaConversionException: Invalid caller: java.lang.Object
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:118)
    at java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:155)
    at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:299)

如何将我的ClassLoader实例传递给LambdaMetafactory?

4

2 回答 2

4

正如这个答案所说,查找模式必须包括要接受的私有访问LambdaMetaFactory。基本上,这意味着调用者指定的类,因为它创建了特定的查找实例,或者查找类有足够的信任将查找对象传递给进行实际调用的代码(例如,在使用invokedynamic指向时暗示到特定的引导方法)。

从 Java 9 开始,有一种方法privateLookupIn(Class, MethodHandles.Lookup)可以尝试获取可以private访问另一个类的查找对象。正如文档所指定的,访问是根据模块访问规则检查的,即调用者必须“允许对目标类进行深度反射”。因此,就模块可访问性而言,仍然需要上述信任的存在。我想,这就是框架的方式,由框架管理的代码将向框架开放以支持这种访问。

如果这不可行,则此答案包含替代方法,以防您是类加载器的创建者。它使用类加载器的 API 来注入一个新类,该类创建查找对象并允许创建者访问它。有一些可以想象的变化,包括通过让合成类回调到创建者的代码以交出查找对象来使其安全,而不是将其存储在每个人都可以阅读的字段中。

于 2018-06-11T17:39:54.563 回答
3

LambdaMetafactory的方法要求您将PRIVATE查找作为其第一个参数传递。规范caller - Represents a lookup context with the accessibility privileges of the caller.可能有点晦涩,但它应该给出有关Lookup.

为什么它必须是私有的?这有点像 API 的未来证明。请记住,LambdaMetafactory它应该invokedynamic通过编译器为 lambdas 生成的指令来调用。在这种情况下,VM 将始终将调用者的传递MethodHandles.lookup()给方法,因此Lookup将始终是PRIVATE. 如果您的用LambdaMetafactory例需要它,直接在 Java 代码中使用是非常好的,但这不是主要用途,因此 API 仅限于提供足够的用invokedynamic例,但仅此而已(换句话说 - 如果invokedynamic可以使用,PRIVATE那么让我们禁止一切以防万一)。

于 2018-02-04T12:12:10.763 回答