Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / java / io / ObjectOutputStream.java
blob573b9cfa1de4e6e1086fe160e925cd4191f9308b
1 /* ObjectOutputStream.java -- Class used to write serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.io;
42 import gnu.java.io.ObjectIdentityWrapper;
43 import gnu.java.lang.reflect.TypeSignature;
44 import gnu.java.security.action.SetAccessibleAction;
46 import java.lang.reflect.Array;
47 import java.lang.reflect.Field;
48 import java.lang.reflect.InvocationTargetException;
49 import java.lang.reflect.Method;
50 import java.security.AccessController;
51 import java.util.Hashtable;
53 /**
54 * An <code>ObjectOutputStream</code> can be used to write objects
55 * as well as primitive data in a platform-independent manner to an
56 * <code>OutputStream</code>.
58 * The data produced by an <code>ObjectOutputStream</code> can be read
59 * and reconstituted by an <code>ObjectInputStream</code>.
61 * <code>writeObject (Object)</code> is used to write Objects, the
62 * <code>write&lt;type&gt;</code> methods are used to write primitive
63 * data (as in <code>DataOutputStream</code>). Strings can be written
64 * as objects or as primitive data.
66 * Not all objects can be written out using an
67 * <code>ObjectOutputStream</code>. Only those objects that are an
68 * instance of <code>java.io.Serializable</code> can be written.
70 * Using default serialization, information about the class of an
71 * object is written, all of the non-transient, non-static fields of
72 * the object are written, if any of these fields are objects, they are
73 * written out in the same manner.
75 * An object is only written out the first time it is encountered. If
76 * the object is encountered later, a reference to it is written to
77 * the underlying stream. Thus writing circular object graphs
78 * does not present a problem, nor are relationships between objects
79 * in a graph lost.
81 * Example usage:
82 * <pre>
83 * Hashtable map = new Hashtable ();
84 * map.put ("one", new Integer (1));
85 * map.put ("two", new Integer (2));
87 * ObjectOutputStream oos =
88 * new ObjectOutputStream (new FileOutputStream ("numbers"));
89 * oos.writeObject (map);
90 * oos.close ();
92 * ObjectInputStream ois =
93 * new ObjectInputStream (new FileInputStream ("numbers"));
94 * Hashtable newmap = (Hashtable)ois.readObject ();
96 * System.out.println (newmap);
97 * </pre>
99 * The default serialization can be overriden in two ways.
101 * By defining a method <code>private void
102 * writeObject (ObjectOutputStream)</code>, a class can dictate exactly
103 * how information about itself is written.
104 * <code>defaultWriteObject ()</code> may be called from this method to
105 * carry out default serialization. This method is not
106 * responsible for dealing with fields of super-classes or subclasses.
108 * By implementing <code>java.io.Externalizable</code>. This gives
109 * the class complete control over the way it is written to the
110 * stream. If this approach is used the burden of writing superclass
111 * and subclass data is transfered to the class implementing
112 * <code>java.io.Externalizable</code>.
114 * @see java.io.DataOutputStream
115 * @see java.io.Externalizable
116 * @see java.io.ObjectInputStream
117 * @see java.io.Serializable
119 public class ObjectOutputStream extends OutputStream
120 implements ObjectOutput, ObjectStreamConstants
123 * Creates a new <code>ObjectOutputStream</code> that will do all of
124 * its writing onto <code>out</code>. This method also initializes
125 * the stream by writing the header information (stream magic number
126 * and stream version).
128 * @exception IOException Writing stream header to underlying
129 * stream cannot be completed.
131 * @see #writeStreamHeader()
133 public ObjectOutputStream (OutputStream out) throws IOException
135 realOutput = new DataOutputStream(out);
136 blockData = new byte[ BUFFER_SIZE ];
137 blockDataCount = 0;
138 blockDataOutput = new DataOutputStream(this);
139 setBlockDataMode(true);
140 replacementEnabled = false;
141 isSerializing = false;
142 nextOID = baseWireHandle;
143 OIDLookupTable = new Hashtable();
144 protocolVersion = defaultProtocolVersion;
145 useSubclassMethod = false;
146 writeStreamHeader();
148 if (DEBUG)
150 String val = System.getProperty("gcj.dumpobjects");
151 if (val != null && !val.equals(""))
152 dump = true;
157 * Writes a representation of <code>obj</code> to the underlying
158 * output stream by writing out information about its class, then
159 * writing out each of the objects non-transient, non-static
160 * fields. If any of these fields are other objects,
161 * they are written out in the same manner.
163 * This method can be overriden by a class by implementing
164 * <code>private void writeObject (ObjectOutputStream)</code>.
166 * If an exception is thrown from this method, the stream is left in
167 * an undefined state.
169 * @exception NotSerializableException An attempt was made to
170 * serialize an <code>Object</code> that is not serializable.
172 * @exception InvalidClassException Somebody tried to serialize
173 * an object which is wrongly formatted.
175 * @exception IOException Exception from underlying
176 * <code>OutputStream</code>.
178 public final void writeObject(Object obj) throws IOException
180 if (useSubclassMethod)
182 if (dump)
183 dumpElementln ("WRITE OVERRIDE: " + obj);
185 writeObjectOverride(obj);
186 return;
189 if (dump)
190 dumpElementln ("WRITE: " + obj);
192 depth += 2;
194 boolean was_serializing = isSerializing;
195 boolean old_mode = setBlockDataMode(false);
198 isSerializing = true;
199 boolean replaceDone = false;
200 Object replacedObject = null;
202 while (true)
204 if (obj == null)
206 realOutput.writeByte(TC_NULL);
207 break;
210 Integer handle = findHandle(obj);
211 if (handle != null)
213 realOutput.writeByte(TC_REFERENCE);
214 realOutput.writeInt(handle.intValue());
215 break;
218 if (obj instanceof Class)
220 Class cl = (Class)obj;
221 ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
222 realOutput.writeByte(TC_CLASS);
223 if (!osc.isProxyClass)
225 writeObject (osc);
227 else
229 realOutput.writeByte(TC_PROXYCLASSDESC);
230 Class[] intfs = cl.getInterfaces();
231 realOutput.writeInt(intfs.length);
232 for (int i = 0; i < intfs.length; i++)
233 realOutput.writeUTF(intfs[i].getName());
235 boolean oldmode = setBlockDataMode(true);
236 annotateProxyClass(cl);
237 setBlockDataMode(oldmode);
238 realOutput.writeByte(TC_ENDBLOCKDATA);
240 writeObject(osc.getSuper());
242 assignNewHandle(obj);
243 break;
246 if (obj instanceof ObjectStreamClass)
248 writeClassDescriptor((ObjectStreamClass) obj);
249 break;
252 Class clazz = obj.getClass();
253 ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
254 if (osc == null)
255 throw new NotSerializableException(clazz.getName());
257 if ((replacementEnabled || obj instanceof Serializable)
258 && ! replaceDone)
260 replacedObject = obj;
262 if (obj instanceof Serializable)
266 Method m = osc.writeReplaceMethod;
267 if (m != null)
268 obj = m.invoke(obj, new Object[0]);
270 catch (IllegalAccessException ignore)
273 catch (InvocationTargetException ignore)
278 if (replacementEnabled)
279 obj = replaceObject(obj);
281 replaceDone = true;
282 continue;
285 if (obj instanceof String)
287 realOutput.writeByte(TC_STRING);
288 assignNewHandle(obj);
289 realOutput.writeUTF((String)obj);
290 break;
293 if (clazz.isArray ())
295 realOutput.writeByte(TC_ARRAY);
296 writeObject(osc);
297 assignNewHandle(obj);
298 writeArraySizeAndElements(obj, clazz.getComponentType());
299 break;
302 realOutput.writeByte(TC_OBJECT);
303 writeObject(osc);
305 if (replaceDone)
306 assignNewHandle(replacedObject);
307 else
308 assignNewHandle(obj);
310 if (obj instanceof Externalizable)
312 if (protocolVersion == PROTOCOL_VERSION_2)
313 setBlockDataMode(true);
315 ((Externalizable)obj).writeExternal(this);
317 if (protocolVersion == PROTOCOL_VERSION_2)
319 setBlockDataMode(false);
320 realOutput.writeByte(TC_ENDBLOCKDATA);
323 break;
326 if (obj instanceof Serializable)
328 Object prevObject = this.currentObject;
329 ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
330 currentObject = obj;
331 ObjectStreamClass[] hierarchy =
332 ObjectStreamClass.getObjectStreamClasses(clazz);
334 for (int i = 0; i < hierarchy.length; i++)
336 currentObjectStreamClass = hierarchy[i];
338 fieldsAlreadyWritten = false;
339 if (currentObjectStreamClass.hasWriteMethod())
341 if (dump)
342 dumpElementln ("WRITE METHOD CALLED FOR: " + obj);
343 setBlockDataMode(true);
344 callWriteMethod(obj, currentObjectStreamClass);
345 setBlockDataMode(false);
346 realOutput.writeByte(TC_ENDBLOCKDATA);
347 if (dump)
348 dumpElementln ("WRITE ENDBLOCKDATA FOR: " + obj);
350 else
352 if (dump)
353 dumpElementln ("WRITE FIELDS CALLED FOR: " + obj);
354 writeFields(obj, currentObjectStreamClass);
358 this.currentObject = prevObject;
359 this.currentObjectStreamClass = prevObjectStreamClass;
360 currentPutField = null;
361 break;
364 throw new NotSerializableException(clazz.getName()
365 + " in "
366 + obj.getClass());
367 } // end pseudo-loop
369 catch (ObjectStreamException ose)
371 // Rethrow these are fatal.
372 throw ose;
374 catch (IOException e)
376 realOutput.writeByte(TC_EXCEPTION);
377 reset(true);
379 setBlockDataMode(false);
382 if (DEBUG)
384 e.printStackTrace(System.out);
386 writeObject(e);
388 catch (IOException ioe)
390 StreamCorruptedException ex =
391 new StreamCorruptedException
392 (ioe + " thrown while exception was being written to stream.");
393 if (DEBUG)
395 ex.printStackTrace(System.out);
397 throw ex;
400 reset (true);
403 finally
405 isSerializing = was_serializing;
406 setBlockDataMode(old_mode);
407 depth -= 2;
409 if (dump)
410 dumpElementln ("END: " + obj);
414 protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException
416 if (osc.isProxyClass)
418 realOutput.writeByte(TC_PROXYCLASSDESC);
419 Class[] intfs = osc.forClass().getInterfaces();
420 realOutput.writeInt(intfs.length);
421 for (int i = 0; i < intfs.length; i++)
422 realOutput.writeUTF(intfs[i].getName());
424 boolean oldmode = setBlockDataMode(true);
425 annotateProxyClass(osc.forClass());
426 setBlockDataMode(oldmode);
427 realOutput.writeByte(TC_ENDBLOCKDATA);
429 else
431 realOutput.writeByte(TC_CLASSDESC);
432 realOutput.writeUTF(osc.getName());
433 realOutput.writeLong(osc.getSerialVersionUID());
434 assignNewHandle(osc);
436 int flags = osc.getFlags();
438 if (protocolVersion == PROTOCOL_VERSION_2
439 && osc.isExternalizable())
440 flags |= SC_BLOCK_DATA;
442 realOutput.writeByte(flags);
444 ObjectStreamField[] fields = osc.fields;
445 realOutput.writeShort(fields.length);
447 ObjectStreamField field;
448 for (int i = 0; i < fields.length; i++)
450 field = fields[i];
451 realOutput.writeByte(field.getTypeCode ());
452 realOutput.writeUTF(field.getName ());
454 if (! field.isPrimitive())
455 writeObject(field.getTypeString());
458 boolean oldmode = setBlockDataMode(true);
459 annotateClass(osc.forClass());
460 setBlockDataMode(oldmode);
461 realOutput.writeByte(TC_ENDBLOCKDATA);
464 if (osc.isSerializable() || osc.isExternalizable())
465 writeObject(osc.getSuper());
466 else
467 writeObject(null);
471 * Writes the current objects non-transient, non-static fields from
472 * the current class to the underlying output stream.
474 * This method is intended to be called from within a object's
475 * <code>private void writeObject (ObjectOutputStream)</code>
476 * method.
478 * @exception NotActiveException This method was called from a
479 * context other than from the current object's and current class's
480 * <code>private void writeObject (ObjectOutputStream)</code>
481 * method.
483 * @exception IOException Exception from underlying
484 * <code>OutputStream</code>.
486 public void defaultWriteObject()
487 throws IOException, NotActiveException
489 markFieldsWritten();
490 writeFields(currentObject, currentObjectStreamClass);
494 private void markFieldsWritten() throws IOException
496 if (currentObject == null || currentObjectStreamClass == null)
497 throw new NotActiveException
498 ("defaultWriteObject called by non-active class and/or object");
500 if (fieldsAlreadyWritten)
501 throw new IOException
502 ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once");
504 fieldsAlreadyWritten = true;
508 * Resets stream to state equivalent to the state just after it was
509 * constructed.
511 * Causes all objects previously written to the stream to be
512 * forgotten. A notification of this reset is also written to the
513 * underlying stream.
515 * @exception IOException Exception from underlying
516 * <code>OutputStream</code> or reset called while serialization is
517 * in progress.
519 public void reset() throws IOException
521 reset(false);
525 private void reset(boolean internal) throws IOException
527 if (!internal)
529 if (isSerializing)
530 throw new IOException("Reset called while serialization in progress");
532 realOutput.writeByte(TC_RESET);
535 clearHandles();
540 * Informs this <code>ObjectOutputStream</code> to write data
541 * according to the specified protocol. There are currently two
542 * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
543 * and <code>PROTOCOL_VERSION_2</code>. This implementation writes
544 * data using <code>PROTOCOL_VERSION_2</code> by default, as is done
545 * by the JDK 1.2.
547 * A non-portable method, <code>setDefaultProtocolVersion (int
548 * version)</code> is provided to change the default protocol
549 * version.
551 * For an explanation of the differences between the two protocols
552 * see XXX: the Java ObjectSerialization Specification.
554 * @exception IOException if <code>version</code> is not a valid
555 * protocol
557 * @see #setDefaultProtocolVersion(int)
559 public void useProtocolVersion(int version) throws IOException
561 if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
562 throw new IOException("Invalid protocol version requested.");
564 protocolVersion = version;
569 * <em>GNU $classpath specific</em>
571 * Changes the default stream protocol used by all
572 * <code>ObjectOutputStream</code>s. There are currently two
573 * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
574 * and <code>PROTOCOL_VERSION_2</code>. The default default is
575 * <code>PROTOCOL_VERSION_1</code>.
577 * @exception IOException if <code>version</code> is not a valid
578 * protocol
580 * @see #useProtocolVersion(int)
582 public static void setDefaultProtocolVersion(int version)
583 throws IOException
585 if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
586 throw new IOException("Invalid protocol version requested.");
588 defaultProtocolVersion = version;
593 * An empty hook that allows subclasses to write extra information
594 * about classes to the stream. This method is called the first
595 * time each class is seen, and after all of the standard
596 * information about the class has been written.
598 * @exception IOException Exception from underlying
599 * <code>OutputStream</code>.
601 * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
603 protected void annotateClass(Class cl) throws IOException
607 protected void annotateProxyClass(Class cl) throws IOException
612 * Allows subclasses to replace objects that are written to the
613 * stream with other objects to be written in their place. This
614 * method is called the first time each object is encountered
615 * (modulo reseting of the stream).
617 * This method must be enabled before it will be called in the
618 * serialization process.
620 * @exception IOException Exception from underlying
621 * <code>OutputStream</code>.
623 * @see #enableReplaceObject(boolean)
625 protected Object replaceObject(Object obj) throws IOException
627 return obj;
632 * If <code>enable</code> is <code>true</code> and this object is
633 * trusted, then <code>replaceObject (Object)</code> will be called
634 * in subsequent calls to <code>writeObject (Object)</code>.
635 * Otherwise, <code>replaceObject (Object)</code> will not be called.
637 * @exception SecurityException This class is not trusted.
639 protected boolean enableReplaceObject(boolean enable)
640 throws SecurityException
642 if (enable)
644 SecurityManager sm = System.getSecurityManager();
645 if (sm != null)
646 sm.checkPermission(new SerializablePermission("enableSubstitution"));
649 boolean old_val = replacementEnabled;
650 replacementEnabled = enable;
651 return old_val;
656 * Writes stream magic and stream version information to the
657 * underlying stream.
659 * @exception IOException Exception from underlying
660 * <code>OutputStream</code>.
662 protected void writeStreamHeader() throws IOException
664 realOutput.writeShort(STREAM_MAGIC);
665 realOutput.writeShort(STREAM_VERSION);
669 * Protected constructor that allows subclasses to override
670 * serialization. This constructor should be called by subclasses
671 * that wish to override <code>writeObject (Object)</code>. This
672 * method does a security check <i>NOTE: currently not
673 * implemented</i>, then sets a flag that informs
674 * <code>writeObject (Object)</code> to call the subclasses
675 * <code>writeObjectOverride (Object)</code> method.
677 * @see #writeObjectOverride(Object)
679 protected ObjectOutputStream() throws IOException, SecurityException
681 SecurityManager sec_man = System.getSecurityManager ();
682 if (sec_man != null)
683 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
684 useSubclassMethod = true;
689 * This method allows subclasses to override the default
690 * serialization mechanism provided by
691 * <code>ObjectOutputStream</code>. To make this method be used for
692 * writing objects, subclasses must invoke the 0-argument
693 * constructor on this class from there constructor.
695 * @see #ObjectOutputStream()
697 * @exception NotActiveException Subclass has arranged for this
698 * method to be called, but did not implement this method.
700 protected void writeObjectOverride(Object obj) throws NotActiveException,
701 IOException
703 throw new NotActiveException
704 ("Subclass of ObjectOutputStream must implement writeObjectOverride");
709 * @see DataOutputStream#write(int)
711 public void write (int data) throws IOException
713 if (writeDataAsBlocks)
715 if (blockDataCount == BUFFER_SIZE)
716 drain();
718 blockData[ blockDataCount++ ] = (byte)data;
720 else
721 realOutput.write(data);
726 * @see DataOutputStream#write(byte[])
728 public void write(byte[] b) throws IOException
730 write(b, 0, b.length);
735 * @see DataOutputStream#write(byte[],int,int)
737 public void write(byte[] b, int off, int len) throws IOException
739 if (writeDataAsBlocks)
741 if (len < 0)
742 throw new IndexOutOfBoundsException();
744 if (blockDataCount + len < BUFFER_SIZE)
746 System.arraycopy(b, off, blockData, blockDataCount, len);
747 blockDataCount += len;
749 else
751 drain();
752 writeBlockDataHeader(len);
753 realOutput.write(b, off, len);
756 else
757 realOutput.write(b, off, len);
762 * @see DataOutputStream#flush()
764 public void flush () throws IOException
766 drain();
767 realOutput.flush();
772 * Causes the block-data buffer to be written to the underlying
773 * stream, but does not flush underlying stream.
775 * @exception IOException Exception from underlying
776 * <code>OutputStream</code>.
778 protected void drain() throws IOException
780 if (blockDataCount == 0)
781 return;
783 if (writeDataAsBlocks)
784 writeBlockDataHeader(blockDataCount);
785 realOutput.write(blockData, 0, blockDataCount);
786 blockDataCount = 0;
791 * @see java.io.DataOutputStream#close ()
793 public void close() throws IOException
795 flush();
796 realOutput.close();
801 * @see java.io.DataOutputStream#writeBoolean (boolean)
803 public void writeBoolean(boolean data) throws IOException
805 blockDataOutput.writeBoolean(data);
810 * @see java.io.DataOutputStream#writeByte (int)
812 public void writeByte(int data) throws IOException
814 blockDataOutput.writeByte(data);
819 * @see java.io.DataOutputStream#writeShort (int)
821 public void writeShort (int data) throws IOException
823 blockDataOutput.writeShort(data);
828 * @see java.io.DataOutputStream#writeChar (int)
830 public void writeChar(int data) throws IOException
832 blockDataOutput.writeChar(data);
837 * @see java.io.DataOutputStream#writeInt (int)
839 public void writeInt(int data) throws IOException
841 blockDataOutput.writeInt(data);
846 * @see java.io.DataOutputStream#writeLong (long)
848 public void writeLong(long data) throws IOException
850 blockDataOutput.writeLong(data);
855 * @see java.io.DataOutputStream#writeFloat (float)
857 public void writeFloat(float data) throws IOException
859 blockDataOutput.writeFloat(data);
864 * @see java.io.DataOutputStream#writeDouble (double)
866 public void writeDouble(double data) throws IOException
868 blockDataOutput.writeDouble(data);
873 * @see java.io.DataOutputStream#writeBytes (java.lang.String)
875 public void writeBytes(String data) throws IOException
877 blockDataOutput.writeBytes(data);
882 * @see java.io.DataOutputStream#writeChars (java.lang.String)
884 public void writeChars(String data) throws IOException
886 dataOutput.writeChars(data);
891 * @see java.io.DataOutputStream#writeUTF (java.lang.String)
893 public void writeUTF(String data) throws IOException
895 dataOutput.writeUTF(data);
900 * This class allows a class to specify exactly which fields should
901 * be written, and what values should be written for these fields.
903 * XXX: finish up comments
905 public abstract static class PutField
907 public abstract void put (String name, boolean value);
908 public abstract void put (String name, byte value);
909 public abstract void put (String name, char value);
910 public abstract void put (String name, double value);
911 public abstract void put (String name, float value);
912 public abstract void put (String name, int value);
913 public abstract void put (String name, long value);
914 public abstract void put (String name, short value);
915 public abstract void put (String name, Object value);
918 * @deprecated
920 public abstract void write (ObjectOutput out) throws IOException;
923 public PutField putFields() throws IOException
925 if (currentPutField != null)
926 return currentPutField;
928 currentPutField = new PutField()
930 private byte[] prim_field_data
931 = new byte[currentObjectStreamClass.primFieldSize];
932 private Object[] objs
933 = new Object[currentObjectStreamClass.objectFieldCount];
935 private ObjectStreamField getField (String name)
937 ObjectStreamField field
938 = currentObjectStreamClass.getField(name);
940 if (field == null)
941 throw new IllegalArgumentException("no such serializable field " + name);
943 return field;
946 public void put(String name, boolean value)
948 ObjectStreamField field = getField(name);
950 checkType(field, 'Z');
951 prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
954 public void put(String name, byte value)
956 ObjectStreamField field = getField(name);
958 checkType(field, 'B');
959 prim_field_data[field.getOffset()] = value;
962 public void put(String name, char value)
964 ObjectStreamField field = getField(name);
966 checkType(field, 'C');
967 int off = field.getOffset();
968 prim_field_data[off++] = (byte)(value >>> 8);
969 prim_field_data[off] = (byte)value;
972 public void put(String name, double value)
974 ObjectStreamField field = getField (name);
976 checkType(field, 'D');
977 int off = field.getOffset();
978 long l_value = Double.doubleToLongBits (value);
979 prim_field_data[off++] = (byte)(l_value >>> 52);
980 prim_field_data[off++] = (byte)(l_value >>> 48);
981 prim_field_data[off++] = (byte)(l_value >>> 40);
982 prim_field_data[off++] = (byte)(l_value >>> 32);
983 prim_field_data[off++] = (byte)(l_value >>> 24);
984 prim_field_data[off++] = (byte)(l_value >>> 16);
985 prim_field_data[off++] = (byte)(l_value >>> 8);
986 prim_field_data[off] = (byte)l_value;
989 public void put(String name, float value)
991 ObjectStreamField field = getField(name);
993 checkType(field, 'F');
994 int off = field.getOffset();
995 int i_value = Float.floatToIntBits(value);
996 prim_field_data[off++] = (byte)(i_value >>> 24);
997 prim_field_data[off++] = (byte)(i_value >>> 16);
998 prim_field_data[off++] = (byte)(i_value >>> 8);
999 prim_field_data[off] = (byte)i_value;
1002 public void put(String name, int value)
1004 ObjectStreamField field = getField(name);
1005 checkType(field, 'I');
1006 int off = field.getOffset();
1007 prim_field_data[off++] = (byte)(value >>> 24);
1008 prim_field_data[off++] = (byte)(value >>> 16);
1009 prim_field_data[off++] = (byte)(value >>> 8);
1010 prim_field_data[off] = (byte)value;
1013 public void put(String name, long value)
1015 ObjectStreamField field = getField(name);
1016 checkType(field, 'J');
1017 int off = field.getOffset();
1018 prim_field_data[off++] = (byte)(value >>> 52);
1019 prim_field_data[off++] = (byte)(value >>> 48);
1020 prim_field_data[off++] = (byte)(value >>> 40);
1021 prim_field_data[off++] = (byte)(value >>> 32);
1022 prim_field_data[off++] = (byte)(value >>> 24);
1023 prim_field_data[off++] = (byte)(value >>> 16);
1024 prim_field_data[off++] = (byte)(value >>> 8);
1025 prim_field_data[off] = (byte)value;
1028 public void put(String name, short value)
1030 ObjectStreamField field = getField(name);
1031 checkType(field, 'S');
1032 int off = field.getOffset();
1033 prim_field_data[off++] = (byte)(value >>> 8);
1034 prim_field_data[off] = (byte)value;
1037 public void put(String name, Object value)
1039 ObjectStreamField field = getField(name);
1041 if (value != null &&
1042 ! field.getType().isAssignableFrom(value.getClass ()))
1043 throw new IllegalArgumentException("Class " + value.getClass() +
1044 " cannot be cast to " + field.getType());
1045 objs[field.getOffset()] = value;
1048 public void write(ObjectOutput out) throws IOException
1050 // Apparently Block data is not used with PutField as per
1051 // empirical evidence against JDK 1.2. Also see Mauve test
1052 // java.io.ObjectInputOutput.Test.GetPutField.
1053 boolean oldmode = setBlockDataMode(false);
1054 out.write(prim_field_data);
1055 for (int i = 0; i < objs.length; ++ i)
1056 out.writeObject(objs[i]);
1057 setBlockDataMode(oldmode);
1060 private void checkType(ObjectStreamField field, char type)
1061 throws IllegalArgumentException
1063 if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0)
1064 != type)
1065 throw new IllegalArgumentException();
1068 // end PutFieldImpl
1070 return currentPutField;
1074 public void writeFields() throws IOException
1076 if (currentPutField == null)
1077 throw new NotActiveException("writeFields can only be called after putFields has been called");
1079 markFieldsWritten();
1080 currentPutField.write(this);
1084 // write out the block-data buffer, picking the correct header
1085 // depending on the size of the buffer
1086 private void writeBlockDataHeader(int size) throws IOException
1088 if (size < 256)
1090 realOutput.writeByte(TC_BLOCKDATA);
1091 realOutput.write(size);
1093 else
1095 realOutput.writeByte(TC_BLOCKDATALONG);
1096 realOutput.writeInt(size);
1101 // lookup the handle for OBJ, return null if OBJ doesn't have a
1102 // handle yet
1103 private Integer findHandle(Object obj)
1105 return (Integer)OIDLookupTable.get(new ObjectIdentityWrapper(obj));
1109 // assigns the next availible handle to OBJ
1110 private int assignNewHandle(Object obj)
1112 OIDLookupTable.put(new ObjectIdentityWrapper(obj),
1113 new Integer(nextOID));
1114 return nextOID++;
1118 // resets mapping from objects to handles
1119 private void clearHandles()
1121 nextOID = baseWireHandle;
1122 OIDLookupTable.clear();
1126 // write out array size followed by each element of the array
1127 private void writeArraySizeAndElements(Object array, Class clazz)
1128 throws IOException
1130 int length = Array.getLength(array);
1132 if (clazz.isPrimitive())
1134 if (clazz == Boolean.TYPE)
1136 boolean[] cast_array = (boolean[])array;
1137 realOutput.writeInt (length);
1138 for (int i = 0; i < length; i++)
1139 realOutput.writeBoolean(cast_array[i]);
1140 return;
1142 if (clazz == Byte.TYPE)
1144 byte[] cast_array = (byte[])array;
1145 realOutput.writeInt(length);
1146 realOutput.write(cast_array, 0, length);
1147 return;
1149 if (clazz == Character.TYPE)
1151 char[] cast_array = (char[])array;
1152 realOutput.writeInt(length);
1153 for (int i = 0; i < length; i++)
1154 realOutput.writeChar(cast_array[i]);
1155 return;
1157 if (clazz == Double.TYPE)
1159 double[] cast_array = (double[])array;
1160 realOutput.writeInt(length);
1161 for (int i = 0; i < length; i++)
1162 realOutput.writeDouble(cast_array[i]);
1163 return;
1165 if (clazz == Float.TYPE)
1167 float[] cast_array = (float[])array;
1168 realOutput.writeInt(length);
1169 for (int i = 0; i < length; i++)
1170 realOutput.writeFloat(cast_array[i]);
1171 return;
1173 if (clazz == Integer.TYPE)
1175 int[] cast_array = (int[])array;
1176 realOutput.writeInt(length);
1177 for (int i = 0; i < length; i++)
1178 realOutput.writeInt(cast_array[i]);
1179 return;
1181 if (clazz == Long.TYPE)
1183 long[] cast_array = (long[])array;
1184 realOutput.writeInt (length);
1185 for (int i = 0; i < length; i++)
1186 realOutput.writeLong(cast_array[i]);
1187 return;
1189 if (clazz == Short.TYPE)
1191 short[] cast_array = (short[])array;
1192 realOutput.writeInt (length);
1193 for (int i = 0; i < length; i++)
1194 realOutput.writeShort(cast_array[i]);
1195 return;
1198 else
1200 Object[] cast_array = (Object[])array;
1201 realOutput.writeInt(length);
1202 for (int i = 0; i < length; i++)
1203 writeObject(cast_array[i]);
1208 // writes out FIELDS of OBJECT for the specified ObjectStreamClass.
1209 // FIELDS are already in canonical order.
1210 private void writeFields(Object obj, ObjectStreamClass osc)
1211 throws IOException
1213 ObjectStreamField[] fields = osc.fields;
1214 boolean oldmode = setBlockDataMode(false);
1215 String field_name;
1216 Class type;
1218 for (int i = 0; i < fields.length; i++)
1220 field_name = fields[i].getName();
1221 type = fields[i].getType();
1223 if (dump)
1224 dumpElementln ("WRITE FIELD: " + field_name + " type=" + type);
1226 if (type == Boolean.TYPE)
1227 realOutput.writeBoolean(getBooleanField(obj, osc.forClass(), field_name));
1228 else if (type == Byte.TYPE)
1229 realOutput.writeByte(getByteField(obj, osc.forClass(), field_name));
1230 else if (type == Character.TYPE)
1231 realOutput.writeChar(getCharField(obj, osc.forClass(), field_name));
1232 else if (type == Double.TYPE)
1233 realOutput.writeDouble(getDoubleField(obj, osc.forClass(), field_name));
1234 else if (type == Float.TYPE)
1235 realOutput.writeFloat(getFloatField(obj, osc.forClass(), field_name));
1236 else if (type == Integer.TYPE)
1237 realOutput.writeInt(getIntField(obj, osc.forClass(), field_name));
1238 else if (type == Long.TYPE)
1239 realOutput.writeLong(getLongField(obj, osc.forClass(), field_name));
1240 else if (type == Short.TYPE)
1241 realOutput.writeShort(getShortField(obj, osc.forClass(), field_name));
1242 else
1243 writeObject(getObjectField(obj, osc.forClass(), field_name,
1244 fields[i].getTypeString ()));
1246 setBlockDataMode(oldmode);
1250 // Toggles writing primitive data to block-data buffer.
1251 // Package-private to avoid a trampoline constructor.
1252 boolean setBlockDataMode(boolean on) throws IOException
1254 if (on == writeDataAsBlocks)
1255 return on;
1257 drain();
1258 boolean oldmode = writeDataAsBlocks;
1259 writeDataAsBlocks = on;
1261 if (on)
1262 dataOutput = blockDataOutput;
1263 else
1264 dataOutput = realOutput;
1266 return oldmode;
1270 private void callWriteMethod(Object obj, ObjectStreamClass osc)
1271 throws IOException
1273 currentPutField = null;
1276 Object args[] = {this};
1277 osc.writeObjectMethod.invoke(obj, args);
1279 catch (InvocationTargetException x)
1281 /* Rethrow if possible. */
1282 Throwable exception = x.getTargetException();
1283 if (exception instanceof RuntimeException)
1284 throw (RuntimeException) exception;
1285 if (exception instanceof IOException)
1286 throw (IOException) exception;
1288 IOException ioe
1289 = new IOException("Exception thrown from writeObject() on " +
1290 osc.forClass().getName() + ": " +
1291 exception.getClass().getName());
1292 ioe.initCause(exception);
1293 throw ioe;
1295 catch (Exception x)
1297 IOException ioe
1298 = new IOException("Failure invoking writeObject() on " +
1299 osc.forClass().getName() + ": " +
1300 x.getClass().getName());
1301 ioe.initCause(x);
1302 throw ioe;
1306 private boolean getBooleanField(Object obj, Class klass, String field_name)
1307 throws IOException
1311 Field f = getField(klass, field_name);
1312 boolean b = f.getBoolean(obj);
1313 return b;
1315 catch (IllegalArgumentException _)
1317 throw new InvalidClassException
1318 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1320 catch (IOException e)
1322 throw e;
1324 catch (Exception _)
1326 throw new IOException("Unexpected exception " + _);
1330 private byte getByteField (Object obj, Class klass, String field_name)
1331 throws IOException
1335 Field f = getField (klass, field_name);
1336 byte b = f.getByte (obj);
1337 return b;
1339 catch (IllegalArgumentException _)
1341 throw new InvalidClassException
1342 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1344 catch (IOException e)
1346 throw e;
1348 catch (Exception _)
1350 throw new IOException("Unexpected exception " + _);
1354 private char getCharField (Object obj, Class klass, String field_name)
1355 throws IOException
1359 Field f = getField (klass, field_name);
1360 char b = f.getChar (obj);
1361 return b;
1363 catch (IllegalArgumentException _)
1365 throw new InvalidClassException
1366 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1368 catch (IOException e)
1370 throw e;
1372 catch (Exception _)
1374 throw new IOException("Unexpected exception " + _);
1378 private double getDoubleField (Object obj, Class klass, String field_name)
1379 throws IOException
1383 Field f = getField (klass, field_name);
1384 double b = f.getDouble (obj);
1385 return b;
1387 catch (IllegalArgumentException _)
1389 throw new InvalidClassException
1390 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1392 catch (IOException e)
1394 throw e;
1396 catch (Exception _)
1398 throw new IOException("Unexpected exception " + _);
1402 private float getFloatField (Object obj, Class klass, String field_name)
1403 throws IOException
1407 Field f = getField (klass, field_name);
1408 float b = f.getFloat (obj);
1409 return b;
1411 catch (IllegalArgumentException _)
1413 throw new InvalidClassException
1414 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1416 catch (IOException e)
1418 throw e;
1420 catch (Exception _)
1422 throw new IOException("Unexpected exception " + _);
1426 private int getIntField (Object obj, Class klass, String field_name)
1427 throws IOException
1431 Field f = getField (klass, field_name);
1432 int b = f.getInt (obj);
1433 return b;
1435 catch (IllegalArgumentException _)
1437 throw new InvalidClassException
1438 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1440 catch (IOException e)
1442 throw e;
1444 catch (Exception _)
1446 throw new IOException("Unexpected exception " + _);
1450 private long getLongField (Object obj, Class klass, String field_name)
1451 throws IOException
1455 Field f = getField (klass, field_name);
1456 long b = f.getLong (obj);
1457 return b;
1459 catch (IllegalArgumentException _)
1461 throw new InvalidClassException
1462 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1464 catch (IOException e)
1466 throw e;
1468 catch (Exception _)
1470 throw new IOException("Unexpected exception " + _);
1474 private short getShortField (Object obj, Class klass, String field_name)
1475 throws IOException
1479 Field f = getField (klass, field_name);
1480 short b = f.getShort (obj);
1481 return b;
1483 catch (IllegalArgumentException _)
1485 throw new InvalidClassException
1486 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1488 catch (IOException e)
1490 throw e;
1492 catch (Exception _)
1494 throw new IOException("Unexpected exception " + _);
1498 private Object getObjectField (Object obj, Class klass, String field_name,
1499 String type_code) throws IOException
1503 Field f = getField (klass, field_name);
1504 ObjectStreamField of = new ObjectStreamField(f.getName(), f.getType());
1506 /* if of is primitive something went wrong
1507 * in the check for primitive classes in writeFields.
1509 if (of.isPrimitive())
1510 throw new InvalidClassException
1511 ("invalid type code for " + field_name + " in class " + klass.getName() + " : object stream field is primitive");
1513 if (!of.getTypeString().equals(type_code))
1514 throw new InvalidClassException
1515 ("invalid type code for " + field_name + " in class " + klass.getName() + " : object stream field " + of + " has type string " + of.getTypeString() + " instead of " + type_code);
1517 Object o = f.get (obj);
1518 // FIXME: We should check the type_code here
1519 return o;
1521 catch (IOException e)
1523 throw e;
1525 catch (Exception e)
1527 throw new IOException ();
1531 private Field getField (Class klass, String name)
1532 throws java.io.InvalidClassException
1536 final Field f = klass.getDeclaredField(name);
1537 setAccessible.setMember(f);
1538 AccessController.doPrivileged(setAccessible);
1539 return f;
1541 catch (java.lang.NoSuchFieldException e)
1543 throw new InvalidClassException
1544 ("no field called " + name + " in class " + klass.getName());
1548 private void dumpElementln (String msg)
1550 for (int i = 0; i < depth; i++)
1551 System.out.print (" ");
1552 System.out.print (Thread.currentThread() + ": ");
1553 System.out.println(msg);
1556 // this value comes from 1.2 spec, but is used in 1.1 as well
1557 private static final int BUFFER_SIZE = 1024;
1559 private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
1561 private DataOutputStream dataOutput;
1562 private boolean writeDataAsBlocks;
1563 private DataOutputStream realOutput;
1564 private DataOutputStream blockDataOutput;
1565 private byte[] blockData;
1566 private int blockDataCount;
1567 private Object currentObject;
1568 // Package-private to avoid a trampoline.
1569 ObjectStreamClass currentObjectStreamClass;
1570 private PutField currentPutField;
1571 private boolean fieldsAlreadyWritten;
1572 private boolean replacementEnabled;
1573 private boolean isSerializing;
1574 private int nextOID;
1575 private Hashtable OIDLookupTable;
1576 private int protocolVersion;
1577 private boolean useSubclassMethod;
1578 private SetAccessibleAction setAccessible = new SetAccessibleAction();
1580 // The nesting depth for debugging output
1581 private int depth = 0;
1583 // Set if we're generating debugging dumps
1584 private boolean dump = false;
1586 private static final boolean DEBUG = false;