-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8280377: MethodHandleProxies does not correctly invoke default methods with varags #7185
Conversation
👋 Welcome back mchung! A progress list of the required criteria for merging this PR into |
Webrevs
|
Will older versions up to Java 8 get an alternative fix (changing the accessed handle to non-vararg) too? This API is currently the most backward-compatible way to create a proper (as in calling default methods as desired) interface proxy in Java 8 or 11. |
This is up to the update release maintainers to decide. The backport fix is straight-forward. I include that in the JBS report. |
@mlchung This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 46 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
When testing this patch from a named module and not-exported package, I get the following exception:
My test code. |
@DasBrain thanks for catching this. The patch is updated. |
@@ -202,7 +202,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl | |||
if (isObjectMethod(method)) | |||
return callObjectMethod(proxy, method, args); | |||
if (isDefaultMethod(method)) { | |||
return callDefaultMethod(defaultMethodMap, proxy, intfc, method, args); | |||
// no additional access check is performed | |||
return JLRA.invokeDefault(proxy, method, null, args); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the argument order ..., args, caller
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such edit was an accident. Fixed.
|
||
public Object invokeDefault(Object proxy, Method method, Object[] args, Class<?> caller) | ||
throws Throwable { | ||
return Proxy.invokeDefault(proxy, method, args, caller); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about other, non-jdk code that wishes to implement a similar thing - make a proxy for an arbitrary interface and handle default methods by invoking them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To invoke the default method, the caller will need access to the declaring interface of the default method (via bytecode invocation or reflection). The bug I had was because java.base (the module of the invocation handler) does not have access to the interface even though the caller has.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To invoke the default method, the caller will need access to the declaring interface of the default method (via bytecode invocation or reflection). The bug I had was because java.base (the module of the invocation handler) does not have access to the interface even though the caller has.
So invokeDefault is moved to Proxy with an optional access check, and you've made it callable from MHProxies by way of JLRA. I think that is okay.
@@ -102,4 +102,7 @@ public void setConstructorAccessor(Constructor<?> c, | |||
/** Returns a new instance created by the given constructor with access check */ | |||
public <T> T newInstance(Constructor<T> ctor, Object[] args, Class<?> caller) | |||
throws IllegalAccessException, InstantiationException, InvocationTargetException; | |||
|
|||
public Object invokeDefault(Object proxy, Method method, Object[] args, Class<?> caller) | |||
throws Throwable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nit: add a comment to the method so that it's consistent with the other JLRA methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this:
/** Invokes the given default method if the method's declaring interface is
* accessible to the given caller. Otherwise, IllegalAccessException will
* be thrown. If the caller is null, no access check is performed.
*/
public Object invokeDefault(Object proxy, Method method, Object[] args, Class<?> caller)
throws Throwable;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this:
Looks okay, main thing is to have it be consistent with the existing methods.
My question was for when a library wants to implement something similar to But this might be a discussion for an other time. |
They will probably accept a |
Yes, that's one option. Such library should take a Lookup parameter to find the method handle for the default method as in the previous |
/integrate |
Going to push as commit a183bfb.
Your commit was automatically rebased without conflicts. |
The MethodHandle of a default method should be made as a fixed arity method handle because it is invoked via Proxy's invocation handle with a non-vararg array of arguments. On the other hand, the
InvocationHandle::invokeDefault
method was added in Java 16 to invoke a default method of a proxy instance. This patch simply converts the implementation to callInvocationHandle::invokeDefault
instead.Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/7185/head:pull/7185
$ git checkout pull/7185
Update a local copy of the PR:
$ git checkout pull/7185
$ git pull https://git.openjdk.java.net/jdk pull/7185/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 7185
View PR using the GUI difftool:
$ git pr show -t 7185
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/7185.diff