Define custom class loader to overwrite defineClass; then load binary class by the code below. This will throw InCompatibleClassChangeError.
CustomClassLoader c = new CustomClassLoader();
c.findClass(SEALING_CLASS_NAME);
Sample error as below,
Exception in thread "main" java.lang.IncompatibleClassChangeError: class samplecode.SealedSubClass cannot inherit from sealed class samplecode.SealedClassParentClass
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:874)
at samplecode.SealedSubClassTest$CustomClassLoader.findClass(SealedSubClassTest.java:63)
at samplecode.SealedSubClassTest.inCompatibleClassChangeErrorTest(SealedSubClassTest.java:23)
at samplecode.SealedSubClassTest.main(SealedSubClassTest.java:16)
Please refer to JVM spec for JDK17 at https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-5.html#jvms-5.3.2.
The explanation as below,
To start loading of a class the class loader has to locate its class file (or other representation) and pass it to defineClass. As part of loading that class JVM has to resolve its super classes and load them first - which starts by asking the current defining classloader to load it. If that classloader delegates to its parent loader (as it should) and the parent loader finds the superclass, then it gets loaded by the parent loader. As a result the superclass and subclass end up loaded by different loaders. For sealed classes this is a fatal error that prevents the loading of the subclass from completing successfully. In JVM specification, InCompatibleClassChangeError is thrown.
CustomClassLoader c = new CustomClassLoader();
c.findClass(SEALING_CLASS_NAME);
Sample error as below,
Exception in thread "main" java.lang.IncompatibleClassChangeError: class samplecode.SealedSubClass cannot inherit from sealed class samplecode.SealedClassParentClass
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:874)
at samplecode.SealedSubClassTest$CustomClassLoader.findClass(SealedSubClassTest.java:63)
at samplecode.SealedSubClassTest.inCompatibleClassChangeErrorTest(SealedSubClassTest.java:23)
at samplecode.SealedSubClassTest.main(SealedSubClassTest.java:16)
Please refer to JVM spec for JDK17 at https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-5.html#jvms-5.3.2.
The explanation as below,
To start loading of a class the class loader has to locate its class file (or other representation) and pass it to defineClass. As part of loading that class JVM has to resolve its super classes and load them first - which starts by asking the current defining classloader to load it. If that classloader delegates to its parent loader (as it should) and the parent loader finds the superclass, then it gets loaded by the parent loader. As a result the superclass and subclass end up loaded by different loaders. For sealed classes this is a fatal error that prevents the loading of the subclass from completing successfully. In JVM specification, InCompatibleClassChangeError is thrown.
- relates to
-
JDK-8345911 Enhance error message when IncompatibleClassChangeError is thrown for sealed class loading failures
- Resolved