8225054: Compiler implementation for records

8225052: javax.lang.model support for records
8225053: Preview APIs support for records
8225055: Javadoc for records
8226314: com.sun.source support for records
8227113: Specification for java.lang.Record
8233526: JVM support for records

Implement records in the compiler and the JVM, including serialization, reflection and APIs support

Co-authored-by: Brian Goetz <brian.goetz@oracle.com>
Co-authored-by: Maurizio Cimadamore <maurizio.cimadamore@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Joe Darcy <joe.darcy@oracle.com>
Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com>
Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Reviewed-by: mcimadamore, briangoetz, alanb, darcy, chegar, jrose, jlahoda, coleenp, dholmes, lfoltan, mchung, sadayapalam, hannesw, sspitsyn
This commit is contained in:
Vicente Romero 2019-12-04 15:57:39 -05:00
parent 0a375cfa2d
commit 827e5e3226
351 changed files with 24958 additions and 6395 deletions

View file

@ -26,7 +26,9 @@
package java.io;
import java.io.ObjectStreamClass.WeakClassKey;
import java.io.ObjectStreamClass.RecordSupport;
import java.lang.System.Logger;
import java.lang.invoke.MethodHandle;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
@ -218,6 +220,39 @@ import sun.reflect.misc.ReflectUtil;
* Similarly, any serialPersistentFields or serialVersionUID field declarations
* are also ignored--all enum types have a fixed serialVersionUID of 0L.
*
* @implSpec
* <a id="record-serialization"></a>
* Records are serialized differently than ordinary serializable or externalizable
* objects. The serialized form of a record object is a sequence of values derived
* from the record components. The stream format of a record object is the same as
* that of an ordinary object in the stream. During deserialization, if the local
* class equivalent of the specified stream class descriptor is a record class,
* then first the stream fields are read and reconstructed to serve as the record's
* component values; and second, a record object is created by invoking the
* record's <i>canonical</i> constructor with the component values as arguments (or the
* default value for component's type if a component value is absent from the
* stream).
* Like other serializable or externalizable objects, record objects can function
* as the target of back references appearing subsequently in the serialization
* stream. However, a cycle in the graph where the record object is referred to,
* either directly or transitively, by one of its components, is not preserved.
* The record components are deserialized prior to the invocation of the record
* constructor, hence this limitation (see
* <a href="{@docRoot}/../specs/serialization/serial-arch.html#cyclic-references">
* [Section 1.14, "Circular References"</a> for additional information).
* The process by which record objects are serialized or externalized cannot be
* customized; any class-specific writeObject, readObject, readObjectNoData,
* writeExternal, and readExternal methods defined by record classes are
* ignored during serialization and deserialization. However, a substitute object
* to be serialized or a designate replacement may be specified, by the
* writeReplace and readResolve methods, respectively. Any
* serialPersistentFields field declaration is ignored. Documenting serializable
* fields and data for record classes is unnecessary, since there is no variation
* in the serial form, other than whether a substitute or replacement object is
* used. The serialVersionUID of a record class is 0L unless explicitly
* declared. The requirement for matching serialVersionUID values is waived for
* record classes.
*
* @author Mike Warres
* @author Roger Riggs
* @see java.io.DataInput
@ -2047,6 +2082,11 @@ public class ObjectInputStream
return result;
}
@SuppressWarnings("preview")
private static boolean isRecord(Class<?> cls) {
return cls.isRecord();
}
/**
* Reads and returns "ordinary" (i.e., not a String, Class,
* ObjectStreamClass, array, or enum constant) object, or null if object's
@ -2085,7 +2125,12 @@ public class ObjectInputStream
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {
final boolean isRecord = cl != null && isRecord(cl) ? true : false;
if (isRecord) {
assert obj == null;
obj = readRecord(desc);
handles.setObject(passHandle, obj);
} else if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
@ -2171,6 +2216,43 @@ public class ObjectInputStream
*/
}
/** Reads a record. */
private Object readRecord(ObjectStreamClass desc) throws IOException {
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
if (slots.length != 1) {
// skip any superclass stream field values
for (int i = 0; i < slots.length-1; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slots[i].hasData) {
defaultReadFields(null, slotDesc);
}
}
}
FieldValues fieldValues = defaultReadFields(null, desc);
// retrieve the canonical constructor
MethodHandle ctrMH = desc.getRecordConstructor();
// bind the stream field values
ctrMH = RecordSupport.bindCtrValues(ctrMH, desc, fieldValues);
try {
return ctrMH.invoke();
} catch (Exception e) {
InvalidObjectException ioe = new InvalidObjectException(e.getMessage());
ioe.initCause(e);
throw ioe;
} catch (Error e) {
throw e;
} catch (Throwable t) {
ObjectStreamException ose = new InvalidObjectException(
"ReflectiveOperationException during deserialization");
ose.initCause(t);
throw ose;
}
}
/**
* Reads (or attempts to skip, if obj is null or is tagged with a
* ClassNotFoundException) instance data for each serializable class of
@ -2317,7 +2399,7 @@ public class ObjectInputStream
}
}
private class FieldValues {
/*package-private*/ class FieldValues {
final byte[] primValues;
final Object[] objValues;