Clarifying record reflective support
Remi Forax
forax at univ-mlv.fr
Tue Dec 3 21:10:54 UTC 2019
Hi Chris,
Please do not add another java.io.File.listFiles() !
People will test a code that use Class.getRecordComponents() only with records forgetting as usual to have negative tests and it will blow in production.
A method that returns an array should never return null.
I repeat
A method that returns an array should never return null.
If someone want to disambiguate between i've no record component because i'm a record or i've no record component because i'm not a record, isRecord is exactly the kind of method you want to call.
regards,
Rémi
----- Mail original -----
> De: "Chris Hegarty" <chris.hegarty at oracle.com>
> À: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>, "joe darcy" <joe.darcy at oracle.com>, "Maurizio Cimadamore"
> <maurizio.cimadamore at oracle.com>
> Envoyé: Mardi 3 Décembre 2019 12:26:53
> Objet: Clarifying record reflective support
> A number of issues and/or concerns have been come up recently relating
> to the reflective support for records. These arose when finalizing and
> completing the runtime CSR. Taken together they seem to lead back to a
> few small, but significant, omissions in the spec that would be good to
> tighten up. 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) It's 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 it's specification, guaranteed both of
> point 1 and point 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. We thought it
> kinda nice to be able to avoid returning null, but with hindsight I
> think that it would be better to remove this potential ambiguity. The
> getRecordComponents method should only return a non-null value if both
> point 1 ( the class is a record class ) and point 2 above are true.
> There are many other null returning methods in Class, so this is not
> unusual or out of place. The implementation only requires a minor change
> to support this ( return null for non-record classes ).
>
> The most significant part of the changes proposed are to the
> specification, so I've included that here inline. The proposed changes
> tightly couple the pair of methods as part of their specification,
> something that will hopefully be cleaner to do (or even unnecessary)
> when we have full pattern matching.
>
>
> /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 empty)
> + * 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 false, then this method returns null. Conversely,
> if
> + * {@link #isRecord()} returns 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() { … }
>
>
> -Chris.
More information about the amber-spec-experts
mailing list