fixes for host gcc 4.6.1
[zpugcc/jano.git] / toolchain / gcc / libjava / java / io / ObjectOutputStream.java
blobb60f3b6a100d7b40796c9fc5023e946be06179e9
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.security.PrivilegedAction;
46 import java.security.AccessController;
47 import java.util.Hashtable;
49 import gnu.java.io.ObjectIdentityWrapper;
50 import gnu.java.lang.reflect.TypeSignature;
51 import gnu.classpath.Configuration;
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();
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 InvalidClassException Somebody tried to serialize
166 * an object which is wrongly formatted.
168 * @exception IOException Exception from underlying
169 * <code>OutputStream</code>.
171 public final void writeObject(Object obj) throws IOException
173 if (useSubclassMethod)
175 writeObjectOverride(obj);
176 return;
179 boolean was_serializing = isSerializing;
180 boolean old_mode = setBlockDataMode(false);
183 isSerializing = true;
184 boolean replaceDone = false;
185 Object replacedObject = null;
187 while (true)
189 if (obj == null)
191 realOutput.writeByte(TC_NULL);
192 break;
195 Integer handle = findHandle(obj);
196 if (handle != null)
198 realOutput.writeByte(TC_REFERENCE);
199 realOutput.writeInt(handle.intValue());
200 break;
203 if (obj instanceof Class)
205 Class cl = (Class)obj;
206 ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
207 assignNewHandle(obj);
208 realOutput.writeByte(TC_CLASS);
209 if (!osc.isProxyClass)
211 writeObject (osc);
213 else
215 realOutput.writeByte(TC_PROXYCLASSDESC);
216 Class[] intfs = cl.getInterfaces();
217 realOutput.writeInt(intfs.length);
218 for (int i = 0; i < intfs.length; i++)
219 realOutput.writeUTF(intfs[i].getName());
221 boolean oldmode = setBlockDataMode(true);
222 annotateProxyClass(cl);
223 setBlockDataMode(oldmode);
224 realOutput.writeByte(TC_ENDBLOCKDATA);
226 writeObject(osc.getSuper());
228 break;
231 if (obj instanceof ObjectStreamClass)
233 writeClassDescriptor((ObjectStreamClass) obj);
234 break;
237 if ((replacementEnabled || obj instanceof Serializable)
238 && ! replaceDone)
240 replacedObject = obj;
242 if (obj instanceof Serializable)
244 Method m = null;
247 Class classArgs[] = {};
248 m = getMethod(obj.getClass(), "writeReplace",
249 classArgs);
250 // m can't be null by definition since an
251 // exception would have been thrown so a check
252 // for null is not needed.
253 obj = m.invoke(obj, new Object[] {});
255 catch (NoSuchMethodException ignore)
258 catch (IllegalAccessException ignore)
261 catch (InvocationTargetException ignore)
266 if (replacementEnabled)
267 obj = replaceObject(obj);
269 replaceDone = true;
270 continue;
273 if (obj instanceof String)
275 realOutput.writeByte(TC_STRING);
276 assignNewHandle(obj);
277 realOutput.writeUTF((String)obj);
278 break;
281 Class clazz = obj.getClass();
282 ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
283 if (osc == null)
284 throw new NotSerializableException(clazz.getName());
286 if (clazz.isArray ())
288 realOutput.writeByte(TC_ARRAY);
289 writeObject(osc);
290 assignNewHandle(obj);
291 writeArraySizeAndElements(obj, clazz.getComponentType());
292 break;
295 realOutput.writeByte(TC_OBJECT);
296 writeObject(osc);
298 if (replaceDone)
299 assignNewHandle(replacedObject);
300 else
301 assignNewHandle(obj);
303 if (obj instanceof Externalizable)
305 if (protocolVersion == PROTOCOL_VERSION_2)
306 setBlockDataMode(true);
308 ((Externalizable)obj).writeExternal(this);
310 if (protocolVersion == PROTOCOL_VERSION_2)
312 setBlockDataMode(false);
313 realOutput.writeByte(TC_ENDBLOCKDATA);
316 break;
319 if (obj instanceof Serializable)
321 currentObject = obj;
322 ObjectStreamClass[] hierarchy =
323 ObjectStreamClass.getObjectStreamClasses(clazz);
325 for (int i = 0; i < hierarchy.length; i++)
327 currentObjectStreamClass = hierarchy[i];
329 fieldsAlreadyWritten = false;
330 if (currentObjectStreamClass.hasWriteMethod())
332 setBlockDataMode(true);
333 callWriteMethod(obj, currentObjectStreamClass);
334 setBlockDataMode(false);
335 realOutput.writeByte(TC_ENDBLOCKDATA);
337 else
338 writeFields(obj, currentObjectStreamClass);
341 currentObject = null;
342 currentObjectStreamClass = null;
343 currentPutField = null;
344 break;
347 throw new NotSerializableException(clazz.getName ());
348 } // end pseudo-loop
350 catch (ObjectStreamException ose)
352 // Rethrow these are fatal.
353 throw ose;
355 catch (IOException e)
357 realOutput.writeByte(TC_EXCEPTION);
358 reset(true);
360 setBlockDataMode(false);
363 writeObject(e);
365 catch (IOException ioe)
367 throw new StreamCorruptedException
368 ("Exception " + ioe + " thrown while exception was being written to stream.");
371 reset (true);
374 finally
376 isSerializing = was_serializing;
377 setBlockDataMode(old_mode);
381 protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException
383 realOutput.writeByte(TC_CLASSDESC);
384 realOutput.writeUTF(osc.getName());
385 realOutput.writeLong(osc.getSerialVersionUID());
386 assignNewHandle(osc);
388 int flags = osc.getFlags();
390 if (protocolVersion == PROTOCOL_VERSION_2
391 && osc.isExternalizable())
392 flags |= SC_BLOCK_DATA;
394 realOutput.writeByte(flags);
396 ObjectStreamField[] fields = osc.fields;
397 realOutput.writeShort(fields.length);
399 ObjectStreamField field;
400 for (int i = 0; i < fields.length; i++)
402 field = fields[i];
403 realOutput.writeByte(field.getTypeCode ());
404 realOutput.writeUTF(field.getName ());
406 if (! field.isPrimitive())
407 writeObject(field.getTypeString());
410 boolean oldmode = setBlockDataMode(true);
411 annotateClass(osc.forClass());
412 setBlockDataMode(oldmode);
413 realOutput.writeByte(TC_ENDBLOCKDATA);
415 if (osc.isSerializable() || osc.isExternalizable())
416 writeObject(osc.getSuper());
417 else
418 writeObject(null);
422 * Writes the current objects non-transient, non-static fields from
423 * the current class to the underlying output stream.
425 * This method is intended to be called from within a object's
426 * <code>private void writeObject (ObjectOutputStream)</code>
427 * method.
429 * @exception NotActiveException This method was called from a
430 * context other than from the current object's and current class's
431 * <code>private void writeObject (ObjectOutputStream)</code>
432 * method.
434 * @exception IOException Exception from underlying
435 * <code>OutputStream</code>.
437 public void defaultWriteObject()
438 throws IOException, NotActiveException
440 markFieldsWritten();
441 writeFields(currentObject, currentObjectStreamClass);
445 private void markFieldsWritten() throws IOException
447 if (currentObject == null || currentObjectStreamClass == null)
448 throw new NotActiveException
449 ("defaultWriteObject called by non-active class and/or object");
451 if (fieldsAlreadyWritten)
452 throw new IOException
453 ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once");
455 fieldsAlreadyWritten = true;
459 * Resets stream to state equivalent to the state just after it was
460 * constructed.
462 * Causes all objects previously written to the stream to be
463 * forgotten. A notification of this reset is also written to the
464 * underlying stream.
466 * @exception IOException Exception from underlying
467 * <code>OutputStream</code> or reset called while serialization is
468 * in progress.
470 public void reset() throws IOException
472 reset(false);
476 private void reset(boolean internal) throws IOException
478 if (!internal)
480 if (isSerializing)
481 throw new IOException("Reset called while serialization in progress");
483 realOutput.writeByte(TC_RESET);
486 clearHandles();
491 * Informs this <code>ObjectOutputStream</code> to write data
492 * according to the specified protocol. There are currently two
493 * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
494 * and <code>PROTOCOL_VERSION_2</code>. This implementation writes
495 * data using <code>PROTOCOL_VERSION_2</code> by default, as is done
496 * by the JDK 1.2.
498 * A non-portable method, <code>setDefaultProtocolVersion (int
499 * version)</code> is provided to change the default protocol
500 * version.
502 * For an explination of the differences beween the two protocols
503 * see XXX: the Java ObjectSerialization Specification.
505 * @exception IOException if <code>version</code> is not a valid
506 * protocol
508 * @see #setDefaultProtocolVersion(int)
510 public void useProtocolVersion(int version) throws IOException
512 if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
513 throw new IOException("Invalid protocol version requested.");
515 protocolVersion = version;
520 * <em>GNU $classpath specific</em>
522 * Changes the default stream protocol used by all
523 * <code>ObjectOutputStream</code>s. There are currently two
524 * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
525 * and <code>PROTOCOL_VERSION_2</code>. The default default is
526 * <code>PROTOCOL_VERSION_1</code>.
528 * @exception IOException if <code>version</code> is not a valid
529 * protocol
531 * @see #useProtocolVersion(int)
533 public static void setDefaultProtocolVersion(int version)
534 throws IOException
536 if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
537 throw new IOException("Invalid protocol version requested.");
539 defaultProtocolVersion = version;
544 * An empty hook that allows subclasses to write extra information
545 * about classes to the stream. This method is called the first
546 * time each class is seen, and after all of the standard
547 * information about the class has been written.
549 * @exception IOException Exception from underlying
550 * <code>OutputStream</code>.
552 * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
554 protected void annotateClass(Class cl) throws IOException
558 protected void annotateProxyClass(Class cl) throws IOException
563 * Allows subclasses to replace objects that are written to the
564 * stream with other objects to be written in their place. This
565 * method is called the first time each object is encountered
566 * (modulo reseting of the stream).
568 * This method must be enabled before it will be called in the
569 * serialization process.
571 * @exception IOException Exception from underlying
572 * <code>OutputStream</code>.
574 * @see #enableReplaceObject(boolean)
576 protected Object replaceObject(Object obj) throws IOException
578 return obj;
583 * If <code>enable</code> is <code>true</code> and this object is
584 * trusted, then <code>replaceObject (Object)</code> will be called
585 * in subsequent calls to <code>writeObject (Object)</code>.
586 * Otherwise, <code>replaceObject (Object)</code> will not be called.
588 * @exception SecurityException This class is not trusted.
590 protected boolean enableReplaceObject(boolean enable)
591 throws SecurityException
593 if (enable)
595 SecurityManager sm = System.getSecurityManager();
596 if (sm != null)
597 sm.checkPermission(new SerializablePermission("enableSubstitution"));
600 boolean old_val = replacementEnabled;
601 replacementEnabled = enable;
602 return old_val;
607 * Writes stream magic and stream version information to the
608 * underlying stream.
610 * @exception IOException Exception from underlying
611 * <code>OutputStream</code>.
613 protected void writeStreamHeader() throws IOException
615 realOutput.writeShort(STREAM_MAGIC);
616 realOutput.writeShort(STREAM_VERSION);
620 * Protected constructor that allows subclasses to override
621 * serialization. This constructor should be called by subclasses
622 * that wish to override <code>writeObject (Object)</code>. This
623 * method does a security check <i>NOTE: currently not
624 * implemented</i>, then sets a flag that informs
625 * <code>writeObject (Object)</code> to call the subclasses
626 * <code>writeObjectOverride (Object)</code> method.
628 * @see #writeObjectOverride(Object)
630 protected ObjectOutputStream() throws IOException, SecurityException
632 SecurityManager sec_man = System.getSecurityManager ();
633 if (sec_man != null)
634 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
635 useSubclassMethod = true;
640 * This method allows subclasses to override the default
641 * serialization mechanism provided by
642 * <code>ObjectOutputStream</code>. To make this method be used for
643 * writing objects, subclasses must invoke the 0-argument
644 * constructor on this class from there constructor.
646 * @see #ObjectOutputStream()
648 * @exception NotActiveException Subclass has arranged for this
649 * method to be called, but did not implement this method.
651 protected void writeObjectOverride(Object obj) throws NotActiveException,
652 IOException
654 throw new NotActiveException
655 ("Subclass of ObjectOutputStream must implement writeObjectOverride");
660 * @see DataOutputStream#write(int)
662 public void write (int data) throws IOException
664 if (writeDataAsBlocks)
666 if (blockDataCount == BUFFER_SIZE)
667 drain();
669 blockData[ blockDataCount++ ] = (byte)data;
671 else
672 realOutput.write(data);
677 * @see DataOutputStream#write(byte[])
679 public void write(byte[] b) throws IOException
681 write(b, 0, b.length);
686 * @see DataOutputStream#write(byte[],int,int)
688 public void write(byte[] b, int off, int len) throws IOException
690 if (writeDataAsBlocks)
692 if (len < 0)
693 throw new IndexOutOfBoundsException();
695 if (blockDataCount + len < BUFFER_SIZE)
697 System.arraycopy(b, off, blockData, blockDataCount, len);
698 blockDataCount += len;
700 else
702 drain();
703 writeBlockDataHeader(len);
704 realOutput.write(b, off, len);
707 else
708 realOutput.write(b, off, len);
713 * @see DataOutputStream#flush()
715 public void flush () throws IOException
717 drain();
718 realOutput.flush();
723 * Causes the block-data buffer to be written to the underlying
724 * stream, but does not flush underlying stream.
726 * @exception IOException Exception from underlying
727 * <code>OutputStream</code>.
729 protected void drain() throws IOException
731 if (blockDataCount == 0)
732 return;
734 if (writeDataAsBlocks)
735 writeBlockDataHeader(blockDataCount);
736 realOutput.write(blockData, 0, blockDataCount);
737 blockDataCount = 0;
742 * @see java.io.DataOutputStream#close ()
744 public void close() throws IOException
746 flush();
747 realOutput.close();
752 * @see java.io.DataOutputStream#writeBoolean (boolean)
754 public void writeBoolean(boolean data) throws IOException
756 blockDataOutput.writeBoolean(data);
761 * @see java.io.DataOutputStream#writeByte (int)
763 public void writeByte(int data) throws IOException
765 blockDataOutput.writeByte(data);
770 * @see java.io.DataOutputStream#writeShort (int)
772 public void writeShort (int data) throws IOException
774 blockDataOutput.writeShort(data);
779 * @see java.io.DataOutputStream#writeChar (int)
781 public void writeChar(int data) throws IOException
783 blockDataOutput.writeChar(data);
788 * @see java.io.DataOutputStream#writeInt (int)
790 public void writeInt(int data) throws IOException
792 blockDataOutput.writeInt(data);
797 * @see java.io.DataOutputStream#writeLong (long)
799 public void writeLong(long data) throws IOException
801 blockDataOutput.writeLong(data);
806 * @see java.io.DataOutputStream#writeFloat (float)
808 public void writeFloat(float data) throws IOException
810 blockDataOutput.writeFloat(data);
815 * @see java.io.DataOutputStream#writeDouble (double)
817 public void writeDouble(double data) throws IOException
819 blockDataOutput.writeDouble(data);
824 * @see java.io.DataOutputStream#writeBytes (java.lang.String)
826 public void writeBytes(String data) throws IOException
828 blockDataOutput.writeBytes(data);
833 * @see java.io.DataOutputStream#writeChars (java.lang.String)
835 public void writeChars(String data) throws IOException
837 dataOutput.writeChars(data);
842 * @see java.io.DataOutputStream#writeUTF (java.lang.String)
844 public void writeUTF(String data) throws IOException
846 dataOutput.writeUTF(data);
851 * This class allows a class to specify exactly which fields should
852 * be written, and what values should be written for these fields.
854 * XXX: finish up comments
856 public static abstract class PutField
858 public abstract void put (String name, boolean value);
859 public abstract void put (String name, byte value);
860 public abstract void put (String name, char value);
861 public abstract void put (String name, double value);
862 public abstract void put (String name, float value);
863 public abstract void put (String name, int value);
864 public abstract void put (String name, long value);
865 public abstract void put (String name, short value);
866 public abstract void put (String name, Object value);
869 * @deprecated
871 public abstract void write (ObjectOutput out) throws IOException;
874 public PutField putFields() throws IOException
876 if (currentPutField != null)
877 return currentPutField;
879 currentPutField = new PutField()
881 private byte[] prim_field_data
882 = new byte[currentObjectStreamClass.primFieldSize];
883 private Object[] objs
884 = new Object[currentObjectStreamClass.objectFieldCount];
886 private ObjectStreamField getField (String name)
888 ObjectStreamField field
889 = currentObjectStreamClass.getField(name);
891 if (field == null)
892 throw new IllegalArgumentException("no such serializable field " + name);
894 return field;
897 public void put(String name, boolean value)
899 ObjectStreamField field = getField(name);
901 checkType(field, 'Z');
902 prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
905 public void put(String name, byte value)
907 ObjectStreamField field = getField(name);
909 checkType(field, 'B');
910 prim_field_data[field.getOffset()] = value;
913 public void put(String name, char value)
915 ObjectStreamField field = getField(name);
917 checkType(field, 'C');
918 int off = field.getOffset();
919 prim_field_data[off++] = (byte)(value >>> 8);
920 prim_field_data[off] = (byte)value;
923 public void put(String name, double value)
925 ObjectStreamField field = getField (name);
927 checkType(field, 'D');
928 int off = field.getOffset();
929 long l_value = Double.doubleToLongBits (value);
930 prim_field_data[off++] = (byte)(l_value >>> 52);
931 prim_field_data[off++] = (byte)(l_value >>> 48);
932 prim_field_data[off++] = (byte)(l_value >>> 40);
933 prim_field_data[off++] = (byte)(l_value >>> 32);
934 prim_field_data[off++] = (byte)(l_value >>> 24);
935 prim_field_data[off++] = (byte)(l_value >>> 16);
936 prim_field_data[off++] = (byte)(l_value >>> 8);
937 prim_field_data[off] = (byte)l_value;
940 public void put(String name, float value)
942 ObjectStreamField field = getField(name);
944 checkType(field, 'F');
945 int off = field.getOffset();
946 int i_value = Float.floatToIntBits(value);
947 prim_field_data[off++] = (byte)(i_value >>> 24);
948 prim_field_data[off++] = (byte)(i_value >>> 16);
949 prim_field_data[off++] = (byte)(i_value >>> 8);
950 prim_field_data[off] = (byte)i_value;
953 public void put(String name, int value)
955 ObjectStreamField field = getField(name);
956 checkType(field, 'I');
957 int off = field.getOffset();
958 prim_field_data[off++] = (byte)(value >>> 24);
959 prim_field_data[off++] = (byte)(value >>> 16);
960 prim_field_data[off++] = (byte)(value >>> 8);
961 prim_field_data[off] = (byte)value;
964 public void put(String name, long value)
966 ObjectStreamField field = getField(name);
967 checkType(field, 'J');
968 int off = field.getOffset();
969 prim_field_data[off++] = (byte)(value >>> 52);
970 prim_field_data[off++] = (byte)(value >>> 48);
971 prim_field_data[off++] = (byte)(value >>> 40);
972 prim_field_data[off++] = (byte)(value >>> 32);
973 prim_field_data[off++] = (byte)(value >>> 24);
974 prim_field_data[off++] = (byte)(value >>> 16);
975 prim_field_data[off++] = (byte)(value >>> 8);
976 prim_field_data[off] = (byte)value;
979 public void put(String name, short value)
981 ObjectStreamField field = getField(name);
982 checkType(field, 'S');
983 int off = field.getOffset();
984 prim_field_data[off++] = (byte)(value >>> 8);
985 prim_field_data[off] = (byte)value;
988 public void put(String name, Object value)
990 ObjectStreamField field = getField(name);
992 if (value != null &&
993 ! field.getType().isAssignableFrom(value.getClass ()))
994 throw new IllegalArgumentException("Class " + value.getClass() +
995 " cannot be cast to " + field.getType());
996 objs[field.getOffset()] = value;
999 public void write(ObjectOutput out) throws IOException
1001 // Apparently Block data is not used with PutField as per
1002 // empirical evidence against JDK 1.2. Also see Mauve test
1003 // java.io.ObjectInputOutput.Test.GetPutField.
1004 boolean oldmode = setBlockDataMode(false);
1005 out.write(prim_field_data);
1006 for (int i = 0; i < objs.length; ++ i)
1007 out.writeObject(objs[i]);
1008 setBlockDataMode(oldmode);
1011 private void checkType(ObjectStreamField field, char type)
1012 throws IllegalArgumentException
1014 if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0)
1015 != type)
1016 throw new IllegalArgumentException();
1019 // end PutFieldImpl
1021 return currentPutField;
1025 public void writeFields() throws IOException
1027 if (currentPutField == null)
1028 throw new NotActiveException("writeFields can only be called after putFields has been called");
1030 markFieldsWritten();
1031 currentPutField.write(this);
1035 // write out the block-data buffer, picking the correct header
1036 // depending on the size of the buffer
1037 private void writeBlockDataHeader(int size) throws IOException
1039 if (size < 256)
1041 realOutput.writeByte(TC_BLOCKDATA);
1042 realOutput.write(size);
1044 else
1046 realOutput.writeByte(TC_BLOCKDATALONG);
1047 realOutput.writeInt(size);
1052 // lookup the handle for OBJ, return null if OBJ doesn't have a
1053 // handle yet
1054 private Integer findHandle(Object obj)
1056 return (Integer)OIDLookupTable.get(new ObjectIdentityWrapper(obj));
1060 // assigns the next availible handle to OBJ
1061 private int assignNewHandle(Object obj)
1063 OIDLookupTable.put(new ObjectIdentityWrapper(obj),
1064 new Integer(nextOID));
1065 return nextOID++;
1069 // resets mapping from objects to handles
1070 private void clearHandles()
1072 nextOID = baseWireHandle;
1073 OIDLookupTable.clear();
1077 // write out array size followed by each element of the array
1078 private void writeArraySizeAndElements(Object array, Class clazz)
1079 throws IOException
1081 int length = Array.getLength(array);
1083 if (clazz.isPrimitive())
1085 if (clazz == Boolean.TYPE)
1087 boolean[] cast_array = (boolean[])array;
1088 realOutput.writeInt (length);
1089 for (int i = 0; i < length; i++)
1090 realOutput.writeBoolean(cast_array[i]);
1091 return;
1093 if (clazz == Byte.TYPE)
1095 byte[] cast_array = (byte[])array;
1096 realOutput.writeInt(length);
1097 realOutput.write(cast_array, 0, length);
1098 return;
1100 if (clazz == Character.TYPE)
1102 char[] cast_array = (char[])array;
1103 realOutput.writeInt(length);
1104 for (int i = 0; i < length; i++)
1105 realOutput.writeChar(cast_array[i]);
1106 return;
1108 if (clazz == Double.TYPE)
1110 double[] cast_array = (double[])array;
1111 realOutput.writeInt(length);
1112 for (int i = 0; i < length; i++)
1113 realOutput.writeDouble(cast_array[i]);
1114 return;
1116 if (clazz == Float.TYPE)
1118 float[] cast_array = (float[])array;
1119 realOutput.writeInt(length);
1120 for (int i = 0; i < length; i++)
1121 realOutput.writeFloat(cast_array[i]);
1122 return;
1124 if (clazz == Integer.TYPE)
1126 int[] cast_array = (int[])array;
1127 realOutput.writeInt(length);
1128 for (int i = 0; i < length; i++)
1129 realOutput.writeInt(cast_array[i]);
1130 return;
1132 if (clazz == Long.TYPE)
1134 long[] cast_array = (long[])array;
1135 realOutput.writeInt (length);
1136 for (int i = 0; i < length; i++)
1137 realOutput.writeLong(cast_array[i]);
1138 return;
1140 if (clazz == Short.TYPE)
1142 short[] cast_array = (short[])array;
1143 realOutput.writeInt (length);
1144 for (int i = 0; i < length; i++)
1145 realOutput.writeShort(cast_array[i]);
1146 return;
1149 else
1151 Object[] cast_array = (Object[])array;
1152 realOutput.writeInt(length);
1153 for (int i = 0; i < length; i++)
1154 writeObject(cast_array[i]);
1159 // writes out FIELDS of OBJECT for the specified ObjectStreamClass.
1160 // FIELDS are already in canonical order.
1161 private void writeFields(Object obj, ObjectStreamClass osc)
1162 throws IOException
1164 ObjectStreamField[] fields = osc.fields;
1165 boolean oldmode = setBlockDataMode(false);
1166 String field_name;
1167 Class type;
1169 for (int i = 0; i < fields.length; i++)
1171 field_name = fields[i].getName();
1172 type = fields[i].getType();
1174 if (type == Boolean.TYPE)
1175 realOutput.writeBoolean(getBooleanField(obj, osc.forClass(), field_name));
1176 else if (type == Byte.TYPE)
1177 realOutput.writeByte(getByteField(obj, osc.forClass(), field_name));
1178 else if (type == Character.TYPE)
1179 realOutput.writeChar(getCharField(obj, osc.forClass(), field_name));
1180 else if (type == Double.TYPE)
1181 realOutput.writeDouble(getDoubleField(obj, osc.forClass(), field_name));
1182 else if (type == Float.TYPE)
1183 realOutput.writeFloat(getFloatField(obj, osc.forClass(), field_name));
1184 else if (type == Integer.TYPE)
1185 realOutput.writeInt(getIntField(obj, osc.forClass(), field_name));
1186 else if (type == Long.TYPE)
1187 realOutput.writeLong(getLongField(obj, osc.forClass(), field_name));
1188 else if (type == Short.TYPE)
1189 realOutput.writeShort(getShortField(obj, osc.forClass(), field_name));
1190 else
1191 writeObject(getObjectField(obj, osc.forClass(), field_name,
1192 fields[i].getTypeString ()));
1194 setBlockDataMode(oldmode);
1198 // Toggles writing primitive data to block-data buffer.
1199 private boolean setBlockDataMode(boolean on) throws IOException
1201 if (on == writeDataAsBlocks)
1202 return on;
1204 drain();
1205 boolean oldmode = writeDataAsBlocks;
1206 writeDataAsBlocks = on;
1208 if (on)
1209 dataOutput = blockDataOutput;
1210 else
1211 dataOutput = realOutput;
1213 return oldmode;
1217 private void callWriteMethod(Object obj, ObjectStreamClass osc)
1218 throws IOException
1220 Class klass = osc.forClass();
1221 currentPutField = null;
1224 Class classArgs[] = {ObjectOutputStream.class};
1225 Method m = getMethod(klass, "writeObject", classArgs);
1226 Object args[] = {this};
1227 m.invoke(obj, args);
1229 catch (NoSuchMethodException nsme)
1231 // Nothing.
1233 catch (InvocationTargetException x)
1235 /* Rethrow if possible. */
1236 Throwable exception = x.getTargetException();
1237 if (exception instanceof RuntimeException)
1238 throw (RuntimeException) exception;
1239 if (exception instanceof IOException)
1240 throw (IOException) exception;
1242 IOException ioe
1243 = new IOException("Exception thrown from writeObject() on " +
1244 klass + ": " + exception.getClass().getName());
1245 ioe.initCause(exception);
1246 throw ioe;
1248 catch (Exception x)
1250 IOException ioe
1251 = new IOException("Failure invoking writeObject() on " +
1252 klass + ": " + x.getClass().getName());
1253 ioe.initCause(x);
1254 throw ioe;
1258 private boolean getBooleanField(Object obj, Class klass, String field_name)
1259 throws IOException
1263 Field f = getField(klass, field_name);
1264 boolean b = f.getBoolean(obj);
1265 return b;
1267 catch (IllegalArgumentException _)
1269 throw new InvalidClassException
1270 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1272 catch (IOException e)
1274 throw e;
1276 catch (Exception _)
1278 throw new IOException("Unexpected exception " + _);
1282 private byte getByteField (Object obj, Class klass, String field_name)
1283 throws IOException
1287 Field f = getField (klass, field_name);
1288 byte b = f.getByte (obj);
1289 return b;
1291 catch (IllegalArgumentException _)
1293 throw new InvalidClassException
1294 ("invalid requested type for field " + field_name + " in class " + klass.getName());
1296 catch (IOException e)
1298 throw e;
1300 catch (Exception _)
1302 throw new IOException("Unexpected exception " + _);
1306 private char getCharField (Object obj, Class klass, String field_name)
1307 throws IOException
1311 Field f = getField (klass, field_name);
1312 char b = f.getChar (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 double getDoubleField (Object obj, Class klass, String field_name)
1331 throws IOException
1335 Field f = getField (klass, field_name);
1336 double b = f.getDouble (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 float getFloatField (Object obj, Class klass, String field_name)
1355 throws IOException
1359 Field f = getField (klass, field_name);
1360 float b = f.getFloat (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 int getIntField (Object obj, Class klass, String field_name)
1379 throws IOException
1383 Field f = getField (klass, field_name);
1384 int b = f.getInt (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 long getLongField (Object obj, Class klass, String field_name)
1403 throws IOException
1407 Field f = getField (klass, field_name);
1408 long b = f.getLong (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 short getShortField (Object obj, Class klass, String field_name)
1427 throws IOException
1431 Field f = getField (klass, field_name);
1432 short b = f.getShort (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 Object getObjectField (Object obj, Class klass, String field_name,
1451 String type_code) throws IOException
1455 Field f = getField (klass, field_name);
1456 ObjectStreamField of = new ObjectStreamField(f.getName(), f.getType());
1458 if (of.getTypeString() == null ||
1459 !of.getTypeString().equals(type_code))
1460 throw new InvalidClassException
1461 ("invalid type code for " + field_name + " in class " + klass.getName());
1463 Object o = f.get (obj);
1464 // FIXME: We should check the type_code here
1465 return o;
1467 catch (IOException e)
1469 throw e;
1471 catch (Exception e)
1473 throw new IOException ();
1477 private static Field getField (Class klass, String name)
1478 throws java.io.InvalidClassException
1482 final Field f = klass.getDeclaredField(name);
1483 AccessController.doPrivileged(new PrivilegedAction()
1485 public Object run()
1487 f.setAccessible(true);
1488 return null;
1491 return f;
1493 catch (java.lang.NoSuchFieldException e)
1495 throw new InvalidClassException
1496 ("no field called " + name + " in class " + klass.getName());
1500 private static Method getMethod (Class klass, String name, Class[] args)
1501 throws java.lang.NoSuchMethodException
1503 final Method m = klass.getDeclaredMethod(name, args);
1504 AccessController.doPrivileged(new PrivilegedAction()
1506 public Object run()
1508 m.setAccessible(true);
1509 return null;
1512 return m;
1515 // this value comes from 1.2 spec, but is used in 1.1 as well
1516 private final static int BUFFER_SIZE = 1024;
1518 private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
1520 private DataOutputStream dataOutput;
1521 private boolean writeDataAsBlocks;
1522 private DataOutputStream realOutput;
1523 private DataOutputStream blockDataOutput;
1524 private byte[] blockData;
1525 private int blockDataCount;
1526 private Object currentObject;
1527 private ObjectStreamClass currentObjectStreamClass;
1528 private PutField currentPutField;
1529 private boolean fieldsAlreadyWritten;
1530 private boolean replacementEnabled;
1531 private boolean isSerializing;
1532 private int nextOID;
1533 private Hashtable OIDLookupTable;
1534 private int protocolVersion;
1535 private boolean useSubclassMethod;
1537 static
1539 if (Configuration.INIT_LOAD_LIBRARY)
1541 System.loadLibrary("javaio");