The Record Attribute - What does it mean to be a record at runtime?

Remi Forax forax at univ-mlv.fr
Thu Nov 5 23:59:27 UTC 2020


----- Mail original -----
> De: "Chris Hegarty" <chris.hegarty at oracle.com>
> À: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Jeudi 5 Novembre 2020 11:31:43
> Objet: The Record Attribute - What does it mean to be a record at runtime?

> This email has no concrete proposal describe within, but rather is
> intended to start a discussion relating to the finer-grain aspects of
> the Record Attribute and the primitives built atop.
> 
> Records offers a new protocol that can be leveraged at runtime by
> frameworks and libraries; A record class has a known state, accessors
> of that state, and a canonical constructor to initialize the state.
> Taken together these properties offer a new protocol for libraries to
> interact with records. We already see this with serialization libraries,
> e.g. Java Serialization, Jackson, Kryo, etc.
> 
> The language, as it should, provides very strong guarantees about what
> it means to be a record class; is final, j.l.Record is the direct
> superclass, a final field and accessor for each component, a canonical
> constructor, etc. The JVM, however, does not provide such strong
> guarantees, which is not surprising. There is, and it is desirable to
> have, flexibility between the language and the JVM.
> 
> The last piece of the puzzle, which builds atop the runtime, is the
> reflective support in the Java Core Libraries, namely j.l.Class and
> friends. For frameworks and libraries to take advantage of the "records
> protocol", then they need to be able to introspect and determine the
> various properties of a record class. To date, the Class::isRecord and
> Class::getRecordComponents primitives have proved sufficient for this.
> 
> Lastly, and highly desirable, is that we've been able to expand the
> notion of "trusted final fields" to the fields of record classes [1].
> The impact of this on the Java Core Libraries is that the fields
> (backing that of the record components) are not writable through the
> various Core Reflection, MethodHandle and VarHandles, APIs.
> 
> There is a clear and tight coupling between the Java Reflection APIs
> and that of the JVM - they don't necessarily need to operate or even
> behave in the exact same way, but the relationship should be clear and
> well-specified. When it is not, we often find undesirable and
> uncomfortable behavior in dark corners - "Here be Dragons"!
> 
> A recent change, 8255342 [2], laxifies the JVM checking of the Record
> Attribute - the JVM will happily consider a non-final, abstract class,
> that is not a direct subclass of j.l.Record to be a record class. The
> JVM implementation stores the record-ness property which feeds into the
> consideration of trust-final-non-static-fields, which can then feed into
> potential behavior (and optimizations?) in the JVM. In the Java
> Reflection APIs, the "writability" of the field of the record class is
> determine by the JVM's notion of whether or not class C is a record, and
> not C.isRecord - which may disagree with the JVM. But the specification
> of writability in the Core Reflection APIs builds upon Class::isRecord
> (what else could it do!). Not to mention object field lookup in Unsafe.
> 
> We have a JIRA issue [3] tracking the potential knock-on affect on
> the Java Core Reflection APIs resulting from the changes for 8255342.
> We could just "fix" that bug and move on, but I think there is something
> more fundamental at stake here, and it may be best to re-consider some
> prior decisions relating to the interpretation of the Record Attribute
> itself. I don't have all the answers, but it seems that at an early
> stage the Record Attribute was merely some meta-data carried in the
> class file, hence its position in the second of the predefined attribute
> categorizes, "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". Is that still the case? Does the JVM consider the record-ness
> of a class for other parts of it operation now (trusting final fields)?
> 
> It seems highly desirable that both the JVM and the Java Reflection
> Libraries agree on what it means to be a record at runtime. And where
> they do not, then that should be explicitly understood and the
> implications assessed.
> 
> Comments welcome.

What a record is, is defined by the JLS but not by the JVMS (like enums),
so the JVM should not know what a record is given that it's an artifact of the language not an artifact of the VM.

We are also trying to enforce more unmodifiability of the final fields in the VM, Reflection, Unsafe, VarHandle, etc.
Because of backward compatibility, we can not just make all final fields unmodifiable, because some libraries (or worst some Jakarta EE specs) relies on the fact that a final field can be changed after construction.
So we are selectively enabling a more stronger stance on the modifiability of final field only for new constructs, VM anonymous class, VM hidden class and record class.
Here the VM doesn't really need to know what a record is but only that this is a new construct so the rules around final fields are stronger, stricter.
So for me, we do not need to do more in the VM.

Now, for the reflection part, the reflection is mostly the Java view of the world, it's not stricto sensu true because you can see the desugaring done by the compiler.
The reflection knows what a record is, it has to directly inherits from java.lang.Record, be final and have a RecordComponents attribute (gently provided by the VM).
So both isRecord and getRecordComponents should checks these properties.

I hope that help.

> 
> -Chris.

Rémi

> 
> [1] https://bugs.openjdk.java.net/browse/JDK-8247444
> [2] https://bugs.openjdk.java.net/browse/JDK-8255342
> [3] https://bugs.openjdk.java.net/browse/JDK-8255560


More information about the amber-spec-experts mailing list