LambdaMetafactory 访问不同 ClassLoader 上的类

Geo*_*met 5 java lambda methodhandle lambda-metafactory

我有这段代码可以正常工作:

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();
Run Code Online (Sandbox Code Playgroud)

但是,如果该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)
Run Code Online (Sandbox Code Playgroud)

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

Hol*_*ger 6

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

\n\n

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

\n\n

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

\n