This specification is not final and is subject to change. Use is subject to license terms.

Sealed Types

Changes to the Java® Virtual Machine Specification • Version 15-internal+0-adhoc.dlsmith.20200421

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:

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:

  1. Six Seven attributes are critical to correct interpretation of the class file by the Java Virtual Machine:

    • ConstantValue
    • Code
    • StackMapTable
    • BootstrapMethods
    • NestHost
    • NestMembers
    • PermittedSubtypes

    In a class file 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 the class file format, and the attribute was first defined in version v or earlier of the class file format, and the attribute appears in a location where it is defined to appear.

  2. Nine attributes are not critical to correct interpretation of the class file by the Java Virtual Machine, but are either critical to correct interpretation of the class file 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"):

    • Exceptions
    • InnerClasses
    • EnclosingMethod
    • Synthetic
    • Signature
    • SourceFile
    • LineNumberTable
    • LocalVariableTable
    • LocalVariableTypeTable

    In a class file 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 the class file format, and the attribute was first defined in version v or earlier of the class file format, and the attribute appears in a location where it is defined to appear.

  3. Thirteen attributes are not critical to correct interpretation of the class file by the Java Virtual Machine, but contain metadata about the class file 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"):

    • SourceDebugExtension
    • Deprecated
    • RuntimeVisibleAnnotations
    • RuntimeInvisibleAnnotations
    • RuntimeVisibleParameterAnnotations
    • RuntimeInvisibleParameterAnnotations
    • RuntimeVisibleTypeAnnotations
    • RuntimeInvisibleTypeAnnotations
    • AnnotationDefault
    • MethodParameters
    • Module
    • ModulePackages
    • ModuleMainClass

    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 sealed modifier to indicate a class or interface that constrains extension in this way. In the class file, there is no ACC_SEALED flag. Instead, a sealed class or interface is indicated by the presence of the PermittedSubtypes attribute.

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_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing the string "PermittedSubtypes".

attribute_length

The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes.

number_of_classes

The value of the number_of_classes item indicates the number of entries in the classes array.

classes[]

Each value in the classes array must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing a class or interface which is authorized to extend or implement the current class or interface.

The classes array 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.

  1. 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/Object can 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.*.

  2. 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 of ClassFormatError, was introduced to enable easy identification of a ClassFormatError caused by an attempt to load a class whose representation uses an unsupported version of the class file format. In JDK 1.1 and earlier, an instance of NoClassDefFoundError or ClassFormatError was 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 ClassFile structure (4.1, 4.8), derivation throws an instance of ClassFormatError.

    • Otherwise, if the purported representation does not actually represent a class or interface named N, derivation throws an instance of NoClassDefFoundError or an instance of one of its subclasses.

      This occurs when the purported representation has either a this_class item which specifies a name other than N, or an access_flags item which has the ACC_MODULE flag set.

  3. 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 Object as its direct superclass. Only Object has 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 final class, derivation throws an IncompatibleClassChangeError.

    • Otherwise, if the class named as the direct superclass of C has a PermittedSubtypes attribute (4.7.30), at least one entry in the classes table of the superclass's PermittedSubtypes attribute must reference a class or interface with name N. If not, derivation throws an IncompatibleClassChangeError.

      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-static method declared in C can override (5.4.5) a final, non-static method declared in a superclass of C, derivation throws an IncompatibleClassChangeError.

  4. 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 PermittedSubtypes attribute (4.7.30), at least one entry in the classes table of the superinterface's PermittedSubtypes attribute must reference a class or interface with name N. If not, derivation throws an IncompatibleClassChangeError.

      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.

  5. 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).