RFR: JDK-8322878: Including sealing information Class.toGenericString() [v4]

Pavel Rappo prappo at openjdk.org
Tue Jan 9 15:32:23 UTC 2024


On Mon, 8 Jan 2024 22:29:47 GMT, Joe Darcy <darcy at openjdk.org> wrote:

>>> Since it doesn't seem possible to do so, I did not attempt to relay "non-sealed" information in this PR :-)
>> 
>> Naively, I thought that something like this is possible _in principle_; I might be mistaken though:
>> 
>> diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java
>> index 851d65d06ad..014845860d0 100644
>> --- a/src/java.base/share/classes/java/lang/Class.java
>> +++ b/src/java.base/share/classes/java/lang/Class.java
>> @@ -4771,6 +4771,30 @@ public boolean isSealed() {
>>          return getPermittedSubclasses() != null;
>>      }
>>  
>> +    private boolean isNonSealed() {
>> +        if (isSealed())
>> +            return false;
>> +        if (!isInterface() && Modifier.isFinal(getModifiers())) {
>> +            // unlike interface, class can be final
>> +            return false;
>> +        }
>> +        // if an ancestor is sealed, this class can either be non-sealed or final
>> +        return hasSealedAncestor(this);
>> +    }
>> +
>> +    private boolean hasSealedAncestor(Class<?> clazz) {
>> +        var superclass = clazz.getSuperclass();
>> +        if (superclass != null) {
>> +            if (superclass.isSealed() || hasSealedAncestor(superclass))
>> +                return true;
>> +        }
>> +        for (var superinterface : clazz.getInterfaces()) {
>> +            if (superinterface.isSealed() || hasSealedAncestor(superinterface))
>> +                return true;
>> +        }
>> +        return false;
>> +    }
>> +
>>      private native Class<?>[] getPermittedSubclasses0();
>>  
>>      /*
>
>> Thanks @pavelrappo; I'll explore incorporating functionality like this into the PR, probably next week.
> 
> Pushed an initial cut of non-sealing support; will add more test cases later.

Thanks for including `non-sealed`, Joe.

Regarding your implementation: you are right that only the direct superclass and direct superinterfaces need to be explored for being `sealed`. No need to explore the full ancestry. So, recursion in my [initial proposal] was superfluous.

That said, I have a question on [JLS 8.1.1.2], which you copied as inline commentary:

> It is a compile-time error if a class is declared non-sealed but has neither a sealed direct superclass nor a sealed direct superinterface.
>
> Thus, a subclass of a non-sealed class cannot itself be declared non-sealed.

I wonder if it can be clarified to account for hierarchies where a `non-sealed` class or `non-sealed` interface has a `non-sealed` direct superinterface, or a `non-sealed` class has a `non-sealed` direct superclass.

For example:

    sealed interface A permits B { }

    sealed interface I permits X { }

    non-sealed interface B extends A { }

    non-sealed interface X extends B, I { }

and

    sealed class A permits B { }

    sealed interface I permits C { }

    non-sealed class B extends A { }

    non-sealed class C extends B implements I { }

(CC'ing @GavinBierman)

[initial proposal]: https://github.com/openjdk/jdk/pull/17239#discussion_r1440867004
[JLS 8.1.1.2]: https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.1.1.2

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

PR Review Comment: https://git.openjdk.org/jdk/pull/17239#discussion_r1446243516


More information about the core-libs-dev mailing list