While learning java9 StringConcatFactory
class I am unable to understand why following code with MethodHandles.publicLookup()
throws StringConcatException
exception while if MethodHandles.lookup()
is used everything is working fine.
As per java docs of lookup:
"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
I am not sure where I am mistaken? Please help me understand this behavior.
The javadoc for makeConcat
says about the first parameter:
lookup Represents a lookup context with the accessibility privileges of the caller
The lookup context returned by publicLookup
does not have those privileges.
Even if you concatenate nothing, the exception will still be thrown:
MethodType concatType = MethodType.methodType(String.class); // No arguments, returns String
StringConcatFactory.makeConcat(MethodHandles.publicLookup(), "abc", concatType); // Exception
Because the access privileges of the context are checked in StringConcatFactory#doStringConcat
:
if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
throw new StringConcatException("Invalid caller: " +
lookup.lookupClass().getName());
}
The context needs a private lookup mode, and a publicLookup
does not have it:
System.out.println((MethodHandles.publicLookup().lookupModes()
& MethodHandles.Lookup.PRIVATE) != 0); // false
System.out.println((MethodHandles.lookup().lookupModes()
& MethodHandles.Lookup.PRIVATE) != 0); // true
The Javadoc for publicLookup()
says:
Returns a lookup object which is trusted minimally.
versus 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.
And the Javadoc for makeConcat()
finally says:
throws StringConcatException - If any of the linkage invariants described here are violated.
Given the fact that the question does not contain any more details, the most likely answer is: you have some sort of "permission" problem here. Maybe you try to "concat" something that simply isn't available when using "minimal trust".
The primary reason as in your case when a publicLookup
:
StringConcatFactory.makeConcat(MethodHandles.publicLookup(), "abc", MethodType.methodType(String.class));
can throw a StringConcatException
while on the other hand, the lookup
StringConcatFactory.makeConcat(MethodHandles.lookup(), "abc", MethodType.methodType(String.class));
would work fine is when the method handle created are used to access private members of a class of a private class of a package.
As stated in the Javadoc of publicLookup linked by @GhostCat as well
publicLookup => PUBLIC_LOOKUP => (PUBLIC|UNCONDITIONAL) modes
Returns a lookup object which is trusted minimally. The lookup has the
PUBLIC
andUNCONDITIONAL modes
. It can only be used to create method handles to public members of public classes in packages that are exported unconditionally.
while for a 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With