Summary
-------
Update Class::isRecord to only return true for classes that are final.
Problem
-------
The removal of non-specified JVM checks on classes with a Record
Attribute (see JDK-8255342), has resulted in more types of loadable
classes that may contain a Record Attribute. Since these checks are
not performed by the JVM anymore, `Class::isRecord`, and by extension
`Class::getRecordComponents`, may return true or component values,
respectively, for classes that are not well-formed record classes (as
per the JLS), .e.g. non-final or abstract classes, that contain a record
Attribute.
Solution
--------
Core Reflection, `Class::isRecord`, already asserts checks that the JVM
does not, e.g. that the direct superclass is `java.lang.Record`.
Some points from the Java Language Specification for record classes:
1. It is a compile-time error if a record declaration has the modifier
abstract.
2. A record declaration is implicitly final.
3. The direct superclass type of a record class is Record.
`Class::isRecord` already ensures no.3. This issue proposes to add
explicit checks in Core Reflection to ensure #1 and #2, since the JVM
now allows such classes that contain a Record Attribute to be loaded.
Note: asserting that a class is final is sufficient, as it implies that
the class it non-abstract - an assertion guaranteed by the JVM.
Specification
-------------
java.lang.Class:
/**
* Returns {@code true} if and only if this class is a record class.
*
* <p> The {@linkplain #getSuperclass() direct superclass} of a record
- * class is {@code java.lang.Record}. A record class has (possibly zero)
- * record components, that is, {@link #getRecordComponents()} returns a
- * non-null value.
+ * class is {@code java.lang.Record}. A record class is {@linkplain
+ * Modifier#FINAL final}. A record class has (possibly zero) record
+ * components; {@link #getRecordComponents()} returns a non-null but
+ * possibly empty value for a record.
*
* <p> Note that class {@link Record} is not a record type and thus invoking
* this method on class {@code Record} returns {@code false}.
*
* @return true if and only if this class is a record class, otherwise false
* @jls 8.10 Record Types
* @since 16
*/
public boolean isRecord() { ... }