RFR: 8246778: Compiler implementation for Sealed Classes (Second Preview) [v3]

Mandy Chung mchung at openjdk.java.net
Thu Dec 3 18:21:00 UTC 2020

On Wed, 2 Dec 2020 14:40:15 GMT, Jan Lahoda <jlahoda at openjdk.org> wrote:

>> This pull request replaces https://github.com/openjdk/jdk/pull/1227.
>> From the original PR:
>>> Please review the code for the second iteration of sealed classes. In this iteration we are:
>>>     * Enhancing narrowing reference conversion to allow for stricter checking of cast conversions with respect to sealed type hierarchies
>>>     * Also local classes are not considered when determining implicitly declared permitted direct subclasses of a sealed class or sealed interface
>>>     * renaming Class::permittedSubclasses to Class::getPermittedSubclasses, still in the same method, the return type has been changed to Class<?>[] instead of the previous ClassDesc[]
>>>     * adding code to make sure that annotations can't be sealed
>>>     * improving some tests
>>> TIA
>>> Related specs:
>>> [Sealed Classes JSL](http://cr.openjdk.java.net/~gbierman/jep397/jep397-20201104/specs/sealed-classes-jls.html)
>>> [Sealed Classes JVMS](http://cr.openjdk.java.net/~gbierman/jep397/jep397-20201104/specs/sealed-classes-jvms.html)
>>> [Additional: Contextual Keywords](http://cr.openjdk.java.net/~gbierman/jep397/jep397-20201104/specs/contextual-keywords-jls.html)
>> This PR strives to reflect the review comments from 1227:
>>  * adjustments to javadoc of j.l.Class methods
>>  * package access checks in Class.getPermittedSubclasses()
>>  * fixed to the narrowing conversion/castability as pointed out by Maurizio
> Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:
>   Improving Class.getPermittedSubclasses to filter out permitted classes that are not a subtype of the current class, and other adjustments per the review feedback.

I approve this version of `Class::getPermittedSubclasses` implementation for this PR.    We need to follow up the specification of `Class::getPermittedSubclasses` w.r.t. what it should return e.g. the classes whatever in `PermittedSubclasses` attribute vs the classes that are permitted subtypes at runtime and return null if this class is not sealed. 

I reviewed hotspot and java.base changes (not langtools) with a couple minor comments.

test/jdk/java/lang/reflect/sealed_classes/TestSecurityManagerChecks.java line 51:

> 49: public class TestSecurityManagerChecks {
> 50: 
> 51:     private static final ClassLoader OBJECT_CL = Object.class.getClassLoader();

This is `null` - the bootstrap class loader.   An alternative to the static variable we can simply use null.

test/jdk/java/lang/reflect/sealed_classes/TestSecurityManagerChecks.java line 66:

> 64:                                                     .getProtectionDomain()
> 65:                                                     .getCodeSource()
> 66:                                                     .getLocation();

This is essentially the classpath.   An alternative way to get the location through `System.getProperty("test.class.path")`.

test/jdk/java/lang/reflect/sealed_classes/TestSecurityManagerChecks.java line 86:

> 84: 
> 85:         // First get hold of the target classes before we enable security
> 86:         Class<?> sealed = testLayer.findLoader("test").loadClass("test.Base");

I would recommend to use `Class::forName` instead of `ClassLoader::loadClass`  even though this is just a test (for security reason for example avoid type confusion).   If you want to load a class from a specific module, you can use `Class.forName(String cn, Module m)`

test/jdk/java/lang/reflect/sealed_classes/TestSecurityManagerChecks.java line 91:

> 89:         Class<?>[] subclasses = sealed.getPermittedSubclasses();
> 90: 
> 91:         if (subclasses.length != 3) {

I suggest to check against the expected list of permitted subclasses here and also the validation in the subsequent calls to `getPermittedSubclasses` with security manager enabled.   That would help the readers easier to understand this test.

test/jdk/java/lang/reflect/sealed_classes/TestSecurityManagerChecks.java line 120:

> 118: 
> 119:         //should pass - does not return a class from package "test":
> 120:         sealed.getPermittedSubclasses();

Adding a check to the expected returned value would make this clear (no permitted subclasses of package `test`).

src/java.base/share/classes/java/lang/Class.java line 3035:

> 3033:      */
> 3034:     private static void checkPackageAccessForPermittedSubclasses(SecurityManager sm,
> 3035:                                     final ClassLoader ccl, boolean checkProxyInterfaces,

`checkProxyInterfaces` parameter is not needed.  It can be removed.


Marked as reviewed by mchung (Reviewer).

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

More information about the compiler-dev mailing list