src/java.base/share/classes/java/io/ObjectInputStream.java
Print this page
*** 250,262 ****
/** scratch field for passing handle values up/down call stack */
private int passHandle = NULL_HANDLE;
/** flag set when at end of field value block with no TC_ENDBLOCKDATA */
private boolean defaultDataEnd = false;
- /** buffer for reading primitive field values */
- private byte[] primVals;
-
/** if true, invoke readObjectOverride() instead of readObject() */
private final boolean enableOverride;
/** if true, invoke resolveObject() */
private boolean enableResolve;
--- 250,259 ----
*** 495,505 ****
throw new NotActiveException("not in call to readObject");
}
Object curObj = ctx.getObj();
ObjectStreamClass curDesc = ctx.getDesc();
bin.setBlockDataMode(false);
! defaultReadFields(curObj, curDesc);
bin.setBlockDataMode(true);
if (!curDesc.hasWriteObjectData()) {
/*
* Fix for 4360508: since stream does not contain terminating
* TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
--- 492,506 ----
throw new NotActiveException("not in call to readObject");
}
Object curObj = ctx.getObj();
ObjectStreamClass curDesc = ctx.getDesc();
bin.setBlockDataMode(false);
! FieldValues vals = defaultReadFields(curObj, curDesc);
! if (curObj != null) {
! defaultCheckFieldValues(curObj, curDesc, vals);
! defaultSetFieldValues(curObj, curDesc, vals);
! }
bin.setBlockDataMode(true);
if (!curDesc.hasWriteObjectData()) {
/*
* Fix for 4360508: since stream does not contain terminating
* TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
*** 1876,1885 ****
--- 1877,1906 ----
*/
private void readSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+ // Best effort Failure Atomicity; slotValues will be non-null if field
+ // values can be set after reading all field data in the hierarchy.
+ // Field values can only be set after reading all data if there are no
+ // user observable methods in the hierarchy, readObject(NoData). The
+ // top most Serializable class in the hierarchy can be skipped.
+ FieldValues[] slotValues = null;
+
+ boolean hasSpecialReadMethod = false;
+ for (int i = 1; i < slots.length; i++) {
+ ObjectStreamClass slotDesc = slots[i].desc;
+ if (slotDesc.hasReadObjectMethod()
+ || slotDesc.hasReadObjectNoDataMethod()) {
+ hasSpecialReadMethod = true;
+ break;
+ }
+ }
+ // No special read methods, can store values and defer setting.
+ if (!hasSpecialReadMethod)
+ slotValues = new FieldValues[slots.length];
+
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slots[i].hasData) {
if (obj != null &&
*** 1912,1922 ****
* readObject() method when calling defaultReadObject() or
* readFields(); clear it to restore normal read behavior.
*/
defaultDataEnd = false;
} else {
! defaultReadFields(obj, slotDesc);
}
if (slotDesc.hasWriteObjectData()) {
skipCustomData();
} else {
bin.setBlockDataMode(false);
--- 1933,1949 ----
* readObject() method when calling defaultReadObject() or
* readFields(); clear it to restore normal read behavior.
*/
defaultDataEnd = false;
} else {
! FieldValues vals = defaultReadFields(obj, slotDesc);
! if (slotValues != null) {
! slotValues[i] = vals;
! } else if (obj != null) {
! defaultCheckFieldValues(obj, slotDesc, vals);
! defaultSetFieldValues(obj, slotDesc, vals);
! }
}
if (slotDesc.hasWriteObjectData()) {
skipCustomData();
} else {
bin.setBlockDataMode(false);
*** 1928,1937 ****
--- 1955,1977 ----
{
slotDesc.invokeReadObjectNoData(obj);
}
}
}
+
+ if (obj != null && slotValues != null) {
+ // Check that the non-primitive types are assignable for all slots
+ // before assigning.
+ for (int i = 0; i < slots.length; i++) {
+ if (slotValues[i] != null)
+ defaultCheckFieldValues(obj, slots[i].desc, slotValues[i]);
+ }
+ for (int i = 0; i < slots.length; i++) {
+ if (slotValues[i] != null)
+ defaultSetFieldValues(obj, slots[i].desc, slotValues[i]);
+ }
+ }
}
/**
* Skips over all block data and objects until TC_ENDBLOCKDATA is
* encountered.
*** 1959,2010 ****
break;
}
}
}
/**
* Reads in values of serializable fields declared by given class
! * descriptor. If obj is non-null, sets field values in obj. Expects that
! * passHandle is set to obj's handle before this method is called.
*/
! private void defaultReadFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
int primDataSize = desc.getPrimDataSize();
if (primDataSize > 0) {
- if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
- }
bin.readFully(primVals, 0, primDataSize, false);
- if (obj != null) {
- desc.setPrimFieldValues(obj, primVals);
- }
}
int numObjFields = desc.getNumObjFields();
if (numObjFields > 0) {
int objHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
! Object[] objVals = new Object[numObjFields];
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
ObjectStreamField f = fields[numPrimFields + i];
objVals[i] = readObject0(f.isUnshared());
if (f.getField() != null) {
handles.markDependency(objHandle, passHandle);
}
}
- if (obj != null) {
- desc.setObjFieldValues(obj, objVals);
- }
passHandle = objHandle;
}
}
/**
* Reads in and returns IOException that caused serialization to abort.
* All stream state is discarded prior to reading in fatal exception. Sets
--- 1999,2076 ----
break;
}
}
}
+ private class FieldValues {
+ final byte[] primValues;
+ final Object[] objValues;
+
+ FieldValues(byte[] primValues, Object[] objValues) {
+ this.primValues = primValues;
+ this.objValues = objValues;
+ }
+ }
+
/**
* Reads in values of serializable fields declared by given class
! * descriptor. Expects that passHandle is set to obj's handle before this
! * method is called.
*/
! private FieldValues defaultReadFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
+ byte[] primVals = null;
int primDataSize = desc.getPrimDataSize();
if (primDataSize > 0) {
primVals = new byte[primDataSize];
bin.readFully(primVals, 0, primDataSize, false);
}
+ Object[] objVals = null;
int numObjFields = desc.getNumObjFields();
if (numObjFields > 0) {
int objHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
! objVals = new Object[numObjFields];
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
ObjectStreamField f = fields[numPrimFields + i];
objVals[i] = readObject0(f.isUnshared());
if (f.getField() != null) {
handles.markDependency(objHandle, passHandle);
}
}
passHandle = objHandle;
}
+
+ return new FieldValues(primVals, objVals);
+ }
+
+ /** Throws ClassCastException if any value is not assignable. */
+ private void defaultCheckFieldValues(Object obj, ObjectStreamClass desc,
+ FieldValues values) {
+ Object[] objectValues = values.objValues;
+ if (objectValues != null)
+ desc.checkObjFieldValueTypes(obj, objectValues);
+ }
+
+ /** Sets field values in obj. */
+ private void defaultSetFieldValues(Object obj, ObjectStreamClass desc,
+ FieldValues values) {
+ byte[] primValues = values.primValues;
+ Object[] objectValues = values.objValues;
+
+ if (primValues != null)
+ desc.setPrimFieldValues(obj, primValues);
+ if (objectValues != null)
+ desc.setObjFieldValues(obj, objectValues);
}
/**
* Reads in and returns IOException that caused serialization to abort.
* All stream state is discarded prior to reading in fatal exception. Sets