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

Chris Hegarty chris.hegarty at oracle.com
Thu Nov 5 10:31:43 UTC 2020


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.

-Chris.

[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