Is it possible to check if a class is explicitly marked as non-sealed
like with MyClass.class.isSealed()
and without checking its parent hierarchy? (And if so, how?)
Reason - I want to know if the info is somewhere in the class itself and not guess by checking if its final and looking up the parents. Maybe the language changes one day and this indirect condition may too.
There is, unfortunately, no dedicated method to find out whether a given class is explicitly defined as non-sealed
and negating the result of isSealed
method does not give you an accurate answer.
If you know the rules of defining a class as non-sealed
, you can construct the method that would do it for you.
class
/interface
must not be final
.class
/interface
must not be sealed
class
, its direct superclass must be sealed
.interface
, one of the direct superclasses must be sealed
.You don't need to check the whole parent hierarchy but due to the definition of non-sealed
, you have to inspect its direct supertype (or supertypes in case of interface
).
private static boolean isNonSealed(Class<?> clazz) {
final boolean extendsSealedInterface = clazz.isInterface() && Arrays.stream(clazz.getInterfaces()).anyMatch(Class::isSealed);
final boolean extendsSealedClass = clazz.getSuperclass() != null && clazz.getSuperclass().isSealed();
return !clazz.isSealed()
&& (extendsSealedInterface || extendsSealedClass)
&& !Modifier.isFinal(clazz.getModifiers());
}
In a small test, only Reptile
and Cat
are and should be found non-sealed
:
List<Class<?>> classes = List.of(
Animal.class, Mammal.class, Reptile.class,
Dog.class, Cat.class, SiameseCat.class);
classes.forEach(clazz -> {
System.out.printf("%10s : isSealed = %5s, parent.isSealed=%5s, isFinal=%5s -> isNonSealed=%s%n",
clazz.getSimpleName(),
clazz.isSealed(),
clazz.getSuperclass().isSealed(),
Modifier.isFinal(clazz.getModifiers()),
isNonSealed(clazz));
});
Classes:
// Let's omit 'permits' as all the subclasses are in the same file.
static sealed class Animal {}
static sealed class Mammal extends Animal {}
static non-sealed class Reptile extends Animal {}
static final class Dog extends Mammal {}
static non-sealed class Cat extends Mammal {}
static class SiameseCat extends Cat {}
Output, as you see, only Reptile
and Dog
are non-sealed
:
Animal : isInterface=false, isSealed = true, isFinal=false, parentClass.isSealed=false, parentInterfaces.anyIsSealed=false -> isNonSealed=false Mammal : isInterface=false, isSealed = true, isFinal=false, parentClass.isSealed= true, parentInterfaces.anyIsSealed=false -> isNonSealed=false Reptile : isInterface=false, isSealed = false, isFinal=false, parentClass.isSealed= true, parentInterfaces.anyIsSealed=false -> isNonSealed=true Dog : isInterface=false, isSealed = false, isFinal= true, parentClass.isSealed= true, parentInterfaces.anyIsSealed=false -> isNonSealed=false Cat : isInterface=false, isSealed = false, isFinal=false, parentClass.isSealed= true, parentInterfaces.anyIsSealed=false -> isNonSealed=true SiameseCat : isInterface=false, isSealed = false, isFinal=false, parentClass.isSealed=false, parentInterfaces.anyIsSealed=false -> isNonSealed=false
Interfaces:
sealed interface Animal {}
sealed interface Mammal extends Animal {}
non-sealed interface Reptile extends Animal {}
static final class Dog implements Mammal {} // doggo remains a class
non-sealed interface Cat extends Mammal {}
interface SiameseCat extends Cat {}
Output:
Animal : isInterface= true, isSealed = true, isFinal=false, parentClass.isSealed=false, parentInterfaces.anyIsSealed=false -> isNonSealed=false Mammal : isInterface= true, isSealed = true, isFinal=false, parentClass.isSealed=false, parentInterfaces.anyIsSealed= true -> isNonSealed=false Reptile : isInterface= true, isSealed = false, isFinal=false, parentClass.isSealed=false, parentInterfaces.anyIsSealed= true -> isNonSealed=true Dog : isInterface=false, isSealed = false, isFinal= true, parentClass.isSealed=false, parentInterfaces.anyIsSealed= true -> isNonSealed=false Cat : isInterface= true, isSealed = false, isFinal=false, parentClass.isSealed=false, parentInterfaces.anyIsSealed= true -> isNonSealed=true SiameseCat : isInterface= true, isSealed = false, isFinal=false, parentClass.isSealed=false, parentInterfaces.anyIsSealed=false -> isNonSealed=false