This document describes changes to the Java Virtual Machine Specification as modified by Class Loading Cleanup to support sealed types, a preview feature of Java SE 15. A sealed class or interface restricts extension and implementation to an enumerated set of authorized subclasses or subinterfaces. See JEP 360 for an overview of the feature.
Changes are described with respect to existing sections of the JVM Specification. New text is indicated like this and deleted text is indicated like this. Explanation and discussion, as needed, is set aside in grey boxes.
Chapter 4: The class File Format
4.7 Attributes
Attributes are used in the ClassFile, field_info, method_info, and Code_attribute structures of the class file format (4.1, 4.5, 4.6, 4.7.3).
All attributes have the following general format:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
For all attributes, the attribute_name_index item must be a valid unsigned 16-bit index into the constant pool of the class. The constant_pool entry at attribute_name_index must be a CONSTANT_Utf8_info structure (4.4.7) representing the name of the attribute. The value of the attribute_length item indicates the length of the subsequent information in bytes. The length does not include the initial six bytes that contain the attribute_name_index and attribute_length items.
28 29 attributes are predefined by this specification. They are listed three times, for ease of navigation:
Table 4.7-A is ordered by the attributes' section numbers in this chapter. Each attribute is shown with the first version of the
classfile format in which it was defined. Also shown is the version of the Java SE Platform which introduced that version of theclassfile format (4.1).Table 4.7-B is ordered by the first version of the
classfile format in which each attribute was defined.Table 4.7-C is ordered by the location in a
classfile where each attribute is defined to appear.
Within the context of their use in this specification, that is, in the attributes tables of the class file structures in which they appear, the names of these predefined attributes are reserved.
Any conditions on the presence of a predefined attribute in an attributes table are specified explicitly in the section which describes the attribute. If no conditions are specified, then the attribute may appear any number of times in an attributes table.
The predefined attributes are categorized into three groups according to their purpose:
SixSeven attributes are critical to correct interpretation of theclassfile by the Java Virtual Machine:ConstantValueCodeStackMapTableBootstrapMethodsNestHostNestMembersPermittedSubtypes
In a
classfile whose version number is v, each of these attributes must be recognized and correctly read by an implementation of the Java Virtual Machine if the implementation supports version v of theclassfile format, and the attribute was first defined in version v or earlier of theclassfile format, and the attribute appears in a location where it is defined to appear.Nine attributes are not critical to correct interpretation of the
classfile by the Java Virtual Machine, but are either critical to correct interpretation of theclassfile by the class libraries of the Java SE Platform, or are useful for tools (in which case the section that specifies an attribute describes it as "optional"):ExceptionsInnerClassesEnclosingMethodSyntheticSignatureSourceFileLineNumberTableLocalVariableTableLocalVariableTypeTable
In a
classfile whose version number is v, each of these attributes must be recognized and correctly read by an implementation of the Java Virtual Machine if the implementation supports version v of theclassfile format, and the attribute was first defined in version v or earlier of theclassfile format, and the attribute appears in a location where it is defined to appear.Thirteen attributes are not critical to correct interpretation of the
classfile by the Java Virtual Machine, but contain metadata about theclassfile that is either exposed by the class libraries of the Java SE Platform, or made available by tools (in which case the section that specifies an attribute describes it as "optional"):SourceDebugExtensionDeprecatedRuntimeVisibleAnnotationsRuntimeInvisibleAnnotationsRuntimeVisibleParameterAnnotationsRuntimeInvisibleParameterAnnotationsRuntimeVisibleTypeAnnotationsRuntimeInvisibleTypeAnnotationsAnnotationDefaultMethodParametersModuleModulePackagesModuleMainClass
An implementation of the Java Virtual Machine may use the information that these attributes contain, or otherwise must silently ignore these attributes.
Table 4.7-A. Predefined class file attributes (by section)
| Attribute | Section | class file |
Java SE |
|---|---|---|---|
ConstantValue |
4.7.2 | 45.3 | 1.0.2 |
Code |
4.7.3 | 45.3 | 1.0.2 |
StackMapTable |
4.7.4 | 50.0 | 6 |
Exceptions |
4.7.5 | 45.3 | 1.0.2 |
InnerClasses |
4.7.6 | 45.3 | 1.1 |
EnclosingMethod |
4.7.7 | 49.0 | 5.0 |
Synthetic |
4.7.8 | 45.3 | 1.1 |
Signature |
4.7.9 | 49.0 | 5.0 |
SourceFile |
4.7.10 | 45.3 | 1.0.2 |
SourceDebugExtension |
4.7.11 | 49.0 | 5.0 |
LineNumberTable |
4.7.12 | 45.3 | 1.0.2 |
LocalVariableTable |
4.7.13 | 45.3 | 1.0.2 |
LocalVariableTypeTable |
4.7.14 | 49.0 | 5.0 |
Deprecated |
4.7.15 | 45.3 | 1.1 |
RuntimeVisibleAnnotations |
4.7.16 | 49.0 | 5.0 |
RuntimeInvisibleAnnotations |
4.7.17 | 49.0 | 5.0 |
RuntimeVisibleParameterAnnotations |
4.7.18 | 49.0 | 5.0 |
RuntimeInvisibleParameterAnnotations |
4.7.19 | 49.0 | 5.0 |
RuntimeVisibleTypeAnnotations |
4.7.20 | 52.0 | 8 |
RuntimeInvisibleTypeAnnotations |
4.7.21 | 52.0 | 8 |
AnnotationDefault |
4.7.22 | 49.0 | 5.0 |
BootstrapMethods |
4.7.23 | 51.0 | 7 |
MethodParameters |
4.7.24 | 52.0 | 8 |
Module |
4.7.25 | 53.0 | 9 |
ModulePackages |
4.7.26 | 53.0 | 9 |
ModuleMainClass |
4.7.27 | 53.0 | 9 |
NestHost |
4.7.28 | 55.0 | 11 |
NestMembers |
4.7.29 | 55.0 | 11 |
PermittedSubtypes |
4.7.30 | 59.65535 | 15 |
Table 4.7-B. Predefined class file attributes (by class file format)
| Attribute | class file |
Java SE | Section |
|---|---|---|---|
ConstantValue |
45.3 | 1.0.2 | 4.7.2 |
Code |
45.3 | 1.0.2 | 4.7.3 |
Exceptions |
45.3 | 1.0.2 | 4.7.5 |
SourceFile |
45.3 | 1.0.2 | 4.7.10 |
LineNumberTable |
45.3 | 1.0.2 | 4.7.12 |
LocalVariableTable |
45.3 | 1.0.2 | 4.7.13 |
InnerClasses |
45.3 | 1.1 | 4.7.6 |
Synthetic |
45.3 | 1.1 | 4.7.8 |
Deprecated |
45.3 | 1.1 | 4.7.15 |
EnclosingMethod |
49.0 | 5.0 | 4.7.7 |
Signature |
49.0 | 5.0 | 4.7.9 |
SourceDebugExtension |
49.0 | 5.0 | 4.7.11 |
LocalVariableTypeTable |
49.0 | 5.0 | 4.7.14 |
RuntimeVisibleAnnotations |
49.0 | 5.0 | 4.7.16 |
RuntimeInvisibleAnnotations |
49.0 | 5.0 | 4.7.17 |
RuntimeVisibleParameterAnnotations |
49.0 | 5.0 | 4.7.18 |
RuntimeInvisibleParameterAnnotations |
49.0 | 5.0 | 4.7.19 |
AnnotationDefault |
49.0 | 5.0 | 4.7.22 |
StackMapTable |
50.0 | 6 | 4.7.4 |
BootstrapMethods |
51.0 | 7 | 4.7.23 |
RuntimeVisibleTypeAnnotations |
52.0 | 8 | 4.7.20 |
RuntimeInvisibleTypeAnnotations |
52.0 | 8 | 4.7.21 |
MethodParameters |
52.0 | 8 | 4.7.24 |
Module |
53.0 | 9 | 4.7.25 |
ModulePackages |
53.0 | 9 | 4.7.26 |
ModuleMainClass |
53.0 | 9 | 4.7.27 |
NestHost |
55.0 | 11 | 4.7.28 |
NestMembers |
55.0 | 11 | 4.7.29 |
PermittedSubtypes |
59.65535 | 15 | 4.7.30 |
Table 4.7-C. Predefined class file attributes (by location)
| Attribute | Location | class file |
|---|---|---|
SourceFile |
ClassFile |
45.3 |
InnerClasses |
ClassFile |
45.3 |
EnclosingMethod |
ClassFile |
49.0 |
SourceDebugExtension |
ClassFile |
49.0 |
BootstrapMethods |
ClassFile |
51.0 |
Module, ModulePackages, ModuleMainClass |
ClassFile |
53.0 |
NestHost, NestMembers |
ClassFile |
55.0 |
PermittedSubtypes |
ClassFile |
59.65535 |
ConstantValue |
field_info |
45.3 |
Code |
method_info |
45.3 |
Exceptions |
method_info |
45.3 |
RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations |
method_info |
49.0 |
AnnotationDefault |
method_info |
49.0 |
MethodParameters |
method_info |
52.0 |
Synthetic |
ClassFile, field_info, method_info |
45.3 |
Deprecated |
ClassFile, field_info, method_info |
45.3 |
Signature |
ClassFile, field_info, method_info |
49.0 |
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations |
ClassFile, field_info, method_info |
49.0 |
LineNumberTable |
Code |
45.3 |
LocalVariableTable |
Code |
45.3 |
LocalVariableTypeTable |
Code |
49.0 |
StackMapTable |
Code |
50.0 |
RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations |
ClassFile, field_info, method_info, Code |
52.0 |
4.7.30 The PermittedSubtypes Attribute
The PermittedSubtypes attribute is a variable-length attribute in the attributes table of a ClassFile structure. If a class or interface has a PermittedSubtypes attribute, any class or interface that attempts to extend or implement it must be named by the attribute (5.3.5).
In the Java Programming Language, there is a
sealedmodifier to indicate a class or interface that constrains extension in this way. In the class file, there is noACC_SEALEDflag. Instead, asealedclass or interface is indicated by the presence of thePermittedSubtypesattribute.
There may be at most one PermittedSubtypes attribute in the attributes table of a ClassFile structure whose ACC_FINAL flag is not set (4.1). If the ACC_FINAL flag is set, then the ClassFile structure must not have a PermittedSubtypes attribute.
We treat sealed as distinct from final—a sealed class has an enumerated list of designated subclasses, while a final class has no subclasses. Thus, a ClassFile structure may have a PermittedSubtypes attribute, or may have its ACC_FINAL flag set, but not both.
Alternatively, we could have let the PermittedSubtypes attribute refine the ACC_FINAL flag—reinterpreting "final" to mean "can't be extended, except for authorized subclasses". But doing so risks disrupting consumers of class files that have long assumed "final" means "has 0 subclasses" and that interfaces cannot be final.
The PermittedSubtypes attribute has the following format:
PermittedSubtypes_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
u2 classes[number_of_classes];
}
The items of the PermittedSubtypes_attribute structure are as follows:
- attribute_name_index
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (4.4.7) representing the string "PermittedSubtypes".- attribute_length
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes.- number_of_classes
The value of the
number_of_classesitem indicates the number of entries in theclassesarray.- classes[]
Each value in the
classesarray must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure (4.4.1) representing a class or interface which is authorized to extend or implement the current class or interface.The
classesarray is consulted when a class or interface that attempts to directly extend or implement the current class or interface is created (5.3.5). Array items that do not attempt to directly extend or implement the current class or interface are ignored.
Chapter 5: Loading, Linking, and Initializing
5.3 Creation and Loading
5.3.5 Deriving a Class from a class File Representation
The following steps are used to derive a nonarray class or interface C denoted by N using loader L from a purported representation in class file format.
First, the Java Virtual Machine determines whether the attempt to derive a class or interface named N for class loader L is invalid. If so, derivation throws a
LinkageError.An attempt to derive a class or interface named N for class loader L is invalid if one of the following are true:
L has already been recorded as as an initiating loader of a class or interface named N.
L is not the bootstrap class loader (5.3) and N is the reserved name
java/lang/Object.
The second case, combined with restrictions in 4.1, ensures that there is only one root of the class hierarchy, and the name
java/lang/Objectcan reliably be used to refer to it.The Java SE API enforces additional security restrictions that prevent unauthorized attempts to load classes in certain packages, including
java.*.Otherwise, the Java Virtual Machine attempts to parse the purported representation. However, the purported representation may not in fact be a valid representation of C.
This phase of derivation must detect the following errors:
If the purported representation provides a major and minor version number in its 5th through 8th bytes (4.1), but the version number is not supported by this Java Virtual Machine implementation, derivation throws an instance of
UnsupportedClassVersionError.UnsupportedClassVersionError, a subclass ofClassFormatError, was introduced to enable easy identification of aClassFormatErrorcaused by an attempt to load a class whose representation uses an unsupported version of theclassfile format. In JDK 1.1 and earlier, an instance ofNoClassDefFoundErrororClassFormatErrorwas thrown in case of an unsupported version, depending on whether the class was being loaded by the system class loader or a user-defined class loader.Otherwise, if the purported representation is not a
ClassFilestructure (4.1, 4.8), derivation throws an instance ofClassFormatError.Otherwise, if the purported representation does not actually represent a class or interface named N, derivation throws an instance of
NoClassDefFoundErroror an instance of one of its subclasses.This occurs when the purported representation has either a
this_classitem which specifies a name other than N, or anaccess_flagsitem which has theACC_MODULEflag set.
If C has a direct superclass, the symbolic reference from C to its direct superclass is resolved using the algorithm of 5.4.3.1. Note that if C is an interface it must have
Objectas its direct superclass. OnlyObjecthas no direct superclass.Any exceptions that can be thrown due to class or interface resolution can be thrown as a result of this phase of derivation. In addition, this phase of derivation must detect the following errors:
If the attempt to resolve the direct superclass leads to the current thread attempting to recursively derive a class named N using loader L, derivation throws a
ClassCircularityError.Otherwise, if the class or interface named as the direct superclass of C is an interface or a
finalclass, derivation throws anIncompatibleClassChangeError.Otherwise, if the class named as the direct superclass of C has a
PermittedSubtypesattribute (4.7.30), at least one entry in theclassestable of the superclass'sPermittedSubtypesattribute must reference a class or interface with name N. If not, derivation throws anIncompatibleClassChangeError.To ensure that the name N appearing in the superclass refers to C, an attempt is made, using the defining class loader of the superclass, to create a class or interface denoted by N. The attempt must lead to the current thread attempting to recursively derive a class or interface named N using loader L; the attempt is then abandoned. If the recursive attempt at derivation does not occur, derivation throws an
IncompatibleClassChangeError.Otherwise, if C is a class and some non-
staticmethod declared in C can override (5.4.5) afinal, non-staticmethod declared in a superclass of C, derivation throws anIncompatibleClassChangeError.
If C has any direct superinterfaces, the symbolic references from C to its direct superinterfaces are resolved using the algorithm of 5.4.3.1.
Any exceptions that can be thrown due to class or interface resolution can be thrown as a result of this phase of derivation. In addition, this phase of derivation must detect the following errors:
If the attempt to resolve a direct superinterface leads to the current thread attempting to recursively derive a class named N using loader L, derivation throws a
ClassCircularityError.Otherwise, if any of the classes or interfaces named as direct superinterfaces of C is not in fact an interface, derivation throws an
IncompatibleClassChangeError.Otherwise, for each direct superinterface, if the superinterface has a
PermittedSubtypesattribute (4.7.30), at least one entry in theclassestable of the superinterface'sPermittedSubtypesattribute must reference a class or interface with name N. If not, derivation throws anIncompatibleClassChangeError.To ensure that the name N appearing in the superinterface refers to C, an attempt is made, using the defining class loader of the superclass, to create a class or interface denoted by N. The attempt must lead to the current thread attempting to recursively derive a class or interface named N using loader L; the attempt is then abandoned. If the recursive attempt at derivation does not occur, derivation throws an
IncompatibleClassChangeError.
If, since step 1, in another thread, the Java Virtual Machine has marked a class or interface named N as having L as its defining class loader, that class or interface is the result of class derivation, and the class or interface derived in steps 1-4 is discarded.
Otherwise, the class or interface derived in steps 1-4 is the result of class derivation, and the Java Virtual Machine marks C as having L as its defining class loader and records that L is an initiating loader of C (5.3.4).