Invoke private method with java.lang.invoke.MethodHandle gives an answer to private member access, while Java access bean methods with LambdaMetafactory gives an answer to lambda based member access. However, by combining the two, I still can not find a way to access private members via lambda. The error:
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)
points to revealDirect which is part of metafactory call site builder. How can I customize the builder to control its access checks?
UPDATE: Example of Working Solution Option #3 per Holger
The critical part is the Lookup
object that is passed to the LambdaMetafactory
on which then revealDirect
is invoked.
From the documententation:
Security and access checks are performed to ensure that this lookup object is capable of reproducing the target method handle. This means that the cracking may fail if target is a direct method handle but was created by an unrelated lookup object.
As a consequence, lambda expression can only access methods accessible by the class containing the lambda expression as the JVM provided Lookup
object will reflect exactly these access permissions.
This also works for Java Beans methods as these are public
by convention.
So if you want to invoke private
methods you have three options:
Generate the lambda instance from within the declaring class of the private
method which has access to it. When this class calls MethodHandles.lookup()
it will get an appropriate Lookup
instance
A class may also create such a Lookup
instance with the desired capabilities and hand it over to another (trusted) class which may use it to perform such reflective operations. This is exactly what happens implicitly when an invokedynamic
instruction is executed. A class containing invokedynamic
instructions pointing to a bootstrap method within LambdaMetaFactory
implies such trust.
So using all-ordinary operations, its always the class having the access permissions which has to enable the access for another class
MethodHandles.privateLookupIn(Class, MethodHandles.Lookup)
to acquire a method handle with private access rights on the specified target class. This is checked against the module access rules. For access within the same module, this should always succeed.Lookup
instance. The question you have linked mentions the non-public
Lookup.IMPL_LOOKUP
. If you get hands on this instance and call in(declaringClass)
on it, you get an instance with the desired properties. Alternatively you can create a restricted lookup object via MethodHandles.publicLookup()
.in(declaringClass)
and overwrite its access modifiers (the ones reported by lookupModes()
to enable full access. Obviously, both require access override on fields that are not part of the public
Java API.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