Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
490 changes: 162 additions & 328 deletions src/java.base/share/classes/java/io/ObjectInputStream.java

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions src/java.base/share/classes/java/io/ObjectOutputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,7 @@ private void writeOrdinaryObject(Object obj,
if (desc.isRecord()) {
writeRecordData(obj, desc);
} else if (desc.isExternalizable() && !desc.isProxy()) {
if (desc.isValue())
if (desc.isValueOrStrictInit())
throw new InvalidClassException("Externalizable not valid for value class "
+ desc.forClass().getName());
writeExternalData((Externalizable) obj);
Expand Down Expand Up @@ -1401,10 +1401,10 @@ private void writeRecordData(Object obj, ObjectStreamClass desc)
throws IOException
{
assert obj.getClass().isRecord();
List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
if (slots.size() != 1) {
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
if (slots.length != 1) {
throw new InvalidClassException(
"expected a single record slot length, but found: " + slots.size());
"expected a single record slot length, but found: " + slots.length);
}

defaultWriteFields(obj, desc); // #### seems unnecessary to use the accessors
Expand All @@ -1417,9 +1417,9 @@ private void writeRecordData(Object obj, ObjectStreamClass desc)
private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
for (int i = 0; i < slots.size(); i++) {
ObjectStreamClass slotDesc = slots.get(i).desc;
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slotDesc.hasWriteObjectMethod()) {
PutFieldImpl oldPut = curPut;
curPut = null;
Expand Down
359 changes: 119 additions & 240 deletions src/java.base/share/classes/java/io/ObjectStreamClass.java

Large diffs are not rendered by default.

21 changes: 2 additions & 19 deletions src/java.base/share/classes/java/io/ObjectStreamField.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ public class ObjectStreamField
private final Field field;
/** offset of field value in enclosing field group */
private int offset;
/** index of the field in the class, retain the declaration order of serializable fields */
private final int argIndex;

/**
* Create a Serializable field with the specified type. This field should
Expand Down Expand Up @@ -86,11 +84,6 @@ public ObjectStreamField(String name, Class<?> type) {
* @since 1.4
*/
public ObjectStreamField(String name, Class<?> type, boolean unshared) {
this(name, type, unshared, -1);
}

/* package-private */
ObjectStreamField(String name, Class<?> type, boolean unshared, int argIndex) {
if (name == null) {
throw new NullPointerException();
}
Expand All @@ -99,22 +92,20 @@ public ObjectStreamField(String name, Class<?> type, boolean unshared) {
this.unshared = unshared;
this.field = null;
this.signature = null;
this.argIndex = argIndex;
}

/**
* Creates an ObjectStreamField representing a field with the given name,
* signature and unshared setting.
*/
ObjectStreamField(String name, String signature, boolean unshared, int argIndex) {
ObjectStreamField(String name, String signature, boolean unshared) {
if (name == null) {
throw new NullPointerException();
}
this.name = name;
this.signature = signature.intern();
this.unshared = unshared;
this.field = null;
this.argIndex = argIndex;

type = switch (signature.charAt(0)) {
case 'Z' -> Boolean.TYPE;
Expand All @@ -138,14 +129,13 @@ public ObjectStreamField(String name, Class<?> type, boolean unshared) {
* ObjectStreamField (if non-primitive) will return Object.class (as
* opposed to a more specific reference type).
*/
ObjectStreamField(Field field, boolean unshared, boolean showType, int argIndex) {
ObjectStreamField(Field field, boolean unshared, boolean showType) {
this.field = field;
this.unshared = unshared;
name = field.getName();
Class<?> ftype = field.getType();
type = (showType || ftype.isPrimitive()) ? ftype : Object.class;
signature = ftype.descriptorString().intern();
this.argIndex = argIndex;
}

/**
Expand Down Expand Up @@ -226,13 +216,6 @@ protected void setOffset(int offset) {
this.offset = offset;
}

/**
* {@return Index of the field in the sequence of Serializable fields}
*/
int getArgIndex() {
return argIndex;
}

/**
* Return true if this field has a primitive type.
*
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Boolean.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public boolean booleanValue() {
* @since 1.4
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Boolean valueOf(boolean b) {
if (!PreviewFeatures.isEnabled()) {
return (b ? TRUE : FALSE);
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Byte.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private ByteCache() {}
* @since 1.5
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Byte valueOf(byte b) {
if (!PreviewFeatures.isEnabled()) {
final int offset = 128;
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Character.java
Original file line number Diff line number Diff line change
Expand Up @@ -9485,7 +9485,7 @@ private CharacterCache(){}
* @since 1.5
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Character valueOf(char c) {
if (!PreviewFeatures.isEnabled()) {
if (c <= 127) { // must cache
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Double.java
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ public static Double valueOf(String s) throws NumberFormatException {
* @since 1.5
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Double valueOf(double d) {
return new Double(d);
}
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Float.java
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ public static Float valueOf(String s) throws NumberFormatException {
* @since 1.5
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Float valueOf(float f) {
return new Float(f);
}
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Integer.java
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ private IntegerCache() {}
* @since 1.5
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Integer valueOf(int i) {
if (!PreviewFeatures.isEnabled()) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Long.java
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ private LongCache() {}
* @since 1.5
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Long valueOf(long l) {
if (!PreviewFeatures.isEnabled()) {
if (l >= -128 && l <= 127) { // will cache
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Short.java
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ private ShortCache() {}
* @since 1.5
*/
@IntrinsicCandidate
@DeserializeConstructor
@DeserializeConstructor("value")
public static Short valueOf(short s) {
if (!PreviewFeatures.isEnabled()) {
final int offset = 128;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@
* The annotation is used by java.io.ObjectStreamClass to select the constructor
* or factory method to create objects from a stream.
*
* @since 24
* @since Valhalla
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, METHOD})
public @interface DeserializeConstructor {
/// Identifies the serial field names for the method parameters.
/// The serial field type are the corresponding parameter types.
String[] value();
}
30 changes: 30 additions & 0 deletions src/java.base/share/classes/jdk/internal/value/ValueClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.classfile.ClassFile.ACC_STRICT_INIT;

/**
* Utilities to access package private methods of java.lang.Class and related reflection classes.
*/
Expand Down Expand Up @@ -139,4 +142,31 @@ public static Object[] copyOfRangeSpecialArray(Object[] array, int from, int to)
*/
@IntrinsicCandidate
public static native boolean isAtomicArray(Object[] array);

// This class also serves as a lazy holder of its singleton instance
private static final class StrictInstanceFieldClassValue extends ClassValue<Boolean> {
private static final StrictInstanceFieldClassValue INSTANCE = new StrictInstanceFieldClassValue();

private StrictInstanceFieldClassValue() {}

@Override
protected Boolean computeValue(Class<?> type) {
if ((type.getModifiers() & (Modifier.ABSTRACT | Modifier.FINAL)) == (Modifier.ABSTRACT | Modifier.FINAL)) {
// Not class or interface
return false;
}
for (var field : type.getDeclaredFields()) {
// Reflection filters fields, hope the filtered classes don't declare strict fields
if ((field.getModifiers() & (ACC_STATIC | ACC_STRICT_INIT)) == ACC_STRICT_INIT) {
return true;
}
}
return false;
}
}

/// Returns whether a class or interface declares strict instance fields.
public static boolean hasStrictInstanceField(Class<?> cl) {
return StrictInstanceFieldClassValue.INSTANCE.get(cl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1003,14 +1003,14 @@ public String expand(String optParameter) {
enum ObjectConstructorFragment implements ComboParameter, CodeShapePredicate {
NONE(""),
ANNOTATED_OBJECT_CONSTRUCTOR_FRAGMENT("""
@DeserializeConstructor
@DeserializeConstructor({"f1", "f2"})
#{CLASSACCESS} #{TESTNAME}(#{FIELD[0]} f1, #{FIELD[1]} f2) {
this.f1 = f1;
this.f2 = f2;
#{FIELD_CONSTRUCTOR_ADDITIONS}
}

@DeserializeConstructor
@DeserializeConstructor({"f1", "f2"})
#{CLASSACCESS} #{TESTNAME}(#{FIELD[0]} f1, #{FIELD[1]} f2, int fExtra) {
this.f1 = f1;
this.f2 = f2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ static value class TreeV implements Tree, Serializable {
private TreeV left;
private TreeV right;

@DeserializeConstructor
@DeserializeConstructor({"left", "right"})
TreeV(TreeV left, TreeV right) {
this.left = left;
this.right = right;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public void implementSerializable(Object obj) throws IOException, ClassNotFoundE
static value class SerializablePoint implements Serializable {
public int x;
public int y;
@DeserializeConstructor
@DeserializeConstructor({"x", "y"})
private SerializablePoint(int x, int y) { this.x = x; this.y = y; }

@Override public String toString() {
Expand All @@ -173,7 +173,7 @@ static value class SerializablePoint implements Serializable {
/* A Serializable Foo, with a serial proxy */
static value class SerializableFoo implements Serializable {
public int x;
@DeserializeConstructor
@DeserializeConstructor("x")
SerializableFoo(int x) { this.x = x; }

@Serial Object writeReplace() throws ObjectStreamException {
Expand Down