* Makefile.am (nat_source_files): Remove
[official-gcc.git] / libjava / java / io / ObjectOutputStream.java
blobd522996d7a55a3a80e21c2e4a2f32c934d40ae53
1 /* ObjectOutputStream.java -- Class used to write serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.io;
41 import java.lang.reflect.Array;
42 import java.lang.reflect.Field;
43 import java.lang.reflect.Method;
44 import java.lang.reflect.InvocationTargetException;
45 import java.util.Hashtable;
47 import gnu.java.io.ObjectIdentityWrapper;
48 import gnu.java.lang.reflect.TypeSignature;
49 import gnu.classpath.Configuration;
51 /**
52 An <code>ObjectOutputStream</code> can be used to write objects
53 as well as primitive data in a platform-independent manner to an
54 <code>OutputStream</code>.
56 The data produced by an <code>ObjectOutputStream</code> can be read
57 and reconstituted by an <code>ObjectInputStream</code>.
59 <code>writeObject (Object)</code> is used to write Objects, the
60 <code>write&lt;type&gt;</code> methods are used to write primitive
61 data (as in <code>DataOutputStream</code>). Strings can be written
62 as objects or as primitive data.
64 Not all objects can be written out using an
65 <code>ObjectOutputStream</code>. Only those objects that are an
66 instance of <code>java.io.Serializable</code> can be written.
68 Using default serialization, information about the class of an
69 object is written, all of the non-transient, non-static fields of
70 the object are written, if any of these fields are objects, they are
71 written out in the same manner.
73 An object is only written out the first time it is encountered. If
74 the object is encountered later, a reference to it is written to
75 the underlying stream. Thus writing circular object graphs
76 does not present a problem, nor are relationships between objects
77 in a graph lost.
79 Example usage:
80 <pre>
81 Hashtable map = new Hashtable ();
82 map.put ("one", new Integer (1));
83 map.put ("two", new Integer (2));
85 ObjectOutputStream oos =
86 new ObjectOutputStream (new FileOutputStream ("numbers"));
87 oos.writeObject (map);
88 oos.close ();
90 ObjectInputStream ois =
91 new ObjectInputStream (new FileInputStream ("numbers"));
92 Hashtable newmap = (Hashtable)ois.readObject ();
94 System.out.println (newmap);
95 </pre>
97 The default serialization can be overriden in two ways.
99 By defining a method <code>private void
100 writeObject (ObjectOutputStream)</code>, a class can dictate exactly
101 how information about itself is written.
102 <code>defaultWriteObject ()</code> may be called from this method to
103 carry out default serialization. This method is not
104 responsible for dealing with fields of super-classes or subclasses.
106 By implementing <code>java.io.Externalizable</code>. This gives
107 the class complete control over the way it is written to the
108 stream. If this approach is used the burden of writing superclass
109 and subclass data is transfered to the class implementing
110 <code>java.io.Externalizable</code>.
112 @see java.io.DataOutputStream
113 @see java.io.Externalizable
114 @see java.io.ObjectInputStream
115 @see java.io.Serializable
116 @see XXX: java serialization spec
118 public class ObjectOutputStream extends OutputStream
119 implements ObjectOutput, ObjectStreamConstants
122 Creates a new <code>ObjectOutputStream</code> that will do all of
123 its writing onto <code>out</code>. This method also initializes
124 the stream by writing the header information (stream magic number
125 and stream version).
127 @exception IOException Writing stream header to underlying
128 stream cannot be completed.
130 @see writeStreamHeader ()
132 public ObjectOutputStream (OutputStream out) throws IOException
134 realOutput = new DataOutputStream (out);
135 blockData = new byte[ BUFFER_SIZE ];
136 blockDataCount = 0;
137 blockDataOutput = new DataOutputStream (this);
138 setBlockDataMode (true);
139 replacementEnabled = false;
140 isSerializing = false;
141 nextOID = baseWireHandle;
142 OIDLookupTable = new Hashtable ();
143 protocolVersion = defaultProtocolVersion;
144 useSubclassMethod = false;
145 writeStreamHeader ();
150 Writes a representation of <code>obj</code> to the underlying
151 output stream by writing out information about its class, then
152 writing out each of the objects non-transient, non-static
153 fields. If any of these fields are other objects,
154 they are written out in the same manner.
156 This method can be overriden by a class by implementing
157 <code>private void writeObject (ObjectOutputStream)</code>.
159 If an exception is thrown from this method, the stream is left in
160 an undefined state.
162 @exception NotSerializableException An attempt was made to
163 serialize an <code>Object</code> that is not serializable.
165 @exception IOException Exception from underlying
166 <code>OutputStream</code>.
168 public final void writeObject (Object obj) throws IOException
170 if (useSubclassMethod)
172 writeObjectOverride (obj);
173 return;
176 boolean was_serializing = isSerializing;
177 boolean old_mode = setBlockDataMode (false);
180 isSerializing = true;
181 boolean replaceDone = false;
182 Object replacedObject = null;
184 while (true)
186 if (obj == null)
188 realOutput.writeByte (TC_NULL);
189 break;
192 Integer handle = findHandle (obj);
193 if (handle != null)
195 realOutput.writeByte (TC_REFERENCE);
196 realOutput.writeInt (handle.intValue ());
197 break;
200 if (obj instanceof Class)
202 Class cl = (Class)obj;
203 ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
204 assignNewHandle (obj);
205 realOutput.writeByte (TC_CLASS);
206 if (!osc.isProxyClass)
208 writeObject(osc);
210 else
212 realOutput.writeByte (TC_PROXYCLASSDESC);
213 Class[] intfs = cl.getInterfaces();
214 realOutput.writeInt(intfs.length);
215 for (int i = 0; i < intfs.length; i++)
216 realOutput.writeUTF(intfs[i].getName());
218 boolean oldmode = setBlockDataMode (true);
219 annotateProxyClass(cl);
220 setBlockDataMode (oldmode);
221 realOutput.writeByte(TC_ENDBLOCKDATA);
223 writeObject (osc.getSuper());
225 break;
228 if (obj instanceof ObjectStreamClass)
230 ObjectStreamClass osc = (ObjectStreamClass)obj;
231 realOutput.writeByte (TC_CLASSDESC);
232 realOutput.writeUTF (osc.getName ());
233 realOutput.writeLong (osc.getSerialVersionUID ());
234 assignNewHandle (obj);
236 int flags = osc.getFlags ();
238 if (protocolVersion == PROTOCOL_VERSION_2
239 && osc.isExternalizable ())
240 flags |= SC_BLOCK_DATA;
242 realOutput.writeByte (flags);
244 ObjectStreamField[] fields = osc.fields;
245 realOutput.writeShort (fields.length);
247 ObjectStreamField field;
248 for (int i=0; i < fields.length; i++)
250 field = fields[i];
251 realOutput.writeByte (field.getTypeCode ());
252 realOutput.writeUTF (field.getName ());
254 if (! field.isPrimitive ())
255 writeObject (field.getTypeString ());
258 boolean oldmode = setBlockDataMode (true);
259 annotateClass (osc.forClass ());
260 setBlockDataMode (oldmode);
261 realOutput.writeByte (TC_ENDBLOCKDATA);
263 if (osc.isSerializable ())
264 writeObject (osc.getSuper ());
265 else
266 writeObject (null);
267 break;
270 if ((replacementEnabled || obj instanceof Serializable)
271 && ! replaceDone)
273 replacedObject = obj;
275 if (obj instanceof Serializable)
277 Method m = null;
280 Class classArgs[] = {};
281 m = obj.getClass ().getDeclaredMethod ("writeReplace",
282 classArgs);
283 // m can't be null by definition since an exception would
284 // have been thrown so a check for null is not needed.
285 obj = m.invoke (obj, new Object[] {});
287 catch (NoSuchMethodException ignore)
290 catch (IllegalAccessException ignore)
293 catch (InvocationTargetException ignore)
298 if (replacementEnabled)
299 obj = replaceObject (obj);
301 replaceDone = true;
302 continue;
305 if (obj instanceof String)
307 realOutput.writeByte (TC_STRING);
308 assignNewHandle (obj);
309 realOutput.writeUTF ((String)obj);
310 break;
313 Class clazz = obj.getClass ();
314 ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject (clazz);
315 if (osc == null)
316 throw new NotSerializableException (clazz.getName ());
318 if (clazz.isArray ())
320 realOutput.writeByte (TC_ARRAY);
321 writeObject (osc);
322 assignNewHandle (obj);
323 writeArraySizeAndElements (obj, clazz.getComponentType ());
324 break;
327 realOutput.writeByte (TC_OBJECT);
328 writeObject (osc);
330 if (replaceDone)
331 assignNewHandle (replacedObject);
332 else
333 assignNewHandle (obj);
335 if (obj instanceof Externalizable)
337 if (protocolVersion == PROTOCOL_VERSION_2)
338 setBlockDataMode (true);
340 ((Externalizable)obj).writeExternal (this);
342 if (protocolVersion == PROTOCOL_VERSION_2)
344 setBlockDataMode (false);
345 realOutput.writeByte (TC_ENDBLOCKDATA);
348 break;
351 if (obj instanceof Serializable)
353 currentObject = obj;
354 ObjectStreamClass[] hierarchy =
355 ObjectStreamClass.getObjectStreamClasses (clazz);
357 boolean has_write;
358 for (int i=0; i < hierarchy.length; i++)
360 currentObjectStreamClass = hierarchy[i];
362 fieldsAlreadyWritten = false;
363 has_write = currentObjectStreamClass.hasWriteMethod ();
365 writeFields (obj, currentObjectStreamClass.fields,
366 has_write);
370 currentObject = null;
371 currentObjectStreamClass = null;
372 currentPutField = null;
373 break;
376 throw new NotSerializableException (clazz.getName ());
377 } // end pseudo-loop
379 catch (ObjectStreamException ose)
381 // Rethrow these are fatal.
382 throw ose;
384 catch (IOException e)
386 realOutput.writeByte (TC_EXCEPTION);
387 reset (true);
389 setBlockDataMode (false);
392 writeObject (e);
394 catch (IOException ioe)
396 throw new StreamCorruptedException ("Exception " + ioe + " thrown while exception was being written to stream.");
399 reset (true);
401 finally
403 isSerializing = was_serializing;
405 setBlockDataMode (old_mode);
411 Writes the current objects non-transient, non-static fields from
412 the current class to the underlying output stream.
414 This method is intended to be called from within a object's
415 <code>private void writeObject (ObjectOutputStream)</code>
416 method.
418 @exception NotActiveException This method was called from a
419 context other than from the current object's and current class's
420 <code>private void writeObject (ObjectOutputStream)</code>
421 method.
423 @exception IOException Exception from underlying
424 <code>OutputStream</code>.
426 public void defaultWriteObject ()
427 throws IOException, NotActiveException
429 markFieldsWritten ();
430 writeFields (currentObject, currentObjectStreamClass.fields, false);
434 private void markFieldsWritten () throws IOException
436 if (currentObject == null || currentObjectStreamClass == null)
437 throw new NotActiveException ("defaultWriteObject called by non-active class and/or object");
439 if (fieldsAlreadyWritten)
440 throw new IOException ("Only one of putFields and defaultWriteObject may be called, and it may only be called once");
442 fieldsAlreadyWritten = true;
447 Resets stream to state equivalent to the state just after it was
448 constructed.
450 Causes all objects previously written to the stream to be
451 forgotten. A notification of this reset is also written to the
452 underlying stream.
454 @exception IOException Exception from underlying
455 <code>OutputStream</code> or reset called while serialization is
456 in progress.
458 public void reset () throws IOException
460 reset (false);
464 private void reset (boolean internal) throws IOException
466 if (!internal)
468 if (isSerializing)
469 throw new IOException ("Reset called while serialization in progress");
471 realOutput.writeByte (TC_RESET);
474 clearHandles ();
479 Informs this <code>ObjectOutputStream</code> to write data
480 according to the specified protocol. There are currently two
481 different protocols, specified by <code>PROTOCOL_VERSION_1</code>
482 and <code>PROTOCOL_VERSION_2</code>. This implementation writes
483 data using <code>PROTOCOL_VERSION_2</code> by default, as is done
484 by the JDK 1.2.
486 A non-portable method, <code>setDefaultProtocolVersion (int
487 version)</code> is provided to change the default protocol
488 version.
490 For an explination of the differences beween the two protocols
491 see XXX: the Java ObjectSerialization Specification.
493 @exception IOException if <code>version</code> is not a valid
494 protocol
496 @see setDefaultProtocolVersion (int)
498 public void useProtocolVersion (int version) throws IOException
500 if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
501 throw new IOException ("Invalid protocol version requested.");
503 protocolVersion = version;
508 <em>GNU $classpath specific</em>
510 Changes the default stream protocol used by all
511 <code>ObjectOutputStream</code>s. There are currently two
512 different protocols, specified by <code>PROTOCOL_VERSION_1</code>
513 and <code>PROTOCOL_VERSION_2</code>. The default default is
514 <code>PROTOCOL_VERSION_1</code>.
516 @exception IOException if <code>version</code> is not a valid
517 protocol
519 @see useProtocolVersion (int)
521 public static void setDefaultProtocolVersion (int version)
522 throws IOException
524 if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
525 throw new IOException ("Invalid protocol version requested.");
527 defaultProtocolVersion = version;
532 An empty hook that allows subclasses to write extra information
533 about classes to the stream. This method is called the first
534 time each class is seen, and after all of the standard
535 information about the class has been written.
537 @exception IOException Exception from underlying
538 <code>OutputStream</code>.
540 @see java.io.ObjectInputStream#resolveClass (java.io.ObjectStreamClass)
542 protected void annotateClass (Class cl) throws IOException
545 protected void annotateProxyClass(Class cl) throws IOException
549 Allows subclasses to replace objects that are written to the
550 stream with other objects to be written in their place. This
551 method is called the first time each object is encountered
552 (modulo reseting of the stream).
554 This method must be enabled before it will be called in the
555 serialization process.
557 @exception IOException Exception from underlying
558 <code>OutputStream</code>.
560 @see enableReplaceObject (boolean)
562 protected Object replaceObject (Object obj) throws IOException
564 return obj;
569 If <code>enable</code> is <code>true</code> and this object is
570 trusted, then <code>replaceObject (Object)</code> will be called
571 in subsequent calls to <code>writeObject (Object)</code>.
572 Otherwise, <code>replaceObject (Object)</code> will not be called.
574 @exception SecurityException This class is not trusted.
576 protected boolean enableReplaceObject (boolean enable)
577 throws SecurityException
579 if (enable)
581 SecurityManager sm = System.getSecurityManager ();
582 if (sm != null)
583 sm.checkPermission (new SerializablePermission ("enableSubstitution"));
586 boolean old_val = replacementEnabled;
587 replacementEnabled = enable;
588 return old_val;
593 Writes stream magic and stream version information to the
594 underlying stream.
596 @exception IOException Exception from underlying
597 <code>OutputStream</code>.
599 protected void writeStreamHeader () throws IOException
601 realOutput.writeShort (STREAM_MAGIC);
602 realOutput.writeShort (STREAM_VERSION);
608 Protected constructor that allows subclasses to override
609 serialization. This constructor should be called by subclasses
610 that wish to override <code>writeObject (Object)</code>. This
611 method does a security check <i>NOTE: currently not
612 implemented</i>, then sets a flag that informs
613 <code>writeObject (Object)</code> to call the subclasses
614 <code>writeObjectOverride (Object)</code> method.
616 @see writeObjectOverride (Object)
618 protected ObjectOutputStream () throws IOException, SecurityException
620 SecurityManager sec_man = System.getSecurityManager ();
621 if (sec_man != null)
622 sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
623 useSubclassMethod = true;
628 This method allows subclasses to override the default
629 serialization mechanism provided by
630 <code>ObjectOutputStream</code>. To make this method be used for
631 writing objects, subclasses must invoke the 0-argument
632 constructor on this class from there constructor.
634 @see ObjectOutputStream ()
636 @exception NotActiveException Subclass has arranged for this
637 method to be called, but did not implement this method.
639 protected void writeObjectOverride (Object obj) throws NotActiveException,
640 IOException
642 throw new NotActiveException ("Subclass of ObjectOutputStream must implement writeObjectOverride");
647 @see java.io.DataOutputStream#write (int)
649 public void write (int data) throws IOException
651 if (writeDataAsBlocks)
653 if (blockDataCount == BUFFER_SIZE)
654 drain ();
656 blockData[ blockDataCount++ ] = (byte)data;
658 else
659 realOutput.write (data);
664 @see java.io.DataOutputStream#write (byte[])
666 public void write (byte[] b) throws IOException
668 write (b, 0, b.length);
673 @see java.io.DataOutputStream#write (byte[],int,int)
675 public void write (byte[] b, int off, int len) throws IOException
677 if (writeDataAsBlocks)
679 if (len < 0)
680 throw new IndexOutOfBoundsException ();
682 if (blockDataCount + len < BUFFER_SIZE)
684 System.arraycopy (b, off, blockData, blockDataCount, len);
685 blockDataCount += len;
687 else
689 drain ();
690 writeBlockDataHeader (len);
691 realOutput.write (b, off, len);
694 else
695 realOutput.write (b, off, len);
700 @see java.io.DataOutputStream#flush ()
702 public void flush () throws IOException
704 drain ();
705 realOutput.flush ();
710 Causes the block-data buffer to be written to the underlying
711 stream, but does not flush underlying stream.
713 @exception IOException Exception from underlying
714 <code>OutputStream</code>.
716 protected void drain () throws IOException
718 if (blockDataCount == 0)
719 return;
721 if (writeDataAsBlocks)
722 writeBlockDataHeader (blockDataCount);
723 realOutput.write (blockData, 0, blockDataCount);
724 blockDataCount = 0;
729 @see java.io.DataOutputStream#close ()
731 public void close () throws IOException
733 flush ();
734 realOutput.close ();
739 @see java.io.DataOutputStream#writeBoolean (boolean)
741 public void writeBoolean (boolean data) throws IOException
743 blockDataOutput.writeBoolean (data);
748 @see java.io.DataOutputStream#writeByte (int)
750 public void writeByte (int data) throws IOException
752 blockDataOutput.writeByte (data);
757 @see java.io.DataOutputStream#writeShort (int)
759 public void writeShort (int data) throws IOException
761 blockDataOutput.writeShort (data);
766 @see java.io.DataOutputStream#writeChar (int)
768 public void writeChar (int data) throws IOException
770 blockDataOutput.writeChar (data);
775 @see java.io.DataOutputStream#writeInt (int)
777 public void writeInt (int data) throws IOException
779 blockDataOutput.writeInt (data);
784 @see java.io.DataOutputStream#writeLong (long)
786 public void writeLong (long data) throws IOException
788 blockDataOutput.writeLong (data);
793 @see java.io.DataOutputStream#writeFloat (float)
795 public void writeFloat (float data) throws IOException
797 blockDataOutput.writeFloat (data);
802 @see java.io.DataOutputStream#writeDouble (double)
804 public void writeDouble (double data) throws IOException
806 blockDataOutput.writeDouble (data);
811 @see java.io.DataOutputStream#writeBytes (java.lang.String)
813 public void writeBytes (String data) throws IOException
815 blockDataOutput.writeBytes (data);
820 @see java.io.DataOutputStream#writeChars (java.lang.String)
822 public void writeChars (String data) throws IOException
824 dataOutput.writeChars (data);
829 @see java.io.DataOutputStream#writeUTF (java.lang.String)
831 public void writeUTF (String data) throws IOException
833 dataOutput.writeUTF (data);
838 This class allows a class to specify exactly which fields should
839 be written, and what values should be written for these fields.
841 XXX: finish up comments
843 public static abstract class PutField
845 public abstract void put (String name, boolean value)
846 throws IOException, IllegalArgumentException;
847 public abstract void put (String name, byte value)
848 throws IOException, IllegalArgumentException;
849 public abstract void put (String name, char value)
850 throws IOException, IllegalArgumentException;
851 public abstract void put (String name, double value)
852 throws IOException, IllegalArgumentException;
853 public abstract void put (String name, float value)
854 throws IOException, IllegalArgumentException;
855 public abstract void put (String name, int value)
856 throws IOException, IllegalArgumentException;
857 public abstract void put (String name, long value)
858 throws IOException, IllegalArgumentException;
859 public abstract void put (String name, short value)
860 throws IOException, IllegalArgumentException;
861 public abstract void put (String name, Object value)
862 throws IOException, IllegalArgumentException;
863 public abstract void write (ObjectOutput out) throws IOException;
867 public PutField putFields () throws IOException
869 markFieldsWritten ();
871 currentPutField = new PutField ()
873 private byte[] prim_field_data
874 = new byte[currentObjectStreamClass.primFieldSize];
875 private Object[] objs
876 = new Object[currentObjectStreamClass.objectFieldCount];
878 public void put (String name, boolean value)
879 throws IOException, IllegalArgumentException
881 ObjectStreamField field
882 = currentObjectStreamClass.getField (name);
883 checkType (field, 'Z');
884 prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
887 public void put (String name, byte value)
888 throws IOException, IllegalArgumentException
890 ObjectStreamField field
891 = currentObjectStreamClass.getField (name);
892 checkType (field, 'B');
893 prim_field_data[field.getOffset ()] = value;
896 public void put (String name, char value)
897 throws IOException, IllegalArgumentException
899 ObjectStreamField field
900 = currentObjectStreamClass.getField (name);
901 checkType (field, 'C');
902 int off = field.getOffset ();
903 prim_field_data[off++] = (byte)(value >>> 8);
904 prim_field_data[off] = (byte)value;
907 public void put (String name, double value)
908 throws IOException, IllegalArgumentException
910 ObjectStreamField field
911 = currentObjectStreamClass.getField (name);
912 checkType (field, 'D');
913 int off = field.getOffset ();
914 long l_value = Double.doubleToLongBits (value);
915 prim_field_data[off++] = (byte)(l_value >>> 52);
916 prim_field_data[off++] = (byte)(l_value >>> 48);
917 prim_field_data[off++] = (byte)(l_value >>> 40);
918 prim_field_data[off++] = (byte)(l_value >>> 32);
919 prim_field_data[off++] = (byte)(l_value >>> 24);
920 prim_field_data[off++] = (byte)(l_value >>> 16);
921 prim_field_data[off++] = (byte)(l_value >>> 8);
922 prim_field_data[off] = (byte)l_value;
925 public void put (String name, float value)
926 throws IOException, IllegalArgumentException
928 ObjectStreamField field
929 = currentObjectStreamClass.getField (name);
930 checkType (field, 'F');
931 int off = field.getOffset ();
932 int i_value = Float.floatToIntBits (value);
933 prim_field_data[off++] = (byte)(i_value >>> 24);
934 prim_field_data[off++] = (byte)(i_value >>> 16);
935 prim_field_data[off++] = (byte)(i_value >>> 8);
936 prim_field_data[off] = (byte)i_value;
939 public void put (String name, int value)
940 throws IOException, IllegalArgumentException
942 ObjectStreamField field
943 = currentObjectStreamClass.getField (name);
944 checkType (field, 'I');
945 int off = field.getOffset ();
946 prim_field_data[off++] = (byte)(value >>> 24);
947 prim_field_data[off++] = (byte)(value >>> 16);
948 prim_field_data[off++] = (byte)(value >>> 8);
949 prim_field_data[off] = (byte)value;
952 public void put (String name, long value)
953 throws IOException, IllegalArgumentException
955 ObjectStreamField field
956 = currentObjectStreamClass.getField (name);
957 checkType (field, 'J');
958 int off = field.getOffset ();
959 prim_field_data[off++] = (byte)(value >>> 52);
960 prim_field_data[off++] = (byte)(value >>> 48);
961 prim_field_data[off++] = (byte)(value >>> 40);
962 prim_field_data[off++] = (byte)(value >>> 32);
963 prim_field_data[off++] = (byte)(value >>> 24);
964 prim_field_data[off++] = (byte)(value >>> 16);
965 prim_field_data[off++] = (byte)(value >>> 8);
966 prim_field_data[off] = (byte)value;
969 public void put (String name, short value)
970 throws IOException, IllegalArgumentException
972 ObjectStreamField field
973 = currentObjectStreamClass.getField (name);
974 checkType (field, 'S');
975 int off = field.getOffset ();
976 prim_field_data[off++] = (byte)(value >>> 8);
977 prim_field_data[off] = (byte)value;
980 public void put (String name, Object value)
981 throws IOException, IllegalArgumentException
983 ObjectStreamField field
984 = currentObjectStreamClass.getField (name);
985 if (field == null)
986 throw new IllegalArgumentException ();
987 if (value != null &&
988 ! field.getType ().isAssignableFrom (value.getClass ()))
989 throw new IllegalArgumentException ();
990 objs[field.getOffset ()] = value;
993 public void write (ObjectOutput out) throws IOException
995 // Apparently Block data is not used with PutField as per
996 // empirical evidence against JDK 1.2. Also see Mauve test
997 // java.io.ObjectInputOutput.Test.GetPutField.
998 boolean oldmode = setBlockDataMode (false);
999 out.write (prim_field_data);
1000 for (int i = 0; i < objs.length; ++ i)
1001 out.writeObject (objs[i]);
1002 setBlockDataMode (oldmode);
1005 private void checkType (ObjectStreamField field, char type)
1006 throws IllegalArgumentException
1008 if (TypeSignature.getEncodingOfClass (field.getType ()).charAt (0) != type)
1009 throw new IllegalArgumentException ();
1012 // end PutFieldImpl
1014 return currentPutField;
1018 public void writeFields () throws IOException
1020 if (currentPutField == null)
1021 throw new NotActiveException ("writeFields can only be called after putFields has been called");
1023 currentPutField.write (this);
1027 // write out the block-data buffer, picking the correct header
1028 // depending on the size of the buffer
1029 private void writeBlockDataHeader (int size) throws IOException
1031 if (size < 256)
1033 realOutput.writeByte (TC_BLOCKDATA);
1034 realOutput.write (size);
1036 else
1038 realOutput.writeByte (TC_BLOCKDATALONG);
1039 realOutput.writeInt (size);
1044 // lookup the handle for OBJ, return null if OBJ doesn't have a
1045 // handle yet
1046 private Integer findHandle (Object obj)
1048 return (Integer)OIDLookupTable.get (new ObjectIdentityWrapper (obj));
1052 // assigns the next availible handle to OBJ
1053 private int assignNewHandle (Object obj)
1055 OIDLookupTable.put (new ObjectIdentityWrapper (obj),
1056 new Integer (nextOID));
1057 return nextOID++;
1061 // resets mapping from objects to handles
1062 private void clearHandles ()
1064 nextOID = baseWireHandle;
1065 OIDLookupTable.clear ();
1069 // write out array size followed by each element of the array
1070 private void writeArraySizeAndElements (Object array, Class clazz)
1071 throws IOException
1073 int length = Array.getLength (array);
1075 if (clazz.isPrimitive ())
1077 if (clazz == Boolean.TYPE)
1079 boolean[] cast_array = (boolean[])array;
1080 realOutput.writeInt (length);
1081 for (int i=0; i < length; i++)
1082 realOutput.writeBoolean (cast_array[i]);
1083 return;
1085 if (clazz == Byte.TYPE)
1087 byte[] cast_array = (byte[])array;
1088 realOutput.writeInt (length);
1089 realOutput.write(cast_array, 0, length);
1090 return;
1092 if (clazz == Character.TYPE)
1094 char[] cast_array = (char[])array;
1095 realOutput.writeInt (length);
1096 for (int i=0; i < length; i++)
1097 realOutput.writeChar (cast_array[i]);
1098 return;
1100 if (clazz == Double.TYPE)
1102 double[] cast_array = (double[])array;
1103 realOutput.writeInt (length);
1104 for (int i=0; i < length; i++)
1105 realOutput.writeDouble (cast_array[i]);
1106 return;
1108 if (clazz == Float.TYPE)
1110 float[] cast_array = (float[])array;
1111 realOutput.writeInt (length);
1112 for (int i=0; i < length; i++)
1113 realOutput.writeFloat (cast_array[i]);
1114 return;
1116 if (clazz == Integer.TYPE)
1118 int[] cast_array = (int[])array;
1119 realOutput.writeInt (length);
1120 for (int i=0; i < length; i++)
1121 realOutput.writeInt (cast_array[i]);
1122 return;
1124 if (clazz == Long.TYPE)
1126 long[] cast_array = (long[])array;
1127 realOutput.writeInt (length);
1128 for (int i=0; i < length; i++)
1129 realOutput.writeLong (cast_array[i]);
1130 return;
1132 if (clazz == Short.TYPE)
1134 short[] cast_array = (short[])array;
1135 realOutput.writeInt (length);
1136 for (int i=0; i < length; i++)
1137 realOutput.writeShort (cast_array[i]);
1138 return;
1141 else
1143 Object[] cast_array = (Object[])array;
1144 realOutput.writeInt (length);
1145 for (int i=0; i < length; i++)
1146 writeObject (cast_array[i]);
1151 // writes out FIELDS of OBJECT. If CALL_WRITE_METHOD is true, use
1152 // object's writeObject (ObjectOutputStream), otherwise use default
1153 // serialization. FIELDS are already in canonical order.
1154 private void writeFields (Object obj,
1155 ObjectStreamField[] fields,
1156 boolean call_write_method) throws IOException
1158 if (call_write_method)
1160 setBlockDataMode (true);
1161 callWriteMethod (obj);
1162 setBlockDataMode (false);
1163 realOutput.writeByte (TC_ENDBLOCKDATA);
1164 return;
1167 boolean oldmode = setBlockDataMode (false);
1168 String field_name;
1169 Class type;
1170 for (int i=0; i < fields.length; i++)
1172 field_name = fields[i].getName ();
1173 type = fields[i].getType ();
1175 if (type == Boolean.TYPE)
1176 realOutput.writeBoolean (getBooleanField (obj, field_name));
1177 else if (type == Byte.TYPE)
1178 realOutput.writeByte (getByteField (obj, field_name));
1179 else if (type == Character.TYPE)
1180 realOutput.writeChar (getCharField (obj, field_name));
1181 else if (type == Double.TYPE)
1182 realOutput.writeDouble (getDoubleField (obj, field_name));
1183 else if (type == Float.TYPE)
1184 realOutput.writeFloat (getFloatField (obj, field_name));
1185 else if (type == Integer.TYPE)
1186 realOutput.writeInt (getIntField (obj, field_name));
1187 else if (type == Long.TYPE)
1188 realOutput.writeLong (getLongField (obj, field_name));
1189 else if (type == Short.TYPE)
1190 realOutput.writeShort (getShortField (obj, field_name));
1191 else
1192 writeObject (getObjectField (obj, field_name,
1193 fields[i].getTypeString ()));
1195 setBlockDataMode(oldmode);
1199 // Toggles writing primitive data to block-data buffer.
1200 private boolean setBlockDataMode (boolean on) throws IOException
1202 if (on == writeDataAsBlocks)
1203 return on;
1205 drain();
1206 boolean oldmode = writeDataAsBlocks;
1207 writeDataAsBlocks = on;
1209 if (on)
1210 dataOutput = blockDataOutput;
1211 else
1212 dataOutput = realOutput;
1214 return oldmode;
1218 private void callWriteMethod (Object obj) throws IOException
1220 Class klass = obj.getClass ();
1223 Class classArgs[] = {ObjectOutputStream.class};
1224 Method m = getMethod (klass, "writeObject", classArgs);
1225 if (m == null)
1226 return;
1227 Object args[] = {this};
1228 m.invoke (obj, args);
1230 catch (InvocationTargetException x)
1232 /* Rethrow if possible. */
1233 Throwable exception = x.getTargetException();
1234 if (exception instanceof RuntimeException)
1235 throw (RuntimeException) exception;
1236 if (exception instanceof IOException)
1237 throw (IOException) exception;
1239 throw new IOException ("Exception thrown from writeObject() on " +
1240 klass + ": " + exception.getClass().getName());
1242 catch (Exception x)
1244 throw new IOException ("Failure invoking writeObject() on " +
1245 klass + ": " + x.getClass().getName());
1249 private boolean getBooleanField (Object obj, String field_name) throws IOException
1253 Class klass = obj.getClass ();
1254 Field f = getField (klass, field_name);
1255 boolean b = f.getBoolean (obj);
1256 return b;
1258 catch (Exception _)
1260 throw new IOException ();
1264 private byte getByteField (Object obj, String field_name) throws IOException
1268 Class klass = obj.getClass ();
1269 Field f = getField (klass, field_name);
1270 byte b = f.getByte (obj);
1271 return b;
1273 catch (Exception _)
1275 throw new IOException ();
1279 private char getCharField (Object obj, String field_name) throws IOException
1283 Class klass = obj.getClass ();
1284 Field f = getField (klass, field_name);
1285 char b = f.getChar (obj);
1286 return b;
1288 catch (Exception _)
1290 throw new IOException ();
1294 private double getDoubleField (Object obj, String field_name) throws IOException
1298 Class klass = obj.getClass ();
1299 Field f = getField (klass, field_name);
1300 double b = f.getDouble (obj);
1301 return b;
1303 catch (Exception _)
1305 throw new IOException ();
1309 private float getFloatField (Object obj, String field_name) throws IOException
1313 Class klass = obj.getClass ();
1314 Field f = getField (klass, field_name);
1315 float b = f.getFloat (obj);
1316 return b;
1318 catch (Exception _)
1320 throw new IOException ();
1324 private int getIntField (Object obj, String field_name) throws IOException
1328 Class klass = obj.getClass ();
1329 Field f = getField (klass, field_name);
1330 int b = f.getInt (obj);
1331 return b;
1333 catch (Exception _)
1335 throw new IOException ();
1339 private long getLongField (Object obj, String field_name) throws IOException
1343 Class klass = obj.getClass ();
1344 Field f = getField (klass, field_name);
1345 long b = f.getLong (obj);
1346 return b;
1348 catch (Exception _)
1350 throw new IOException ();
1354 private short getShortField (Object obj, String field_name) throws IOException
1358 Class klass = obj.getClass ();
1359 Field f = getField (klass, field_name);
1360 short b = f.getShort (obj);
1361 return b;
1363 catch (Exception _)
1365 throw new IOException ();
1369 private Object getObjectField (Object obj, String field_name,
1370 String type_code) throws IOException
1374 Class klass = obj.getClass ();
1375 Field f = getField (klass, field_name);
1376 Object o = f.get (obj);
1377 // FIXME: We should check the type_code here
1378 return o;
1380 catch (Exception _)
1382 throw new IOException ();
1386 private static Field getField (Class klass, String name)
1387 throws java.lang.NoSuchFieldException
1389 return klass.getDeclaredField(name);
1392 private static Method getMethod (Class klass, String name, Class[] args)
1393 throws java.lang.NoSuchMethodException
1395 return klass.getDeclaredMethod(name, args);
1398 // this value comes from 1.2 spec, but is used in 1.1 as well
1399 private final static int BUFFER_SIZE = 1024;
1401 private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
1403 private DataOutputStream dataOutput;
1404 private boolean writeDataAsBlocks;
1405 private DataOutputStream realOutput;
1406 private DataOutputStream blockDataOutput;
1407 private byte[] blockData;
1408 private int blockDataCount;
1409 private Object currentObject;
1410 private ObjectStreamClass currentObjectStreamClass;
1411 private PutField currentPutField;
1412 private boolean fieldsAlreadyWritten;
1413 private boolean replacementEnabled;
1414 private boolean isSerializing;
1415 private int nextOID;
1416 private Hashtable OIDLookupTable;
1417 private int protocolVersion;
1418 private boolean useSubclassMethod;
1420 static
1422 if (Configuration.INIT_LOAD_LIBRARY)
1424 System.loadLibrary ("javaio");