2005-07-16 00:30:23 +00:00
/ * ObjectOutputStream . java - - Class used to write serialized objects
2006-03-10 21:46:48 +00:00
Copyright ( C ) 1998 , 1999 , 2000 , 2001 , 2002 , 2003 , 2004 , 2005 , 2006
2005-07-16 00:30:23 +00:00
Free Software Foundation , Inc .
This file is part of GNU Classpath .
GNU Classpath is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 , or ( at your option )
any later version .
GNU Classpath is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with GNU Classpath ; see the file COPYING . If not , write to the
Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
02110 - 1301 USA .
Linking this library statically or dynamically with other modules is
making a combined work based on this library . Thus , the terms and
conditions of the GNU General Public License cover the whole
combination .
As a special exception , the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable , regardless of the license terms of these independent
modules , and to copy and distribute the resulting executable under
terms of your choice , provided that you also meet , for each linked
independent module , the terms and conditions of the license of that
module . An independent module is a module which is not derived from
or based on this library . If you modify this library , you may extend
this exception to your version of the library , but you are not
obligated to do so . If you do not wish to do so , delete this
exception statement from your version . * /
package java.io ;
import gnu.java.io.ObjectIdentityWrapper ;
import gnu.java.lang.reflect.TypeSignature ;
import gnu.java.security.action.SetAccessibleAction ;
import java.lang.reflect.Array ;
import java.lang.reflect.Field ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method ;
import java.security.AccessController ;
import java.util.Hashtable ;
/ * *
* An < code > ObjectOutputStream < / code > can be used to write objects
* as well as primitive data in a platform - independent manner to an
* < code > OutputStream < / code > .
*
* The data produced by an < code > ObjectOutputStream < / code > can be read
* and reconstituted by an < code > ObjectInputStream < / code > .
*
* < code > writeObject ( Object ) < / code > is used to write Objects , the
* < code > write & lt ; type & gt ; < / code > methods are used to write primitive
* data ( as in < code > DataOutputStream < / code > ) . Strings can be written
* as objects or as primitive data .
*
* Not all objects can be written out using an
* < code > ObjectOutputStream < / code > . Only those objects that are an
* instance of < code > java . io . Serializable < / code > can be written .
*
* Using default serialization , information about the class of an
* object is written , all of the non - transient , non - static fields of
* the object are written , if any of these fields are objects , they are
* written out in the same manner .
*
* An object is only written out the first time it is encountered . If
* the object is encountered later , a reference to it is written to
* the underlying stream . Thus writing circular object graphs
* does not present a problem , nor are relationships between objects
* in a graph lost .
*
* Example usage :
* < pre >
* Hashtable map = new Hashtable ( ) ;
* map . put ( " one " , new Integer ( 1 ) ) ;
* map . put ( " two " , new Integer ( 2 ) ) ;
*
* ObjectOutputStream oos =
* new ObjectOutputStream ( new FileOutputStream ( " numbers " ) ) ;
* oos . writeObject ( map ) ;
* oos . close ( ) ;
*
* ObjectInputStream ois =
* new ObjectInputStream ( new FileInputStream ( " numbers " ) ) ;
* Hashtable newmap = ( Hashtable ) ois . readObject ( ) ;
*
* System . out . println ( newmap ) ;
* < / pre >
*
* The default serialization can be overriden in two ways .
*
* By defining a method < code > private void
* writeObject ( ObjectOutputStream ) < / code > , a class can dictate exactly
* how information about itself is written .
* < code > defaultWriteObject ( ) < / code > may be called from this method to
* carry out default serialization . This method is not
* responsible for dealing with fields of super - classes or subclasses .
*
* By implementing < code > java . io . Externalizable < / code > . This gives
* the class complete control over the way it is written to the
* stream . If this approach is used the burden of writing superclass
* and subclass data is transfered to the class implementing
* < code > java . io . Externalizable < / code > .
*
* @see java . io . DataOutputStream
* @see java . io . Externalizable
* @see java . io . ObjectInputStream
* @see java . io . Serializable
* /
public class ObjectOutputStream extends OutputStream
implements ObjectOutput , ObjectStreamConstants
{
/ * *
* Creates a new < code > ObjectOutputStream < / code > that will do all of
* its writing onto < code > out < / code > . This method also initializes
* the stream by writing the header information ( stream magic number
* and stream version ) .
*
* @exception IOException Writing stream header to underlying
* stream cannot be completed .
*
* @see # writeStreamHeader ( )
* /
public ObjectOutputStream ( OutputStream out ) throws IOException
{
realOutput = new DataOutputStream ( out ) ;
blockData = new byte [ BUFFER_SIZE ] ;
blockDataCount = 0 ;
blockDataOutput = new DataOutputStream ( this ) ;
setBlockDataMode ( true ) ;
replacementEnabled = false ;
isSerializing = false ;
nextOID = baseWireHandle ;
OIDLookupTable = new Hashtable ( ) ;
protocolVersion = defaultProtocolVersion ;
useSubclassMethod = false ;
writeStreamHeader ( ) ;
if ( DEBUG )
{
String val = System . getProperty ( " gcj.dumpobjects " ) ;
if ( val ! = null & & ! val . equals ( " " ) )
dump = true ;
}
}
/ * *
* Writes a representation of < code > obj < / code > to the underlying
* output stream by writing out information about its class , then
* writing out each of the objects non - transient , non - static
* fields . If any of these fields are other objects ,
* they are written out in the same manner .
*
* This method can be overriden by a class by implementing
* < code > private void writeObject ( ObjectOutputStream ) < / code > .
*
* If an exception is thrown from this method , the stream is left in
* an undefined state .
*
* @exception NotSerializableException An attempt was made to
* serialize an < code > Object < / code > that is not serializable .
*
* @exception InvalidClassException Somebody tried to serialize
* an object which is wrongly formatted .
*
* @exception IOException Exception from underlying
* < code > OutputStream < / code > .
* /
public final void writeObject ( Object obj ) throws IOException
{
if ( useSubclassMethod )
{
if ( dump )
dumpElementln ( " WRITE OVERRIDE: " + obj ) ;
writeObjectOverride ( obj ) ;
return ;
}
if ( dump )
dumpElementln ( " WRITE: " + obj ) ;
depth + = 2 ;
boolean was_serializing = isSerializing ;
boolean old_mode = setBlockDataMode ( false ) ;
try
{
isSerializing = true ;
boolean replaceDone = false ;
Object replacedObject = null ;
while ( true )
{
if ( obj = = null )
{
realOutput . writeByte ( TC_NULL ) ;
break ;
}
Integer handle = findHandle ( obj ) ;
if ( handle ! = null )
{
realOutput . writeByte ( TC_REFERENCE ) ;
realOutput . writeInt ( handle . intValue ( ) ) ;
break ;
}
if ( obj instanceof Class )
{
Class cl = ( Class ) obj ;
ObjectStreamClass osc = ObjectStreamClass . lookupForClassObject ( cl ) ;
realOutput . writeByte ( TC_CLASS ) ;
if ( ! osc . isProxyClass )
{
writeObject ( osc ) ;
}
else
{
realOutput . writeByte ( TC_PROXYCLASSDESC ) ;
Class [ ] intfs = cl . getInterfaces ( ) ;
realOutput . writeInt ( intfs . length ) ;
for ( int i = 0 ; i < intfs . length ; i + + )
realOutput . writeUTF ( intfs [ i ] . getName ( ) ) ;
boolean oldmode = setBlockDataMode ( true ) ;
annotateProxyClass ( cl ) ;
setBlockDataMode ( oldmode ) ;
realOutput . writeByte ( TC_ENDBLOCKDATA ) ;
writeObject ( osc . getSuper ( ) ) ;
}
assignNewHandle ( obj ) ;
break ;
}
if ( obj instanceof ObjectStreamClass )
{
writeClassDescriptor ( ( ObjectStreamClass ) obj ) ;
break ;
}
Class clazz = obj . getClass ( ) ;
ObjectStreamClass osc = ObjectStreamClass . lookupForClassObject ( clazz ) ;
if ( osc = = null )
throw new NotSerializableException ( clazz . getName ( ) ) ;
Imported GNU Classpath 0.92
2006-08-14 Mark Wielaard <mark@klomp.org>
Imported GNU Classpath 0.92
* HACKING: Add more importing hints. Update automake version
requirement.
* configure.ac (gconf-peer): New enable AC argument.
Add --disable-gconf-peer and --enable-default-preferences-peer
to classpath configure when gconf is disabled.
* scripts/makemake.tcl: Set gnu/java/util/prefs/gconf and
gnu/java/awt/dnd/peer/gtk to bc. Classify
gnu/java/security/Configuration.java as generated source file.
* gnu/java/lang/management/VMGarbageCollectorMXBeanImpl.java,
gnu/java/lang/management/VMMemoryPoolMXBeanImpl.java,
gnu/java/lang/management/VMClassLoadingMXBeanImpl.java,
gnu/java/lang/management/VMRuntimeMXBeanImpl.java,
gnu/java/lang/management/VMMemoryManagerMXBeanImpl.java,
gnu/java/lang/management/VMThreadMXBeanImpl.java,
gnu/java/lang/management/VMMemoryMXBeanImpl.java,
gnu/java/lang/management/VMCompilationMXBeanImpl.java: New VM stub
classes.
* java/lang/management/VMManagementFactory.java: Likewise.
* java/net/VMURLConnection.java: Likewise.
* gnu/java/nio/VMChannel.java: Likewise.
* java/lang/Thread.java (getState): Add stub implementation.
* java/lang/Class.java (isEnum): Likewise.
* java/lang/Class.h (isEnum): Likewise.
* gnu/awt/xlib/XToolkit.java (getClasspathTextLayoutPeer): Removed.
* javax/naming/spi/NamingManager.java: New override for StackWalker
functionality.
* configure, sources.am, Makefile.in, gcj/Makefile.in,
include/Makefile.in, testsuite/Makefile.in: Regenerated.
From-SVN: r116139
2006-08-14 23:12:35 +00:00
if ( osc . isEnum ( ) )
{
/* TC_ENUM classDesc newHandle enumConstantName */
realOutput . writeByte ( TC_ENUM ) ;
writeObject ( osc ) ;
assignNewHandle ( obj ) ;
writeObject ( ( ( Enum ) obj ) . name ( ) ) ;
break ;
}
2005-07-16 00:30:23 +00:00
if ( ( replacementEnabled | | obj instanceof Serializable )
& & ! replaceDone )
{
replacedObject = obj ;
if ( obj instanceof Serializable )
{
try
{
Method m = osc . writeReplaceMethod ;
if ( m ! = null )
obj = m . invoke ( obj , new Object [ 0 ] ) ;
}
catch ( IllegalAccessException ignore )
{
}
catch ( InvocationTargetException ignore )
{
}
}
if ( replacementEnabled )
obj = replaceObject ( obj ) ;
replaceDone = true ;
continue ;
}
if ( obj instanceof String )
{
realOutput . writeByte ( TC_STRING ) ;
assignNewHandle ( obj ) ;
realOutput . writeUTF ( ( String ) obj ) ;
break ;
}
if ( clazz . isArray ( ) )
{
realOutput . writeByte ( TC_ARRAY ) ;
writeObject ( osc ) ;
assignNewHandle ( obj ) ;
writeArraySizeAndElements ( obj , clazz . getComponentType ( ) ) ;
break ;
}
realOutput . writeByte ( TC_OBJECT ) ;
writeObject ( osc ) ;
if ( replaceDone )
assignNewHandle ( replacedObject ) ;
else
assignNewHandle ( obj ) ;
if ( obj instanceof Externalizable )
{
if ( protocolVersion = = PROTOCOL_VERSION_2 )
setBlockDataMode ( true ) ;
( ( Externalizable ) obj ) . writeExternal ( this ) ;
if ( protocolVersion = = PROTOCOL_VERSION_2 )
{
setBlockDataMode ( false ) ;
realOutput . writeByte ( TC_ENDBLOCKDATA ) ;
}
break ;
}
if ( obj instanceof Serializable )
{
Object prevObject = this . currentObject ;
ObjectStreamClass prevObjectStreamClass = this . currentObjectStreamClass ;
currentObject = obj ;
ObjectStreamClass [ ] hierarchy =
ObjectStreamClass . getObjectStreamClasses ( clazz ) ;
for ( int i = 0 ; i < hierarchy . length ; i + + )
{
currentObjectStreamClass = hierarchy [ i ] ;
fieldsAlreadyWritten = false ;
if ( currentObjectStreamClass . hasWriteMethod ( ) )
{
if ( dump )
dumpElementln ( " WRITE METHOD CALLED FOR: " + obj ) ;
setBlockDataMode ( true ) ;
callWriteMethod ( obj , currentObjectStreamClass ) ;
setBlockDataMode ( false ) ;
realOutput . writeByte ( TC_ENDBLOCKDATA ) ;
if ( dump )
dumpElementln ( " WRITE ENDBLOCKDATA FOR: " + obj ) ;
}
else
{
if ( dump )
dumpElementln ( " WRITE FIELDS CALLED FOR: " + obj ) ;
writeFields ( obj , currentObjectStreamClass ) ;
}
}
this . currentObject = prevObject ;
this . currentObjectStreamClass = prevObjectStreamClass ;
currentPutField = null ;
break ;
}
2005-11-15 23:20:01 +00:00
throw new NotSerializableException ( clazz . getName ( )
+ " in "
+ obj . getClass ( ) ) ;
2005-07-16 00:30:23 +00:00
} // end pseudo-loop
}
catch ( ObjectStreamException ose )
{
// Rethrow these are fatal.
throw ose ;
}
catch ( IOException e )
{
realOutput . writeByte ( TC_EXCEPTION ) ;
reset ( true ) ;
setBlockDataMode ( false ) ;
try
{
if ( DEBUG )
{
e . printStackTrace ( System . out ) ;
}
writeObject ( e ) ;
}
catch ( IOException ioe )
{
StreamCorruptedException ex =
new StreamCorruptedException
( ioe + " thrown while exception was being written to stream. " ) ;
if ( DEBUG )
{
ex . printStackTrace ( System . out ) ;
}
throw ex ;
}
reset ( true ) ;
}
finally
{
isSerializing = was_serializing ;
setBlockDataMode ( old_mode ) ;
depth - = 2 ;
if ( dump )
dumpElementln ( " END: " + obj ) ;
}
}
protected void writeClassDescriptor ( ObjectStreamClass osc ) throws IOException
{
2005-11-15 23:20:01 +00:00
if ( osc . isProxyClass )
{
realOutput . writeByte ( TC_PROXYCLASSDESC ) ;
Class [ ] intfs = osc . forClass ( ) . getInterfaces ( ) ;
realOutput . writeInt ( intfs . length ) ;
for ( int i = 0 ; i < intfs . length ; i + + )
realOutput . writeUTF ( intfs [ i ] . getName ( ) ) ;
2006-03-10 21:46:48 +00:00
assignNewHandle ( osc ) ;
2005-11-15 23:20:01 +00:00
boolean oldmode = setBlockDataMode ( true ) ;
annotateProxyClass ( osc . forClass ( ) ) ;
setBlockDataMode ( oldmode ) ;
realOutput . writeByte ( TC_ENDBLOCKDATA ) ;
}
else
{
realOutput . writeByte ( TC_CLASSDESC ) ;
realOutput . writeUTF ( osc . getName ( ) ) ;
Imported GNU Classpath 0.92
2006-08-14 Mark Wielaard <mark@klomp.org>
Imported GNU Classpath 0.92
* HACKING: Add more importing hints. Update automake version
requirement.
* configure.ac (gconf-peer): New enable AC argument.
Add --disable-gconf-peer and --enable-default-preferences-peer
to classpath configure when gconf is disabled.
* scripts/makemake.tcl: Set gnu/java/util/prefs/gconf and
gnu/java/awt/dnd/peer/gtk to bc. Classify
gnu/java/security/Configuration.java as generated source file.
* gnu/java/lang/management/VMGarbageCollectorMXBeanImpl.java,
gnu/java/lang/management/VMMemoryPoolMXBeanImpl.java,
gnu/java/lang/management/VMClassLoadingMXBeanImpl.java,
gnu/java/lang/management/VMRuntimeMXBeanImpl.java,
gnu/java/lang/management/VMMemoryManagerMXBeanImpl.java,
gnu/java/lang/management/VMThreadMXBeanImpl.java,
gnu/java/lang/management/VMMemoryMXBeanImpl.java,
gnu/java/lang/management/VMCompilationMXBeanImpl.java: New VM stub
classes.
* java/lang/management/VMManagementFactory.java: Likewise.
* java/net/VMURLConnection.java: Likewise.
* gnu/java/nio/VMChannel.java: Likewise.
* java/lang/Thread.java (getState): Add stub implementation.
* java/lang/Class.java (isEnum): Likewise.
* java/lang/Class.h (isEnum): Likewise.
* gnu/awt/xlib/XToolkit.java (getClasspathTextLayoutPeer): Removed.
* javax/naming/spi/NamingManager.java: New override for StackWalker
functionality.
* configure, sources.am, Makefile.in, gcj/Makefile.in,
include/Makefile.in, testsuite/Makefile.in: Regenerated.
From-SVN: r116139
2006-08-14 23:12:35 +00:00
if ( osc . isEnum ( ) )
realOutput . writeLong ( 0L ) ;
else
realOutput . writeLong ( osc . getSerialVersionUID ( ) ) ;
2005-11-15 23:20:01 +00:00
assignNewHandle ( osc ) ;
2005-07-16 00:30:23 +00:00
2005-11-15 23:20:01 +00:00
int flags = osc . getFlags ( ) ;
2005-07-16 00:30:23 +00:00
2005-11-15 23:20:01 +00:00
if ( protocolVersion = = PROTOCOL_VERSION_2
& & osc . isExternalizable ( ) )
flags | = SC_BLOCK_DATA ;
2005-07-16 00:30:23 +00:00
2005-11-15 23:20:01 +00:00
realOutput . writeByte ( flags ) ;
2005-07-16 00:30:23 +00:00
2005-11-15 23:20:01 +00:00
ObjectStreamField [ ] fields = osc . fields ;
2006-01-17 18:09:40 +00:00
if ( fields = = ObjectStreamClass . INVALID_FIELDS )
throw new InvalidClassException
( osc . getName ( ) , " serialPersistentFields is invalid " ) ;
2005-11-15 23:20:01 +00:00
realOutput . writeShort ( fields . length ) ;
2005-07-16 00:30:23 +00:00
2005-11-15 23:20:01 +00:00
ObjectStreamField field ;
for ( int i = 0 ; i < fields . length ; i + + )
{
field = fields [ i ] ;
realOutput . writeByte ( field . getTypeCode ( ) ) ;
realOutput . writeUTF ( field . getName ( ) ) ;
2005-07-16 00:30:23 +00:00
2005-11-15 23:20:01 +00:00
if ( ! field . isPrimitive ( ) )
writeObject ( field . getTypeString ( ) ) ;
}
2005-07-16 00:30:23 +00:00
2005-11-15 23:20:01 +00:00
boolean oldmode = setBlockDataMode ( true ) ;
annotateClass ( osc . forClass ( ) ) ;
setBlockDataMode ( oldmode ) ;
realOutput . writeByte ( TC_ENDBLOCKDATA ) ;
}
2005-07-16 00:30:23 +00:00
if ( osc . isSerializable ( ) | | osc . isExternalizable ( ) )
writeObject ( osc . getSuper ( ) ) ;
else
writeObject ( null ) ;
}
/ * *
* Writes the current objects non - transient , non - static fields from
* the current class to the underlying output stream .
*
* This method is intended to be called from within a object ' s
* < code > private void writeObject ( ObjectOutputStream ) < / code >
* method .
*
* @exception NotActiveException This method was called from a
* context other than from the current object ' s and current class ' s
* < code > private void writeObject ( ObjectOutputStream ) < / code >
* method .
*
* @exception IOException Exception from underlying
* < code > OutputStream < / code > .
* /
public void defaultWriteObject ( )
throws IOException , NotActiveException
{
markFieldsWritten ( ) ;
writeFields ( currentObject , currentObjectStreamClass ) ;
}
private void markFieldsWritten ( ) throws IOException
{
if ( currentObject = = null | | currentObjectStreamClass = = null )
throw new NotActiveException
( " defaultWriteObject called by non-active class and/or object " ) ;
if ( fieldsAlreadyWritten )
throw new IOException
( " Only one of writeFields and defaultWriteObject may be called, and it may only be called once " ) ;
fieldsAlreadyWritten = true ;
}
/ * *
* Resets stream to state equivalent to the state just after it was
* constructed .
*
* Causes all objects previously written to the stream to be
* forgotten . A notification of this reset is also written to the
* underlying stream .
*
* @exception IOException Exception from underlying
* < code > OutputStream < / code > or reset called while serialization is
* in progress .
* /
public void reset ( ) throws IOException
{
reset ( false ) ;
}
private void reset ( boolean internal ) throws IOException
{
if ( ! internal )
{
if ( isSerializing )
throw new IOException ( " Reset called while serialization in progress " ) ;
realOutput . writeByte ( TC_RESET ) ;
}
clearHandles ( ) ;
}
/ * *
* Informs this < code > ObjectOutputStream < / code > to write data
* according to the specified protocol . There are currently two
* different protocols , specified by < code > PROTOCOL_VERSION_1 < / code >
* and < code > PROTOCOL_VERSION_2 < / code > . This implementation writes
* data using < code > PROTOCOL_VERSION_2 < / code > by default , as is done
2006-05-18 17:29:21 +00:00
* since the JDK 1 . 2 .
* < p >
2005-11-15 23:20:01 +00:00
* For an explanation of the differences between the two protocols
2006-05-18 17:29:21 +00:00
* see the Java Object Serialization Specification .
* < / p >
*
* @param version the version to use .
*
* @throws IllegalArgumentException if < code > version < / code > is not a valid
* protocol .
* @throws IllegalStateException if called after the first the first object
* was serialized .
* @throws IOException if an I / O error occurs .
*
* @see ObjectStreamConstants # PROTOCOL_VERSION_1
* @see ObjectStreamConstants # PROTOCOL_VERSION_2
*
* @since 1 . 2
2005-07-16 00:30:23 +00:00
* /
public void useProtocolVersion ( int version ) throws IOException
{
if ( version ! = PROTOCOL_VERSION_1 & & version ! = PROTOCOL_VERSION_2 )
2006-05-18 17:29:21 +00:00
throw new IllegalArgumentException ( " Invalid protocol version requested. " ) ;
if ( nextOID ! = baseWireHandle )
throw new IllegalStateException ( " Protocol version cannot be changed "
+ " after serialization started. " ) ;
2005-07-16 00:30:23 +00:00
protocolVersion = version ;
}
/ * *
* An empty hook that allows subclasses to write extra information
* about classes to the stream . This method is called the first
* time each class is seen , and after all of the standard
* information about the class has been written .
*
* @exception IOException Exception from underlying
* < code > OutputStream < / code > .
*
* @see ObjectInputStream # resolveClass ( java . io . ObjectStreamClass )
* /
protected void annotateClass ( Class cl ) throws IOException
{
}
protected void annotateProxyClass ( Class cl ) throws IOException
{
}
/ * *
* Allows subclasses to replace objects that are written to the
* stream with other objects to be written in their place . This
* method is called the first time each object is encountered
* ( modulo reseting of the stream ) .
*
* This method must be enabled before it will be called in the
* serialization process .
*
* @exception IOException Exception from underlying
* < code > OutputStream < / code > .
*
* @see # enableReplaceObject ( boolean )
* /
protected Object replaceObject ( Object obj ) throws IOException
{
return obj ;
}
/ * *
* If < code > enable < / code > is < code > true < / code > and this object is
* trusted , then < code > replaceObject ( Object ) < / code > will be called
* in subsequent calls to < code > writeObject ( Object ) < / code > .
* Otherwise , < code > replaceObject ( Object ) < / code > will not be called .
*
* @exception SecurityException This class is not trusted .
* /
protected boolean enableReplaceObject ( boolean enable )
throws SecurityException
{
if ( enable )
{
SecurityManager sm = System . getSecurityManager ( ) ;
if ( sm ! = null )
sm . checkPermission ( new SerializablePermission ( " enableSubstitution " ) ) ;
}
boolean old_val = replacementEnabled ;
replacementEnabled = enable ;
return old_val ;
}
/ * *
* Writes stream magic and stream version information to the
* underlying stream .
*
* @exception IOException Exception from underlying
* < code > OutputStream < / code > .
* /
protected void writeStreamHeader ( ) throws IOException
{
realOutput . writeShort ( STREAM_MAGIC ) ;
realOutput . writeShort ( STREAM_VERSION ) ;
}
/ * *
* Protected constructor that allows subclasses to override
* serialization . This constructor should be called by subclasses
* that wish to override < code > writeObject ( Object ) < / code > . This
* method does a security check < i > NOTE : currently not
* implemented < / i > , then sets a flag that informs
* < code > writeObject ( Object ) < / code > to call the subclasses
* < code > writeObjectOverride ( Object ) < / code > method .
*
* @see # writeObjectOverride ( Object )
* /
protected ObjectOutputStream ( ) throws IOException , SecurityException
{
SecurityManager sec_man = System . getSecurityManager ( ) ;
if ( sec_man ! = null )
sec_man . checkPermission ( SUBCLASS_IMPLEMENTATION_PERMISSION ) ;
useSubclassMethod = true ;
}
/ * *
* This method allows subclasses to override the default
* serialization mechanism provided by
* < code > ObjectOutputStream < / code > . To make this method be used for
* writing objects , subclasses must invoke the 0 - argument
* constructor on this class from there constructor .
*
* @see # ObjectOutputStream ( )
*
* @exception NotActiveException Subclass has arranged for this
* method to be called , but did not implement this method .
* /
protected void writeObjectOverride ( Object obj ) throws NotActiveException ,
IOException
{
throw new NotActiveException
( " Subclass of ObjectOutputStream must implement writeObjectOverride " ) ;
}
/ * *
* @see DataOutputStream # write ( int )
* /
public void write ( int data ) throws IOException
{
if ( writeDataAsBlocks )
{
if ( blockDataCount = = BUFFER_SIZE )
drain ( ) ;
blockData [ blockDataCount + + ] = ( byte ) data ;
}
else
realOutput . write ( data ) ;
}
/ * *
* @see DataOutputStream # write ( byte [ ] )
* /
public void write ( byte [ ] b ) throws IOException
{
write ( b , 0 , b . length ) ;
}
/ * *
* @see DataOutputStream # write ( byte [ ] , int , int )
* /
public void write ( byte [ ] b , int off , int len ) throws IOException
{
if ( writeDataAsBlocks )
{
if ( len < 0 )
throw new IndexOutOfBoundsException ( ) ;
if ( blockDataCount + len < BUFFER_SIZE )
{
System . arraycopy ( b , off , blockData , blockDataCount , len ) ;
blockDataCount + = len ;
}
else
{
drain ( ) ;
writeBlockDataHeader ( len ) ;
realOutput . write ( b , off , len ) ;
}
}
else
realOutput . write ( b , off , len ) ;
}
/ * *
* @see DataOutputStream # flush ( )
* /
public void flush ( ) throws IOException
{
drain ( ) ;
realOutput . flush ( ) ;
}
/ * *
* Causes the block - data buffer to be written to the underlying
* stream , but does not flush underlying stream .
*
* @exception IOException Exception from underlying
* < code > OutputStream < / code > .
* /
protected void drain ( ) throws IOException
{
if ( blockDataCount = = 0 )
return ;
if ( writeDataAsBlocks )
writeBlockDataHeader ( blockDataCount ) ;
realOutput . write ( blockData , 0 , blockDataCount ) ;
blockDataCount = 0 ;
}
/ * *
* @see java . io . DataOutputStream # close ( )
* /
public void close ( ) throws IOException
{
flush ( ) ;
realOutput . close ( ) ;
}
/ * *
* @see java . io . DataOutputStream # writeBoolean ( boolean )
* /
public void writeBoolean ( boolean data ) throws IOException
{
blockDataOutput . writeBoolean ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeByte ( int )
* /
public void writeByte ( int data ) throws IOException
{
blockDataOutput . writeByte ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeShort ( int )
* /
public void writeShort ( int data ) throws IOException
{
blockDataOutput . writeShort ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeChar ( int )
* /
public void writeChar ( int data ) throws IOException
{
blockDataOutput . writeChar ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeInt ( int )
* /
public void writeInt ( int data ) throws IOException
{
blockDataOutput . writeInt ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeLong ( long )
* /
public void writeLong ( long data ) throws IOException
{
blockDataOutput . writeLong ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeFloat ( float )
* /
public void writeFloat ( float data ) throws IOException
{
blockDataOutput . writeFloat ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeDouble ( double )
* /
public void writeDouble ( double data ) throws IOException
{
blockDataOutput . writeDouble ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeBytes ( java . lang . String )
* /
public void writeBytes ( String data ) throws IOException
{
blockDataOutput . writeBytes ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeChars ( java . lang . String )
* /
public void writeChars ( String data ) throws IOException
{
dataOutput . writeChars ( data ) ;
}
/ * *
* @see java . io . DataOutputStream # writeUTF ( java . lang . String )
* /
public void writeUTF ( String data ) throws IOException
{
dataOutput . writeUTF ( data ) ;
}
/ * *
* This class allows a class to specify exactly which fields should
* be written , and what values should be written for these fields .
*
* XXX : finish up comments
* /
public abstract static class PutField
{
public abstract void put ( String name , boolean value ) ;
public abstract void put ( String name , byte value ) ;
public abstract void put ( String name , char value ) ;
public abstract void put ( String name , double value ) ;
public abstract void put ( String name , float value ) ;
public abstract void put ( String name , int value ) ;
public abstract void put ( String name , long value ) ;
public abstract void put ( String name , short value ) ;
public abstract void put ( String name , Object value ) ;
/ * *
* @deprecated
* /
public abstract void write ( ObjectOutput out ) throws IOException ;
}
public PutField putFields ( ) throws IOException
{
if ( currentPutField ! = null )
return currentPutField ;
currentPutField = new PutField ( )
{
private byte [ ] prim_field_data
= new byte [ currentObjectStreamClass . primFieldSize ] ;
private Object [ ] objs
= new Object [ currentObjectStreamClass . objectFieldCount ] ;
private ObjectStreamField getField ( String name )
{
ObjectStreamField field
= currentObjectStreamClass . getField ( name ) ;
if ( field = = null )
throw new IllegalArgumentException ( " no such serializable field " + name ) ;
return field ;
}
public void put ( String name , boolean value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'Z' ) ;
prim_field_data [ field . getOffset ( ) ] = ( byte ) ( value ? 1 : 0 ) ;
}
public void put ( String name , byte value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'B' ) ;
prim_field_data [ field . getOffset ( ) ] = value ;
}
public void put ( String name , char value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'C' ) ;
int off = field . getOffset ( ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 8 ) ;
prim_field_data [ off ] = ( byte ) value ;
}
public void put ( String name , double value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'D' ) ;
int off = field . getOffset ( ) ;
long l_value = Double . doubleToLongBits ( value ) ;
prim_field_data [ off + + ] = ( byte ) ( l_value > > > 52 ) ;
prim_field_data [ off + + ] = ( byte ) ( l_value > > > 48 ) ;
prim_field_data [ off + + ] = ( byte ) ( l_value > > > 40 ) ;
prim_field_data [ off + + ] = ( byte ) ( l_value > > > 32 ) ;
prim_field_data [ off + + ] = ( byte ) ( l_value > > > 24 ) ;
prim_field_data [ off + + ] = ( byte ) ( l_value > > > 16 ) ;
prim_field_data [ off + + ] = ( byte ) ( l_value > > > 8 ) ;
prim_field_data [ off ] = ( byte ) l_value ;
}
public void put ( String name , float value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'F' ) ;
int off = field . getOffset ( ) ;
int i_value = Float . floatToIntBits ( value ) ;
prim_field_data [ off + + ] = ( byte ) ( i_value > > > 24 ) ;
prim_field_data [ off + + ] = ( byte ) ( i_value > > > 16 ) ;
prim_field_data [ off + + ] = ( byte ) ( i_value > > > 8 ) ;
prim_field_data [ off ] = ( byte ) i_value ;
}
public void put ( String name , int value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'I' ) ;
int off = field . getOffset ( ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 24 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 16 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 8 ) ;
prim_field_data [ off ] = ( byte ) value ;
}
public void put ( String name , long value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'J' ) ;
int off = field . getOffset ( ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 52 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 48 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 40 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 32 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 24 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 16 ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 8 ) ;
prim_field_data [ off ] = ( byte ) value ;
}
public void put ( String name , short value )
{
ObjectStreamField field = getField ( name ) ;
checkType ( field , 'S' ) ;
int off = field . getOffset ( ) ;
prim_field_data [ off + + ] = ( byte ) ( value > > > 8 ) ;
prim_field_data [ off ] = ( byte ) value ;
}
public void put ( String name , Object value )
{
ObjectStreamField field = getField ( name ) ;
if ( value ! = null & &
! field . getType ( ) . isAssignableFrom ( value . getClass ( ) ) )
throw new IllegalArgumentException ( " Class " + value . getClass ( ) +
" cannot be cast to " + field . getType ( ) ) ;
objs [ field . getOffset ( ) ] = value ;
}
public void write ( ObjectOutput out ) throws IOException
{
// Apparently Block data is not used with PutField as per
// empirical evidence against JDK 1.2. Also see Mauve test
// java.io.ObjectInputOutput.Test.GetPutField.
boolean oldmode = setBlockDataMode ( false ) ;
out . write ( prim_field_data ) ;
for ( int i = 0 ; i < objs . length ; + + i )
out . writeObject ( objs [ i ] ) ;
setBlockDataMode ( oldmode ) ;
}
private void checkType ( ObjectStreamField field , char type )
throws IllegalArgumentException
{
if ( TypeSignature . getEncodingOfClass ( field . getType ( ) ) . charAt ( 0 )
! = type )
throw new IllegalArgumentException ( ) ;
}
} ;
// end PutFieldImpl
return currentPutField ;
}
public void writeFields ( ) throws IOException
{
if ( currentPutField = = null )
throw new NotActiveException ( " writeFields can only be called after putFields has been called " ) ;
markFieldsWritten ( ) ;
currentPutField . write ( this ) ;
}
// write out the block-data buffer, picking the correct header
// depending on the size of the buffer
private void writeBlockDataHeader ( int size ) throws IOException
{
if ( size < 256 )
{
realOutput . writeByte ( TC_BLOCKDATA ) ;
realOutput . write ( size ) ;
}
else
{
realOutput . writeByte ( TC_BLOCKDATALONG ) ;
realOutput . writeInt ( size ) ;
}
}
// lookup the handle for OBJ, return null if OBJ doesn't have a
// handle yet
private Integer findHandle ( Object obj )
{
return ( Integer ) OIDLookupTable . get ( new ObjectIdentityWrapper ( obj ) ) ;
}
// assigns the next availible handle to OBJ
private int assignNewHandle ( Object obj )
{
OIDLookupTable . put ( new ObjectIdentityWrapper ( obj ) ,
new Integer ( nextOID ) ) ;
return nextOID + + ;
}
// resets mapping from objects to handles
private void clearHandles ( )
{
nextOID = baseWireHandle ;
OIDLookupTable . clear ( ) ;
}
// write out array size followed by each element of the array
private void writeArraySizeAndElements ( Object array , Class clazz )
throws IOException
{
int length = Array . getLength ( array ) ;
if ( clazz . isPrimitive ( ) )
{
if ( clazz = = Boolean . TYPE )
{
boolean [ ] cast_array = ( boolean [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
realOutput . writeBoolean ( cast_array [ i ] ) ;
return ;
}
if ( clazz = = Byte . TYPE )
{
byte [ ] cast_array = ( byte [ ] ) array ;
realOutput . writeInt ( length ) ;
realOutput . write ( cast_array , 0 , length ) ;
return ;
}
if ( clazz = = Character . TYPE )
{
char [ ] cast_array = ( char [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
realOutput . writeChar ( cast_array [ i ] ) ;
return ;
}
if ( clazz = = Double . TYPE )
{
double [ ] cast_array = ( double [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
realOutput . writeDouble ( cast_array [ i ] ) ;
return ;
}
if ( clazz = = Float . TYPE )
{
float [ ] cast_array = ( float [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
realOutput . writeFloat ( cast_array [ i ] ) ;
return ;
}
if ( clazz = = Integer . TYPE )
{
int [ ] cast_array = ( int [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
realOutput . writeInt ( cast_array [ i ] ) ;
return ;
}
if ( clazz = = Long . TYPE )
{
long [ ] cast_array = ( long [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
realOutput . writeLong ( cast_array [ i ] ) ;
return ;
}
if ( clazz = = Short . TYPE )
{
short [ ] cast_array = ( short [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
realOutput . writeShort ( cast_array [ i ] ) ;
return ;
}
}
else
{
Object [ ] cast_array = ( Object [ ] ) array ;
realOutput . writeInt ( length ) ;
for ( int i = 0 ; i < length ; i + + )
writeObject ( cast_array [ i ] ) ;
}
}
// writes out FIELDS of OBJECT for the specified ObjectStreamClass.
// FIELDS are already in canonical order.
private void writeFields ( Object obj , ObjectStreamClass osc )
throws IOException
{
ObjectStreamField [ ] fields = osc . fields ;
boolean oldmode = setBlockDataMode ( false ) ;
String field_name ;
Class type ;
for ( int i = 0 ; i < fields . length ; i + + )
{
field_name = fields [ i ] . getName ( ) ;
type = fields [ i ] . getType ( ) ;
if ( dump )
dumpElementln ( " WRITE FIELD: " + field_name + " type= " + type ) ;
if ( type = = Boolean . TYPE )
realOutput . writeBoolean ( getBooleanField ( obj , osc . forClass ( ) , field_name ) ) ;
else if ( type = = Byte . TYPE )
realOutput . writeByte ( getByteField ( obj , osc . forClass ( ) , field_name ) ) ;
else if ( type = = Character . TYPE )
realOutput . writeChar ( getCharField ( obj , osc . forClass ( ) , field_name ) ) ;
else if ( type = = Double . TYPE )
realOutput . writeDouble ( getDoubleField ( obj , osc . forClass ( ) , field_name ) ) ;
else if ( type = = Float . TYPE )
realOutput . writeFloat ( getFloatField ( obj , osc . forClass ( ) , field_name ) ) ;
else if ( type = = Integer . TYPE )
realOutput . writeInt ( getIntField ( obj , osc . forClass ( ) , field_name ) ) ;
else if ( type = = Long . TYPE )
realOutput . writeLong ( getLongField ( obj , osc . forClass ( ) , field_name ) ) ;
else if ( type = = Short . TYPE )
realOutput . writeShort ( getShortField ( obj , osc . forClass ( ) , field_name ) ) ;
else
writeObject ( getObjectField ( obj , osc . forClass ( ) , field_name ,
fields [ i ] . getTypeString ( ) ) ) ;
}
setBlockDataMode ( oldmode ) ;
}
// Toggles writing primitive data to block-data buffer.
// Package-private to avoid a trampoline constructor.
boolean setBlockDataMode ( boolean on ) throws IOException
{
if ( on = = writeDataAsBlocks )
return on ;
drain ( ) ;
boolean oldmode = writeDataAsBlocks ;
writeDataAsBlocks = on ;
if ( on )
dataOutput = blockDataOutput ;
else
dataOutput = realOutput ;
return oldmode ;
}
private void callWriteMethod ( Object obj , ObjectStreamClass osc )
throws IOException
{
currentPutField = null ;
try
{
Object args [ ] = { this } ;
osc . writeObjectMethod . invoke ( obj , args ) ;
}
catch ( InvocationTargetException x )
{
/* Rethrow if possible. */
Throwable exception = x . getTargetException ( ) ;
if ( exception instanceof RuntimeException )
throw ( RuntimeException ) exception ;
if ( exception instanceof IOException )
throw ( IOException ) exception ;
IOException ioe
= new IOException ( " Exception thrown from writeObject() on " +
osc . forClass ( ) . getName ( ) + " : " +
exception . getClass ( ) . getName ( ) ) ;
ioe . initCause ( exception ) ;
throw ioe ;
}
catch ( Exception x )
{
IOException ioe
= new IOException ( " Failure invoking writeObject() on " +
osc . forClass ( ) . getName ( ) + " : " +
x . getClass ( ) . getName ( ) ) ;
ioe . initCause ( x ) ;
throw ioe ;
}
}
private boolean getBooleanField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
boolean b = f . getBoolean ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private byte getByteField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
byte b = f . getByte ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private char getCharField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
char b = f . getChar ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private double getDoubleField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
double b = f . getDouble ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private float getFloatField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
float b = f . getFloat ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private int getIntField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
int b = f . getInt ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private long getLongField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
long b = f . getLong ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private short getShortField ( Object obj , Class klass , String field_name )
throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
short b = f . getShort ( obj ) ;
return b ;
}
catch ( IllegalArgumentException _ )
{
throw new InvalidClassException
( " invalid requested type for field " + field_name + " in class " + klass . getName ( ) ) ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception _ )
{
throw new IOException ( " Unexpected exception " + _ ) ;
}
}
private Object getObjectField ( Object obj , Class klass , String field_name ,
String type_code ) throws IOException
{
try
{
Field f = getField ( klass , field_name ) ;
ObjectStreamField of = new ObjectStreamField ( f . getName ( ) , f . getType ( ) ) ;
/ * if of is primitive something went wrong
* in the check for primitive classes in writeFields .
* /
if ( of . isPrimitive ( ) )
throw new InvalidClassException
( " invalid type code for " + field_name + " in class " + klass . getName ( ) + " : object stream field is primitive " ) ;
if ( ! of . getTypeString ( ) . equals ( type_code ) )
throw new InvalidClassException
( " invalid type code for " + field_name + " in class " + klass . getName ( ) + " : object stream field " + of + " has type string " + of . getTypeString ( ) + " instead of " + type_code ) ;
Object o = f . get ( obj ) ;
// FIXME: We should check the type_code here
return o ;
}
catch ( IOException e )
{
throw e ;
}
catch ( Exception e )
{
throw new IOException ( ) ;
}
}
private Field getField ( Class klass , String name )
throws java . io . InvalidClassException
{
try
{
final Field f = klass . getDeclaredField ( name ) ;
setAccessible . setMember ( f ) ;
AccessController . doPrivileged ( setAccessible ) ;
return f ;
}
catch ( java . lang . NoSuchFieldException e )
{
throw new InvalidClassException
( " no field called " + name + " in class " + klass . getName ( ) ) ;
}
}
private void dumpElementln ( String msg )
{
for ( int i = 0 ; i < depth ; i + + )
System . out . print ( " " ) ;
System . out . print ( Thread . currentThread ( ) + " : " ) ;
System . out . println ( msg ) ;
}
// this value comes from 1.2 spec, but is used in 1.1 as well
private static final int BUFFER_SIZE = 1024 ;
private static int defaultProtocolVersion = PROTOCOL_VERSION_2 ;
private DataOutputStream dataOutput ;
private boolean writeDataAsBlocks ;
private DataOutputStream realOutput ;
private DataOutputStream blockDataOutput ;
private byte [ ] blockData ;
private int blockDataCount ;
private Object currentObject ;
// Package-private to avoid a trampoline.
ObjectStreamClass currentObjectStreamClass ;
private PutField currentPutField ;
private boolean fieldsAlreadyWritten ;
private boolean replacementEnabled ;
private boolean isSerializing ;
private int nextOID ;
private Hashtable OIDLookupTable ;
private int protocolVersion ;
private boolean useSubclassMethod ;
private SetAccessibleAction setAccessible = new SetAccessibleAction ( ) ;
// The nesting depth for debugging output
private int depth = 0 ;
// Set if we're generating debugging dumps
private boolean dump = false ;
private static final boolean DEBUG = false ;
}