RFR: 8159746: (proxy) Support for default methods [v3]

Peter Levart plevart at openjdk.java.net
Wed Sep 30 21:30:26 UTC 2020


On Wed, 30 Sep 2020 19:14:28 GMT, Mandy Chung <mchung at openjdk.org> wrote:

>> This proposes a new static `Proxy::invokeDefaultMethod` method to invoke
>> the given default method on the given proxy instance.
>> 
>> The implementation looks up a method handle for `invokespecial` instruction
>> as if called from with the proxy class as the caller, equivalent to calling
>> `X.super::m` where `X` is a proxy interface of the proxy class and
>> `X.super::m` will resolve to the specified default method.
>> 
>> The implementation will call a private static `proxyClassLookup(Lookup caller)`
>> method of the proxy class to obtain its private Lookup.  This private method
>> in the proxy class only allows a caller Lookup on java.lang.reflect.Proxy class
>> with full privilege access to use, or else `IllegalAccessException` will be
>> thrown.
>> 
>> This patch also proposes to define a proxy class in an unnamed module to
>> a dynamic module to strengthen encapsulation such that they are only
>> unconditionally exported from a named module but not open for deep reflective
>> access.  This only applies to the case if all the proxy interfaces are public
>> and in a package that is exported or open.
>> 
>> One dynamic module is created for each class loader that defines proxies.
>> The change changes the dynamic module to contain another package (same
>> name as the module) that is unconditionally exported and is opened to
>> `java.base` only.
>> 
>> There is no change to the package and module of the proxy class for
>> the following cases:
>> 
>> - if at least one proxy interface is non-public, then the proxy class is defined
>>   in the package and module of the non-public interfaces
>> - if at least one proxy is in a package that is non-exported and non-open,
>>   if all proxy interfaces are public, then the proxy class is defined in
>>   a non-exported, non-open package of a dynamic module.
>> 
>> The spec change is that a proxy class used to be defined in an unnamed
>> module, i.e. in a exported and open package, is defined in an unconditionally
>> exported but non-open package.  Programs that assume it to be open unconditionally
>> will be affected and cannot do deep reflection on such proxy classes.
>> 
>> Peter Levart contributed an initial prototype [1] (thanks Peter).  I think
>> the exceptions could be simplified as more checking should be done prior to
>> the invocation of the method handle like checking the types of the arguments
>> with the method type.  This approach avoids defining a public API
>> `protected Proxy::$$proxyClassLookup$$` method.  Instead it defines a
>> private static method that is restricted for Proxy class to use (by
>> taking a caller parameter to ensure it's a private lookup on Proxy class).
>> 
>> javadoc/specdiff:
>> http://cr.openjdk.java.net/~mchung/jdk16/webrevs/8159746/api/
>> http://cr.openjdk.java.net/~mchung/jdk16/webrevs/8159746/specdiff/
>> 
>> [1]  http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-June/041629.html
>
> Mandy Chung has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev
> excludes the unrelated changes brought in by the merge/rebase. The pull request contains 17 additional commits since
> the last revision:
>  - Merge branch 'master' of https://github.com/openjdk/jdk into proxy-default-method
>  - minor tweak to the spec wording and impl
>  - Merge pull request #1 from plevart/proxy-default-method-performance
>    
>    Performance improvements for Proxy::invokeDefaultMethod
>  - Add test case for InvocationTargetException
>  - Revert the thrown exceptions spec to be consistent with Method::invoke
>  - Speed up Proxy.invokeDefaultMethod while also changing its spec regarding exception types thrown
>  - Merge branch 'master' of https://github.com/openjdk/jdk into proxy-default-method
>  - fix regression tests due to proxy name change
>  - minor bug fix
>  - Merge branch 'master' of https://github.com/openjdk/jdk into proxy-default-method
>  - ... and 7 more: https://git.openjdk.java.net/jdk/compare/5b4fb338...db6cfc13

src/java.base/share/classes/java/lang/reflect/Proxy.java line 1256:

> 1254:      *             {@code args} elements cannot be assigned to the corresponding
> 1255:      *             method parameter type.</li>
> 1256:      *         </ul>

Hm, well, on a second thought, the following: "...or if, after possible unboxing, any of the args elements cannot be
assigned to the corresponding method parameter type" is not quite what happens. For example, if the method parameter
type is primitive long and an Integer object is passed to the invokeDefaultMethod at its place, then according to above
wording "after unboxing" we get an int value. Can int value be assigned to long parameter? What happens is that Integer
object 1st tries to be cast to Long and only then unboxing happens. Such is the order of spreadArguments MH operator.

-------------

PR: https://git.openjdk.java.net/jdk/pull/313


More information about the core-libs-dev mailing list