StringConcatFactory 异常 - Java 9

Exception in StringConcatFactory - Java 9

在学习 java9 StringConcatFactory class 时,我无法理解为什么使用 MethodHandles.publicLookup() 的代码会抛出 StringConcatException 异常,而如果 MethodHandles.lookup()使用一切正常。

根据 java 查找文档:

"lookup - Represents a lookup context with the accessibility privileges of the caller"

StringConcatFactory.makeConcat(MethodHandles.publicLookup(),
"abc",MethodType.methodType(String.class));//Exception Here


StringConcatFactory.makeConcat(MethodHandles.lookup(), 
"abc", MethodType.methodType(String.class)); //Working fine

不知道我哪里弄错了?请帮助我理解这种行为。

publicLookup() 的 Javadoc 说:

Returns a lookup object which is trusted minimally.

对比lookup()

Returns a lookup object with full capabilities to emulate all supported bytecode behaviors of the caller. These capabilities include private access to the caller. Factory methods on the lookup object can create direct method handles for any member that the caller has access to via bytecodes, including protected and private fields and methods. This lookup object is a capability which may be delegated to trusted agents.

makeConcat() 的 Javadoc 最后说:

throws StringConcatException - If any of the linkage invariants described here are violated.

鉴于问题 包含任何更多细节,最有可能的答案是:您在这里遇到了某种 "permission" 问题。也许您尝试 "concat" 一些在使用 "minimal trust".

时根本不可用的东西

makeConcat 的 javadoc 说第一个参数:

lookup Represents a lookup context with the accessibility privileges of the caller

publicLookup 返回的查找上下文没有这些权限。

即使你不连接任何东西,仍然会抛出异常:

MethodType concatType = MethodType.methodType(String.class); // No arguments, returns String
StringConcatFactory.makeConcat(MethodHandles.publicLookup(), "abc", concatType); // Exception

因为上下文的访问权限是在StringConcatFactory#doStringConcat中检查的:

if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
    throw new StringConcatException("Invalid caller: " +
            lookup.lookupClass().getName());
}

上下文需要私有查找模式,publicLookup没有:

System.out.println((MethodHandles.publicLookup().lookupModes()
    & MethodHandles.Lookup.PRIVATE) != 0); // false
System.out.println((MethodHandles.lookup().lookupModes()
    & MethodHandles.Lookup.PRIVATE) != 0); // true

你的情况下 publicLookup 的主要原因:

StringConcatFactory.makeConcat(MethodHandles.publicLookup(), "abc", MethodType.methodType(String.class));

可以抛出 StringConcatException 而另一方面, lookup

StringConcatFactory.makeConcat(MethodHandles.lookup(), "abc", MethodType.methodType(String.class));

当创建的方法句柄用于访问包的私有 class 的 class 的私有成员时可以正常工作。

如@GhostCat 链接的 Javadoc of publicLookup 中所述

publicLookup => PUBLIC_LOOKUP => (PUBLIC|UNCONDITIONAL) modes

Returns a lookup object which is trusted minimally. The lookup has the PUBLIC and UNCONDITIONAL modes. It can only be used to create method handles to public members of public classes in packages that are exported unconditionally.

lookup

lookup => (lookupClass => Reflection.getCallerClass, FULL_POWER_MODES  => (ALL_MODES & ~UNCONDITIONAL))

Returns a lookup object with full capabilities to emulate all supported bytecode behaviors of the caller. These capabilities include private access to the caller. Factory methods on the lookup object can create direct method handles for any member that the caller has access to via bytecodes, including protected and private fields and methods. This lookup object is a capability which may be delegated to trusted agents.

Do not store it in place where untrusted code can access it. This method is caller sensitive, which means that it may return different values to different callers.

For any given caller class C, the lookup object returned by this call has equivalent capabilities to any lookup object supplied by the JVM to the bootstrap method of an invokedynamic instruction executing in the same caller class C.