Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8235583

Clarify record reflective support specification

XMLWordPrintable

    • 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:

      1. Its direct superclass must be java.lang.Record, and
      2. 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() { ... }

            chegar Chris Hegarty
            chegar Chris Hegarty
            Maurizio Cimadamore, Vicente Arturo Romero Zaldivar
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: