Methods Summary |
---|
protected void | annotateClass(java.lang.Class aClass)Writes optional information for class {@code aClass} to the output
stream. This optional data can be read when deserializing the class
descriptor (ObjectStreamClass) for this class from an input stream. By
default, no extra data is saved.
// By default no extra info is saved. Subclasses can override
|
protected void | annotateProxyClass(java.lang.Class aClass)Writes optional information for a proxy class to the target stream. This
optional data can be read when deserializing the proxy class from an
input stream. By default, no extra data is saved.
// By default no extra info is saved. Subclasses can override
|
private void | checkWritePrimitiveTypes()Do the necessary work to see if the receiver can be used to write
primitive types like int, char, etc.
if (primitiveTypes == null) {
// If we got here we have no Stream previously created
// WARNING - if the stream does not grow, this code is wrong
primitiveTypesBuffer = new ByteArrayOutputStream(128);
primitiveTypes = new DataOutputStream(primitiveTypesBuffer);
}
|
public void | close()Closes this stream. Any buffered data is flushed. This implementation
closes the target stream.
// First flush what is needed (primitive data, etc)
flush();
output.close();
|
private void | computePutField()Computes the collection of emulated fields that users can manipulate to
store a representation different than the one declared by the class of
the object being dumped.
currentPutField = new EmulatedFieldsForDumping(currentClass);
|
public void | defaultWriteObject()Default method to write objects to this stream. Serializable fields
defined in the object's class and superclasses are written to the output
stream.
// We can't be called from just anywhere. There are rules.
if (currentObject == null) {
throw new NotActiveException();
}
writeFieldValues(currentObject, currentClass);
|
protected void | drain()Writes buffered data to the target stream. This is similar to {@code
flush} but the flush is not propagated to the target stream.
if (primitiveTypes == null) {
return;
}
// If we got here we have a Stream previously created
int offset = 0;
byte[] written = primitiveTypesBuffer.toByteArray();
// Normalize the primitive data
while (offset < written.length) {
int toWrite = written.length - offset > 1024 ? 1024
: written.length - offset;
if (toWrite < 256) {
output.writeByte(TC_BLOCKDATA);
output.writeByte((byte) toWrite);
} else {
output.writeByte(TC_BLOCKDATALONG);
output.writeInt(toWrite);
}
// write primitive types we had and the marker of end-of-buffer
output.write(written, offset, toWrite);
offset += toWrite;
}
// and now we're clean to a state where we can write an object
primitiveTypes = null;
primitiveTypesBuffer = null;
|
private java.lang.Integer | dumpCycle(java.lang.Object obj)Dumps the parameter {@code obj} only if it is {@code null}
or an object that has already been dumped previously.
// If the object has been saved already, save its handle only
Integer handle = registeredObjectHandleFor(obj);
if (handle != null) {
writeCyclicReference(handle);
return handle;
}
return null;
|
protected boolean | enableReplaceObject(boolean enable)Enables object replacement for this stream. By default this is not
enabled. Only trusted subclasses (loaded with system class loader) are
allowed to change this status.
if (enable) {
// The Stream has to be trusted for this feature to be enabled.
// trusted means the stream's classloader has to be null
SecurityManager currentManager = System.getSecurityManager();
if (currentManager != null) {
currentManager.checkPermission(SUBSTITUTION_PERMISSION);
}
}
boolean originalValue = enableReplace;
enableReplace = enable;
return originalValue;
|
public void | flush()Writes buffered data to the target stream and calls the {@code flush}
method of the target stream.
drain();
output.flush();
|
private static native boolean | getFieldBool(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
a boolean.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native byte | getFieldByte(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
a byte
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native char | getFieldChar(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
a char.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native double | getFieldDouble(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
a double.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native float | getFieldFloat(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
a float.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native int | getFieldInt(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
an int.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native long | getFieldLong(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
a long.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native java.lang.Object | getFieldObj(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, java.lang.String fieldTypeName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
an Object type whose name is {@code fieldTypeName}.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private static native short | getFieldShort(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)Get the value of field named
{@code fieldName of object instance}. The
field is declared by class {@code declaringClass}. The field is supposed to be
a short.
This method could be implemented non-natively on top of java.lang.reflect implementations
that support the {@code setAccessible} API, at the expense of extra object creation
(java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
by the use of a native method like this one.
|
private int | nextHandle()Return the next {@code int} handle to be used to indicate cyclic
references being saved to the stream.
return this.currentHandle++;
|
public java.io.ObjectOutputStream$PutField | putFields()Gets this stream's {@code PutField} object. This object provides access
to the persistent fields that are eventually written to the output
stream. It is used to transfer the values from the fields of the object
that is currently being written to the persistent fields.
// We can't be called from just anywhere. There are rules.
if (currentObject == null) {
throw new NotActiveException();
}
if (currentPutField == null) {
computePutField();
}
return currentPutField;
|
private java.lang.Integer | registerObjectWritten(java.lang.Object obj)Assume object {@code obj} has not been dumped yet, and assign a
handle to it
Integer handle = Integer.valueOf(nextHandle());
registerObjectWritten(obj, handle);
return handle;
|
private void | registerObjectWritten(java.lang.Object obj, java.lang.Integer handle)Assume object {@code obj} has not been dumped yet, and assign a
handle to it, {@code handle}.
objectsWritten.put(obj, handle);
|
private java.lang.Integer | registeredObjectHandleFor(java.lang.Object obj)Return the {@code Integer} handle used to tag object
{@code obj} as an instance that has been dumped already. Return
{@code null} if object {@code obj} has not been saved yet.
return objectsWritten.get(obj);
|
private void | removeUnsharedReference(java.lang.Object obj, java.lang.Integer previousHandle)Remove the unshared object from the table, and restore any previous
handle.
if (previousHandle != null) {
registerObjectWritten(obj, previousHandle);
} else {
objectsWritten.remove(obj);
}
|
protected java.lang.Object | replaceObject(java.lang.Object object)Allows trusted subclasses to substitute the specified original {@code
object} with a new object. Object substitution has to be activated first
with calling {@code enableReplaceObject(true)}. This implementation just
returns {@code object}.
// By default no object replacement. Subclasses can override
return object;
|
public void | reset()Resets the state of this stream. A marker is written to the stream, so
that the corresponding input stream will also perform a reset at the same
point. Objects previously written are no longer remembered, so they will
be written again (instead of a cyclical reference) if found in the object
graph.
// First we flush what we have
drain();
/*
* And dump a reset marker, so that the ObjectInputStream can reset
* itself at the same point
*/
output.writeByte(TC_RESET);
// Now we reset ourselves
resetState();
|
private void | resetSeenObjects()Reset the collection of objects already dumped by the receiver. If the
objects are found again in the object graph, the receiver will dump them
again, instead of a handle (cyclic reference).
objectsWritten = new IdentityHashMap<Object, Integer>();
currentHandle = baseWireHandle;
|
private void | resetState()Reset the receiver. The collection of objects already dumped by the
receiver is reset, and internal structures are also reset so that the
receiver knows it is in a fresh clean state.
resetSeenObjects();
nestedLevels = 0;
|
public void | useProtocolVersion(int version)Sets the specified protocol version to be used by this stream.
if (version != ObjectStreamConstants.PROTOCOL_VERSION_1
&& version != ObjectStreamConstants.PROTOCOL_VERSION_2) {
throw new IllegalArgumentException(org.apache.harmony.luni.util.Msg
.getString("K00b3", version)); //$NON-NLS-1$
}
protocolVersion = version;
|
public void | write(byte[] buffer)Writes the entire contents of the byte array {@code buffer} to the output
stream. Blocks until all bytes are written.
checkWritePrimitiveTypes();
primitiveTypes.write(buffer);
|
public void | write(byte[] buffer, int offset, int length)Writes {@code count} bytes from the byte array {@code buffer} starting at
offset {@code index} to the target stream. Blocks until all bytes are
written.
checkWritePrimitiveTypes();
primitiveTypes.write(buffer, offset, length);
|
public void | write(int value)Writes a single byte to the target stream. Only the least significant
byte of the integer {@code value} is written to the stream. Blocks until
the byte is actually written.
checkWritePrimitiveTypes();
primitiveTypes.write(value);
|
public void | writeBoolean(boolean value)Writes a boolean to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeBoolean(value);
|
public void | writeByte(int value)Writes a byte (8 bit) to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeByte(value);
|
public void | writeBytes(java.lang.String value)Writes the string {@code value} as a sequence of bytes to the target
stream. Only the least significant byte of each character in the string
is written.
checkWritePrimitiveTypes();
primitiveTypes.writeBytes(value);
|
public void | writeChar(int value)Writes a character (16 bit) to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeChar(value);
|
public void | writeChars(java.lang.String value)Writes the string {@code value} as a sequence of characters to the target
stream.
checkWritePrimitiveTypes();
primitiveTypes.writeChars(value);
|
private java.lang.Integer | writeClassDesc(java.io.ObjectStreamClass classDesc, boolean unshared)Write a class descriptor {@code classDesc} (an
{@code ObjectStreamClass}) to the stream.
if (classDesc == null) {
writeNull();
return null;
}
Integer handle = null;
if (!unshared) {
handle = dumpCycle(classDesc);
}
if (handle == null) {
Class<?> classToWrite = classDesc.forClass();
Integer previousHandle = objectsWritten.get(classDesc);
// If we got here, it is a new (non-null) classDesc that will have
// to be registered as well
handle = registerObjectWritten(classDesc);
if (Proxy.isProxyClass(classToWrite)) {
output.writeByte(TC_PROXYCLASSDESC);
Class<?>[] interfaces = classToWrite.getInterfaces();
output.writeInt(interfaces.length);
for (int i = 0; i < interfaces.length; i++) {
output.writeUTF(interfaces[i].getName());
}
annotateProxyClass(classToWrite);
output.writeByte(TC_ENDBLOCKDATA);
writeClassDescForClass(Proxy.class);
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(classDesc, previousHandle);
}
return handle;
}
output.writeByte(TC_CLASSDESC);
if (protocolVersion == PROTOCOL_VERSION_1) {
writeNewClassDesc(classDesc);
} else {
// So write...() methods can be used by
// subclasses during writeClassDescriptor()
primitiveTypes = output;
writeClassDescriptor(classDesc);
primitiveTypes = null;
}
// Extra class info (optional)
annotateClass(classToWrite);
drain(); // flush primitive types in the annotation
output.writeByte(TC_ENDBLOCKDATA);
writeClassDesc(classDesc.getSuperclass(), unshared);
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(classDesc, previousHandle);
}
}
return handle;
|
private java.lang.Integer | writeClassDescForClass(java.lang.Class objClass)Writes a class descriptor (an {@code ObjectStreamClass}) that
corresponds to the {@code java.lang.Class objClass} to the stream.
return writeClassDesc(ObjectStreamClass.lookup(objClass), false);
|
protected void | writeClassDescriptor(java.io.ObjectStreamClass classDesc)Writes a class descriptor to the target stream.
writeNewClassDesc(classDesc);
|
private void | writeCyclicReference(java.lang.Integer handle)Writes a handle representing a cyclic reference (object previously
dumped).
output.writeByte(TC_REFERENCE);
output.writeInt(handle.intValue());
|
public void | writeDouble(double value)Writes a double (64 bit) to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeDouble(value);
|
private java.io.ObjectStreamClass | writeEnumDesc(java.lang.Class theClass, boolean unshared)
// write classDesc, classDesc for enum is different
ObjectStreamClass classDesc = ObjectStreamClass.lookup(theClass);
// set flag for enum, the flag is (SC_SERIALIZABLE | SC_ENUM)
classDesc.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
Integer previousHandle = objectsWritten.get(classDesc);
Integer handle = null;
if (!unshared) {
handle = dumpCycle(classDesc);
}
if (handle == null) {
Class<?> classToWrite = classDesc.forClass();
// If we got here, it is a new (non-null) classDesc that will have
// to be registered as well
registerObjectWritten(classDesc);
output.writeByte(TC_CLASSDESC);
if (protocolVersion == PROTOCOL_VERSION_1) {
writeNewClassDesc(classDesc);
} else {
// So write...() methods can be used by
// subclasses during writeClassDescriptor()
primitiveTypes = output;
writeClassDescriptor(classDesc);
primitiveTypes = null;
}
// Extra class info (optional)
annotateClass(classToWrite);
drain(); // flush primitive types in the annotation
output.writeByte(TC_ENDBLOCKDATA);
// write super class
ObjectStreamClass superClass = classDesc.getSuperclass();
if (null != superClass) {
// super class is also enum
superClass.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
writeEnumDesc(superClass.forClass(), unshared);
} else {
output.writeByte(TC_NULL);
}
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(classDesc, previousHandle);
}
}
return classDesc;
|
private void | writeFieldDescriptors(java.io.ObjectStreamClass classDesc, boolean externalizable)Writes a collection of field descriptors (name, type name, etc) for the
class descriptor {@code classDesc} (an
{@code ObjectStreamClass})
Class<?> loadedClass = classDesc.forClass();
ObjectStreamField[] fields = null;
int fieldCount = 0;
// The fields of String are not needed since Strings are treated as
// primitive types
if (!externalizable && loadedClass != ObjectStreamClass.STRINGCLASS) {
fields = classDesc.fields();
fieldCount = fields.length;
}
// Field count
output.writeShort(fieldCount);
// Field names
for (int i = 0; i < fieldCount; i++) {
ObjectStreamField f = fields[i];
output.writeByte(f.getTypeCode());
output.writeUTF(f.getName());
if (!f.isPrimitive()) {
writeObject(f.getTypeString());
}
}
|
private void | writeFieldValues(EmulatedFieldsForDumping emulatedFields)Writes a collection of field values for the emulated fields
{@code emulatedFields}
EmulatedFields accessibleSimulatedFields = emulatedFields
.emulatedFields(); // Access internal fields which we can
// set/get. Users can't do this.
EmulatedFields.ObjectSlot[] slots = accessibleSimulatedFields.slots();
for (int i = 0; i < slots.length; i++) {
EmulatedFields.ObjectSlot slot = slots[i];
Object fieldValue = slot.getFieldValue();
Class<?> type = slot.getField().getType();
// WARNING - default values exist for each primitive type
if (type == Integer.TYPE) {
output.writeInt(fieldValue != null ? ((Integer) fieldValue)
.intValue() : 0);
} else if (type == Byte.TYPE) {
output.writeByte(fieldValue != null ? ((Byte) fieldValue)
.byteValue() : (byte) 0);
} else if (type == Character.TYPE) {
output.writeChar(fieldValue != null ? ((Character) fieldValue)
.charValue() : (char) 0);
} else if (type == Short.TYPE) {
output.writeShort(fieldValue != null ? ((Short) fieldValue)
.shortValue() : (short) 0);
} else if (type == Boolean.TYPE) {
output.writeBoolean(fieldValue != null ? ((Boolean) fieldValue)
.booleanValue() : false);
} else if (type == Long.TYPE) {
output.writeLong(fieldValue != null ? ((Long) fieldValue)
.longValue() : (long) 0);
} else if (type == Float.TYPE) {
output.writeFloat(fieldValue != null ? ((Float) fieldValue)
.floatValue() : (float) 0);
} else if (type == Double.TYPE) {
output.writeDouble(fieldValue != null ? ((Double) fieldValue)
.doubleValue() : (double) 0);
} else {
// Either array or Object
writeObject(fieldValue);
}
}
|
private void | writeFieldValues(java.lang.Object obj, java.io.ObjectStreamClass classDesc)Writes a collection of field values for the fields described by class
descriptor {@code classDesc} (an {@code ObjectStreamClass}).
This is the default mechanism, when emulated fields (an
{@code PutField}) are not used. Actual values to dump are fetched
directly from object {@code obj}.
ObjectStreamField[] fields = classDesc.fields();
Class<?> declaringClass = classDesc.forClass();
for (int i = 0; i < fields.length; i++) {
try {
// Code duplication starts, just because Java is typed
ObjectStreamField fieldDesc = fields[i];
if (fieldDesc.isPrimitive()) {
switch (fieldDesc.getTypeCode()) {
case 'B":
output.writeByte(getFieldByte(obj, declaringClass,
fieldDesc.getName()));
break;
case 'C":
output.writeChar(getFieldChar(obj, declaringClass,
fieldDesc.getName()));
break;
case 'D":
output.writeDouble(getFieldDouble(obj,
declaringClass, fieldDesc.getName()));
break;
case 'F":
output.writeFloat(getFieldFloat(obj,
declaringClass, fieldDesc.getName()));
break;
case 'I":
output.writeInt(getFieldInt(obj, declaringClass,
fieldDesc.getName()));
break;
case 'J":
output.writeLong(getFieldLong(obj, declaringClass,
fieldDesc.getName()));
break;
case 'S":
output.writeShort(getFieldShort(obj,
declaringClass, fieldDesc.getName()));
break;
case 'Z":
output.writeBoolean(getFieldBool(obj,
declaringClass, fieldDesc.getName()));
break;
default:
throw new IOException(
org.apache.harmony.luni.util.Msg.getString(
"K00d5", fieldDesc.getTypeCode())); //$NON-NLS-1$
}
} else {
// Object type (array included).
Object field = getFieldObj(obj, declaringClass, fieldDesc
.getName(), fieldDesc.getTypeString());
if (fieldDesc.isUnshared()) {
writeUnshared(field);
} else {
writeObject(field);
}
}
} catch (NoSuchFieldError nsf) {
// The user defined serialPersistentFields but did not provide
// the glue to transfer values,
// (in writeObject) so we end up using the default mechanism and
// fail to set the emulated field
throw new InvalidClassException(classDesc.getName());
}
}
|
public void | writeFields()Writes the fields of the object currently being written to the target
stream. The field values are buffered in the currently active {@code
PutField} object, which can be accessed by calling {@code putFields()}.
// Has to have fields to write
if (currentPutField == null) {
throw new NotActiveException();
}
writeFieldValues(currentPutField);
|
public void | writeFloat(float value)Writes a float (32 bit) to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeFloat(value);
|
private void | writeHierarchy(java.lang.Object object, java.io.ObjectStreamClass classDesc)Walks the hierarchy of classes described by class descriptor
{@code classDesc} and writes the field values corresponding to
fields declared by the corresponding class descriptor. The instance to
fetch field values from is {@code object}. If the class
(corresponding to class descriptor {@code classDesc}) defines
private instance method {@code writeObject} it will be used to
dump field values.
// We can't be called from just anywhere. There are rules.
if (object == null) {
throw new NotActiveException();
}
// Fields are written from class closest to Object to leaf class
// (down the chain)
if (classDesc.getSuperclass() != null) {
// first
writeHierarchy(object, classDesc.getSuperclass());
}
// Have to do this before calling defaultWriteObject or anything
// that calls defaultWriteObject
currentObject = object;
currentClass = classDesc;
// See if the object has a writeObject method. If so, run it
boolean executed = false;
Class<?> targetClass = classDesc.forClass();
try {
final Method method = ObjectStreamClass
.getPrivateWriteObjectMethod(targetClass);
if (method != null) {
// We have to be able to fetch its value, even if it is
// private
AccessController.doPrivileged(new PriviAction<Object>(method));
try {
method.invoke(object, new Object[] { this });
executed = true;
} catch (InvocationTargetException e) {
Throwable ex = e.getTargetException();
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
} else if (ex instanceof Error) {
throw (Error) ex;
}
throw (IOException) ex;
} catch (IllegalAccessException e) {
throw new RuntimeException(e.toString());
}
}
if (executed) {
drain();
output.writeByte(TC_ENDBLOCKDATA);
} else {
// If the object did not have a writeMethod, call
// defaultWriteObject
defaultWriteObject();
}
} finally {
// Cleanup, needs to run always so that we can later detect
// invalid calls to defaultWriteObject
currentObject = null;
currentClass = null;
currentPutField = null;
}
|
public void | writeInt(int value)Writes an integer (32 bit) to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeInt(value);
|
public void | writeLong(long value)Writes a long (64 bit) to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeLong(value);
|
private java.lang.Integer | writeNewArray(java.lang.Object array, java.lang.Class arrayClass, java.lang.Class componentType, boolean unshared)Write array {@code array} of class {@code arrayClass} with
component type {@code componentType} into the receiver. It is
assumed the array has not been dumped yet. Return an {@code Integer}
that represents the handle for this object (array) which is dumped here.
output.writeByte(TC_ARRAY);
writeClassDescForClass(arrayClass);
Integer previousHandle = objectsWritten.get(array);
Integer handle = registerObjectWritten(array);
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(array, previousHandle);
}
// Now we have code duplication just because Java is typed. We have to
// write N elements and assign to array positions, but we must typecast
// the array first, and also call different methods depending on the
// elements.
if (componentType.isPrimitive()) {
if (componentType == Integer.TYPE) {
int[] intArray = (int[]) array;
output.writeInt(intArray.length);
for (int i = 0; i < intArray.length; i++) {
output.writeInt(intArray[i]);
}
} else if (componentType == Byte.TYPE) {
byte[] byteArray = (byte[]) array;
output.writeInt(byteArray.length);
output.write(byteArray, 0, byteArray.length);
} else if (componentType == Character.TYPE) {
char[] charArray = (char[]) array;
output.writeInt(charArray.length);
for (int i = 0; i < charArray.length; i++) {
output.writeChar(charArray[i]);
}
} else if (componentType == Short.TYPE) {
short[] shortArray = (short[]) array;
output.writeInt(shortArray.length);
for (int i = 0; i < shortArray.length; i++) {
output.writeShort(shortArray[i]);
}
} else if (componentType == Boolean.TYPE) {
boolean[] booleanArray = (boolean[]) array;
output.writeInt(booleanArray.length);
for (int i = 0; i < booleanArray.length; i++) {
output.writeBoolean(booleanArray[i]);
}
} else if (componentType == Long.TYPE) {
long[] longArray = (long[]) array;
output.writeInt(longArray.length);
for (int i = 0; i < longArray.length; i++) {
output.writeLong(longArray[i]);
}
} else if (componentType == Float.TYPE) {
float[] floatArray = (float[]) array;
output.writeInt(floatArray.length);
for (int i = 0; i < floatArray.length; i++) {
output.writeFloat(floatArray[i]);
}
} else if (componentType == Double.TYPE) {
double[] doubleArray = (double[]) array;
output.writeInt(doubleArray.length);
for (int i = 0; i < doubleArray.length; i++) {
output.writeDouble(doubleArray[i]);
}
} else {
throw new InvalidClassException(
org.apache.harmony.luni.util.Msg.getString(
"K00d7", arrayClass.getName())); //$NON-NLS-1$
}
} else {
// Array of Objects
Object[] objectArray = (Object[]) array;
output.writeInt(objectArray.length);
for (int i = 0; i < objectArray.length; i++) {
writeObject(objectArray[i]);
}
}
return handle;
|
private java.lang.Integer | writeNewClass(java.lang.Class object, boolean unshared)Write class {@code object} into the receiver. It is assumed the
class has not been dumped yet. Classes are not really dumped, but a class
descriptor ({@code ObjectStreamClass}) that corresponds to them.
Return an {@code Integer} that represents the handle for this
object (class) which is dumped here.
output.writeByte(TC_CLASS);
// Instances of java.lang.Class are always Serializable, even if their
// instances aren't (e.g. java.lang.Object.class).
// We cannot call lookup because it returns null if the parameter
// represents instances that cannot be serialized, and that is not what
// we want.
// The handle for the classDesc is NOT the handle for the class object
// being dumped. We must allocate a new handle and return it.
if (object.isEnum()) {
writeEnumDesc(object, unshared);
} else {
writeClassDesc(ObjectStreamClass.lookupStreamClass(object),
unshared);
}
Integer previousHandle = objectsWritten.get(object);
Integer handle = registerObjectWritten(object);
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(object, previousHandle);
}
return handle;
|
private void | writeNewClassDesc(java.io.ObjectStreamClass classDesc)Write class descriptor {@code classDesc} into the receiver. It is
assumed the class descriptor has not been dumped yet. The class
descriptors for the superclass chain will be dumped as well. Return an
{@code Integer} that represents the handle for this object (class
descriptor) which is dumped here.
output.writeUTF(classDesc.getName());
output.writeLong(classDesc.getSerialVersionUID());
byte flags = classDesc.getFlags();
boolean externalizable = false;
externalizable = ObjectStreamClass.isExternalizable(classDesc
.forClass());
if (protocolVersion != PROTOCOL_VERSION_1) {
// Change for 1.2. Objects can be saved in old format
// (PROTOCOL_VERSION_1) or in the 1.2 format (PROTOCOL_VERSION_2).
// Nested "if" check to optimize checking. Second check is more
// expensive.
if (externalizable) {
flags |= SC_BLOCK_DATA;
}
}
output.writeByte(flags);
if ((SC_ENUM | SC_SERIALIZABLE) != classDesc.getFlags()) {
writeFieldDescriptors(classDesc, externalizable);
} else {
// enum write no fields
output.writeShort(0);
}
|
private java.lang.Integer | writeNewEnum(java.lang.Object object, java.lang.Class theClass, boolean unshared)
// write new Enum
EmulatedFieldsForDumping originalCurrentPutField = currentPutField; // save
// null it, to make sure one will be computed if needed
currentPutField = null;
output.writeByte(TC_ENUM);
while (theClass != null && !theClass.isEnum()) {
// write enum only
theClass = theClass.getSuperclass();
}
ObjectStreamClass classDesc = writeEnumDesc(theClass, unshared);
Integer previousHandle = objectsWritten.get(object);
Integer handle = registerObjectWritten(object);
ObjectStreamField[] fields = classDesc.getSuperclass().fields();
Class<?> declaringClass = classDesc.getSuperclass().forClass();
// Only write field "name" for enum class, which is the second field of
// enum, that is fields[1]. Ignore all non-fields and fields.length < 2
if (null != fields && fields.length > 1) {
String str = (String) getFieldObj(object, declaringClass, fields[1]
.getName(), fields[1].getTypeString());
Integer strhandle = null;
if (!unshared) {
strhandle = dumpCycle(str);
}
if (null == strhandle) {
writeNewString(str, unshared);
}
}
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(object, previousHandle);
}
currentPutField = originalCurrentPutField;
return handle;
|
private void | writeNewException(java.lang.Exception ex)Write exception {@code ex} into the receiver. It is assumed the
exception has not been dumped yet. Return an {@code Integer} that
represents the handle for this object (exception) which is dumped here.
This is used to dump the exception instance that happened (if any) when
dumping the original object graph. The set of seen objects will be reset
just before and just after dumping this exception object.
When exceptions are found normally in the object graph, they are dumped
as a regular object, and not by this method. In that case, the set of
"known objects" is not reset.
output.writeByte(TC_EXCEPTION);
resetSeenObjects();
writeObjectInternal(ex, false, false, false); // No replacements
resetSeenObjects();
|
private java.lang.Integer | writeNewObject(java.lang.Object object, java.lang.Class theClass, boolean unshared)Write object {@code object} of class {@code theClass} into
the receiver. It is assumed the object has not been dumped yet. Return an
{@code Integer} that represents the handle for this object which
is dumped here.
If the object implements {@code Externalizable} its
{@code writeExternal} is called. Otherwise, all fields described
by the class hierarchy is dumped. Each class can define how its declared
instance fields are dumped by defining a private method
{@code writeObject}
// Not String, not null, not array, not cyclic reference
EmulatedFieldsForDumping originalCurrentPutField = currentPutField; // save
currentPutField = null; // null it, to make sure one will be computed if
// needed
boolean externalizable = ObjectStreamClass.isExternalizable(theClass);
boolean serializable = ObjectStreamClass.isSerializable(theClass);
if (!externalizable && !serializable) {
// Object is neither externalizable nor serializable. Error
throw new NotSerializableException(theClass.getName());
}
// Either serializable or externalizable, now we can save info
output.writeByte(TC_OBJECT);
writeClassDescForClass(theClass);
Integer previousHandle = objectsWritten.get(object);
Integer handle = registerObjectWritten(object);
// This is how we know what to do in defaultWriteObject. And it is also
// used by defaultWriteObject to check if it was called from an invalid
// place.
// It allows writeExternal to call defaultWriteObject and have it work.
currentObject = object;
currentClass = ObjectStreamClass.lookup(theClass);
try {
if (externalizable) {
boolean noBlockData = protocolVersion == PROTOCOL_VERSION_1;
if (noBlockData) {
primitiveTypes = output;
}
// Object is externalizable, just call its own method
((Externalizable) object).writeExternal(this);
if (noBlockData) {
primitiveTypes = null;
} else {
// Similar to the code in writeHierarchy when object
// implements writeObject.
// Any primitive data has to be flushed and a tag must be
// written
drain();
output.writeByte(TC_ENDBLOCKDATA);
}
} else { // If it got here, it has to be Serializable
// Object is serializable. Walk the class chain writing the
// fields
writeHierarchy(object, currentClass);
}
} finally {
// Cleanup, needs to run always so that we can later detect invalid
// calls to defaultWriteObject
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(object, previousHandle);
}
currentObject = null;
currentClass = null;
currentPutField = originalCurrentPutField;
}
return handle;
|
private java.lang.Integer | writeNewString(java.lang.String object, boolean unshared)Write String {@code object} into the receiver. It is assumed the
String has not been dumped yet. Return an {@code Integer} that
represents the handle for this object (String) which is dumped here.
Strings are saved encoded with {@link DataInput modified UTF-8}.
long count = output.countUTFBytes(object);
if (count <= 0xffff) {
output.writeByte(TC_STRING);
output.writeShort((short) count);
} else {
output.writeByte(TC_LONGSTRING);
output.writeLong(count);
}
output.writeUTFBytes(object, count);
Integer previousHandle = objectsWritten.get(object);
Integer handle = registerObjectWritten(object);
if (unshared) {
// remove reference to unshared object
removeUnsharedReference(object, previousHandle);
}
return handle;
|
private void | writeNull()Write a special tag that indicates the value {@code null} into the
receiver.
output.writeByte(TC_NULL);
|
public final void | writeObject(java.lang.Object object)Writes an object to the target stream.
writeObject(object, false);
|
private void | writeObject(java.lang.Object object, boolean unshared)
boolean setOutput = (primitiveTypes == output);
if (setOutput) {
primitiveTypes = null;
}
// This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
// behavior overriding.
if (subclassOverridingImplementation && !unshared) {
writeObjectOverride(object);
} else {
try {
// First we need to flush primitive types if they were written
drain();
// Actual work, and class-based replacement should be computed
// if needed.
writeObjectInternal(object, unshared, true, true);
if (setOutput) {
primitiveTypes = output;
}
} catch (IOException ioEx1) {
// This will make it pass through until the top caller. It also
// lets it pass through the nested exception.
if (nestedLevels == 0 && ioEx1 != nestedException) {
try {
writeNewException(ioEx1);
} catch (IOException ioEx2) {
nestedException.fillInStackTrace();
throw nestedException;
}
}
throw ioEx1; // and then we propagate the original exception
}
}
|
private java.lang.Integer | writeObjectInternal(java.lang.Object object, boolean unshared, boolean computeClassBasedReplacement, boolean computeStreamReplacement)Write object {@code object} into the receiver's underlying stream.
if (object == null) {
writeNull();
return null;
}
Integer handle = null;
if (!unshared) {
handle = dumpCycle(object);
if (handle != null) {
return handle; // cyclic reference
}
}
// Non-null object, first time seen...
Class<?> objClass = object.getClass();
nestedLevels++;
try {
if (!(enableReplace && computeStreamReplacement)) {
// Is it a Class ?
if (objClass == ObjectStreamClass.CLASSCLASS) {
return writeNewClass((Class<?>) object, unshared);
}
// Is it an ObjectStreamClass ?
if (objClass == ObjectStreamClass.OBJECTSTREAMCLASSCLASS) {
return writeClassDesc((ObjectStreamClass) object, unshared);
}
}
if (ObjectStreamClass.isSerializable(object.getClass())
&& computeClassBasedReplacement) {
Object writeReplaceMethod = writeReplaceCache.get(objClass);
if (writeReplaceMethod != this) {
if (writeReplaceMethod == null) {
final Method writeReplace = ObjectStreamClass
.methodWriteReplace(objClass);
if (writeReplace == null) {
writeReplaceCache.put(objClass, this);
writeReplaceMethod = null;
} else {
// Has replacement method
AccessController
.doPrivileged(new PriviAction<Object>(
writeReplace));
writeReplaceCache.put(objClass, writeReplace);
writeReplaceMethod = writeReplace;
}
}
if (writeReplaceMethod != null) {
Object classBasedReplacement;
try {
classBasedReplacement = ((Method) writeReplaceMethod)
.invoke(object, (Object[]) null);
} catch (IllegalAccessException iae) {
classBasedReplacement = object;
} catch (InvocationTargetException ite) {
// WARNING - Not sure this is the right thing to do
// if we can't run the method
Throwable target = ite.getTargetException();
if (target instanceof ObjectStreamException) {
throw (ObjectStreamException) target;
} else if (target instanceof Error) {
throw (Error) target;
} else {
throw (RuntimeException) target;
}
}
if (classBasedReplacement != object) {
// All over, class-based replacement off this time.
Integer replacementHandle = writeObjectInternal(
classBasedReplacement, false, false,
computeStreamReplacement);
// Make the original object also map to the same
// handle.
if (replacementHandle != null) {
registerObjectWritten(object, replacementHandle);
}
return replacementHandle;
}
}
}
}
// We get here either if class-based replacement was not needed or
// if it was needed but produced the same object or if it could not
// be computed.
if (enableReplace && computeStreamReplacement) {
// Now we compute the stream-defined replacement.
Object streamReplacement = replaceObject(object);
if (streamReplacement != object) {
// All over, class-based replacement off this time.
Integer replacementHandle = writeObjectInternal(
streamReplacement, false,
computeClassBasedReplacement, false);
// Make the original object also map to the same handle.
if (replacementHandle != null) {
registerObjectWritten(object, replacementHandle);
}
return replacementHandle;
}
}
// We get here if stream-based replacement produced the same object
// Is it a Class ?
if (objClass == ObjectStreamClass.CLASSCLASS) {
return writeNewClass((Class<?>) object, unshared);
}
// Is it an ObjectStreamClass ?
if (objClass == ObjectStreamClass.OBJECTSTREAMCLASSCLASS) {
return writeClassDesc((ObjectStreamClass) object, unshared);
}
// Is it a String ? (instanceof, but == is faster)
if (objClass == ObjectStreamClass.STRINGCLASS) {
return writeNewString((String) object, unshared);
}
// Is it an Array ?
if (objClass.isArray()) {
return writeNewArray(object, objClass, objClass
.getComponentType(), unshared);
}
if (object instanceof Enum) {
return writeNewEnum(object, objClass, unshared);
}
// Not a String or Class or Array. Default procedure.
return writeNewObject(object, objClass, unshared);
} finally {
nestedLevels--;
}
|
protected void | writeObjectOverride(java.lang.Object object)Method to be overridden by subclasses to write {@code object} to the
target stream.
// BEGIN android-changed
// copied from newer version of harmony
if (!subclassOverridingImplementation) {
// Subclasses must override.
throw new IOException();
}
// END android-changed
|
public void | writeShort(int value)Writes a short (16 bit) to the target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeShort(value);
|
protected void | writeStreamHeader()Writes the {@link ObjectOutputStream} header to the target stream.
output.writeShort(STREAM_MAGIC);
output.writeShort(STREAM_VERSION);
|
public void | writeUTF(java.lang.String value)Writes a string encoded with {@link DataInput modified UTF-8} to the
target stream.
checkWritePrimitiveTypes();
primitiveTypes.writeUTF(value);
|
public void | writeUnshared(java.lang.Object object)Writes an unshared object to the target stream. This method is identical
to {@code writeObject}, except that it always writes a new object to the
stream versus the use of back-referencing for identical objects by
{@code writeObject}.
writeObject(object, true);
|