-
CSR
-
Resolution: Approved
-
P2
-
behavioral
-
minimal
-
No compatibility risk. New API in Java 14.
-
Java API
-
SE
Summary
Clarify record reflective support specification.
Problem
A number of issues and/or concerns have been raised recently relating to the reflective support for records. These arose when finalizing and completing the runtime CSR, JDK-8233436. Taken together they seem to lead back to a few small, but significant, omissions in the spec that would be good to tighten up.
Solution
It is important that it be possible to reflectively reason about record classes in a way that is unambiguous and provides certainty that the record class is well-formed.
For a class to be a record class, then:
- Its direct superclass must be
java.lang.Record,
and - It must have a Record attribute.
The entry point to the reflective API for records is the two methods:
Class::isRecord
and Class::getRecordComponents
.
The isRecord
method should, in its specification, guarantee both of
no.1 and no.2 above. That is to say, for a class to be considered a
record class, then its direct superclass must be java.lang.Record
, and
it must have a Record attribute. The implementation already behaves this
way, but the specification should require it.
The getRecordComponents
method currently returns an empty array for
both a record class with no components and a non-record class. While
initially it was considered desirable to avoid returning null, in
hindsight it would be better to remove this potential ambiguity. The
getRecordComponents
method should only return a non-null value if both
no.1 and no.2 above are true, that is, only for record classes. There
are a number of other null-returning partial functions in Class
, e.g.
getEnumConstants
, so this is not unusual or out of place, and in fact
should follow the same pattern.
Discussion on amber-spec-experts: https://mail.openjdk.java.net/pipermail/amber-spec-experts/2019-December/001840.html
Specification
/src/java.base/share/classes/java/lang/Class.java
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns {@code true} if and only if this class is a record class.
- * It returns {@code false} otherwise. Note that class {@link Record} is not a
- * record type and thus invoking this method on class {@link java.lang.Record}
- * returns {@code false}.
- *
- * @return 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.
+ *
+ * <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 14
*/
public boolean isRecord() { ... }
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
- * Returns an array containing {@code RecordComponent} objects reflecting all the
- * declared record components of the record represented by this {@code Class} object.
- * The components are returned in the same order that they are declared in the
- * record header.
- *
- * @return The array of {@code RecordComponent} objects representing all the
- * record components of this record. The array is empty if this class
- * is not a record, or if this class is a record with no components.
+ * Returns an array of {@code RecordComponent} objects representing all the
+ * record components of this record class, or {@code null} if this class is
+ * not a record class.
+ *
+ * <p> The components are returned in the same order that they are declared
+ * in the record header. The array is empty if this record class has no
+ * components. If the class is not a record class, that is {@link
+ * #isRecord()} returns {@code false}, then this method returns {@code null}.
+ * Conversely, if {@link #isRecord()} returns {@code true}, then this method
+ * returns a non-null value.
+ *
+ * @return An array of {@code RecordComponent} objects representing all the
+ * record components of this record class, or {@code null} if this
+ * class is not a record class
* @throws SecurityException
* ...
*
* @jls 8.10 Record Types
* @since 14
*/
public RecordComponent[] getRecordComponents() { ... }
- csr of
-
JDK-8235550 Clarify record reflective support specification
- Closed