1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999 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)
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
21 As a special exception, if you link this library with other files to
22 produce an executable, this library does not by itself cause the
23 resulting executable to be covered by the GNU General Public License.
24 This exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
30 import java.lang.reflect.Array;
31 import java.lang.reflect.Modifier;
32 import java.util.Arrays;
33 import java.util.Hashtable;
34 import java.util.Vector;
36 import gnu.java.io.ObjectIdentityWrapper;
37 import gnu.java.lang.reflect.TypeSignature;
38 import java.lang.reflect.Field;
39 import java.lang.reflect.Method;
43 public class ObjectInputStream extends InputStream
44 implements ObjectInput, ObjectStreamConstants
47 Creates a new <code>ObjectInputStream</code> that will do all of
48 its reading from <code>in</code>. This method also checks
49 the stream by reading the header information (stream magic number
52 @exception IOException Reading stream header from underlying
53 stream cannot be completed.
55 @exception StreamCorruptedException An invalid stream magic
56 number or stream version was read from the stream.
58 @see readStreamHeader ()
60 public ObjectInputStream (InputStream in)
61 throws IOException, StreamCorruptedException
63 this.resolveEnabled = false;
64 this.isDeserializing = false;
65 this.blockDataPosition = 0;
66 this.blockDataBytes = 0;
67 this.blockData = new byte[BUFFER_SIZE];
68 this.blockDataInput = new DataInputStream (this);
69 this.realInputStream = new DataInputStream (in);
70 this.nextOID = baseWireHandle;
71 this.objectLookupTable = new Hashtable ();
72 this.validators = new Vector ();
73 setBlockDataMode (true);
79 Returns the next deserialized object read from the underlying stream.
81 This method can be overriden by a class by implementing
82 <code>private void readObject (ObjectInputStream)</code>.
84 If an exception is thrown from this method, the stream is left in
87 @exception ClassNotFoundException The class that an object being
88 read in belongs to cannot be found.
90 @exception IOException Exception from underlying
91 <code>InputStream</code>.
93 public final Object readObject () throws ClassNotFoundException, IOException
95 if (this.useSubclassMethod)
96 return readObjectOverride ();
98 boolean was_deserializing;
101 was_deserializing = this.isDeserializing;
103 if (! was_deserializing)
104 setBlockDataMode (false);
106 this.isDeserializing = true;
108 // DEBUG ("MARKER ");
109 byte marker = this.realInputStream.readByte ();
114 case TC_BLOCKDATALONG:
115 readNextBlock (marker);
116 throw new BlockDataException (this.blockDataBytes);
124 // DEBUG ("REFERENCE ");
125 Integer oid = new Integer (this.realInputStream.readInt ());
126 ret_val = ((ObjectIdentityWrapper)
127 this.objectLookupTable.get (oid)).object;
133 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
134 Class clazz = osc.forClass ();
135 assignNewHandle (clazz);
142 // DEBUG ("CLASSDESC NAME ");
143 String name = this.realInputStream.readUTF ();
145 long uid = this.realInputStream.readLong ();
147 byte flags = this.realInputStream.readByte ();
148 // DEBUG ("FIELD COUNT ");
149 short field_count = this.realInputStream.readShort ();
150 ObjectStreamField[] fields = new ObjectStreamField[field_count];
152 ObjectStreamClass osc = new ObjectStreamClass (name, uid,
154 assignNewHandle (osc);
156 for (int i=0; i < field_count; i++)
158 // DEBUG ("TYPE CODE ");
159 char type_code = (char)this.realInputStream.readByte ();
160 // DEBUG ("FIELD NAME ");
161 String field_name = this.realInputStream.readUTF ();
164 if (type_code == 'L' || type_code == '[')
165 class_name = (String)readObject ();
167 class_name = String.valueOf (type_code);
170 new ObjectStreamField (field_name,
171 TypeSignature.getClassForEncoding
175 setBlockDataMode (true);
176 osc.setClass (resolveClass (osc));
177 setBlockDataMode (false);
179 // DEBUG ("ENDBLOCKDATA ");
180 if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
181 throw new IOException ("Data annotated to class was not consumed.");
183 osc.setSuperclass ((ObjectStreamClass)readObject ());
190 // DEBUG ("STRING ");
191 String s = this.realInputStream.readUTF ();
192 ret_val = processResoultion (s, assignNewHandle (s));
198 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
199 Class componenetType = osc.forClass ().getComponentType ();
200 // DEBUG ("ARRAY LENGTH ");
201 int length = this.realInputStream.readInt ();
202 Object array = Array.newInstance (componenetType, length);
203 int handle = assignNewHandle (array);
204 readArrayElements (array, componenetType);
205 ret_val = processResoultion (array, handle);
211 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
212 Class clazz = osc.forClass ();
214 if (!Serializable.class.isAssignableFrom (clazz))
215 throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
217 if (Externalizable.class.isAssignableFrom (clazz))
219 Externalizable obj = null;
223 obj = (Externalizable)clazz.newInstance ();
225 catch (InstantiationException e)
227 throw new ClassNotFoundException ("Instance of " + clazz
228 + " could not be created");
230 catch (IllegalAccessException e)
232 throw new ClassNotFoundException ("Instance of " + clazz
233 + " could not be created because class or zero-argument constructor is not accessible");
235 catch (NoSuchMethodError e)
237 throw new ClassNotFoundException ("Instance of " + clazz
238 + " could not be created because zero-argument constructor is not defined");
241 int handle = assignNewHandle (obj);
243 boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
245 if (read_from_blocks)
246 setBlockDataMode (true);
248 obj.readExternal (this);
250 if (read_from_blocks)
251 setBlockDataMode (false);
253 ret_val = processResoultion (obj, handle);
255 } // end if (Externalizable.class.isAssignableFrom (clazz))
257 // find the first non-serializable, non-abstract
258 // class in clazz's inheritance hierarchy
259 Class first_nonserial = clazz.getSuperclass ();
260 while (Serializable.class.isAssignableFrom (first_nonserial)
261 || Modifier.isAbstract (first_nonserial.getModifiers ()))
262 first_nonserial = first_nonserial.getSuperclass ();
264 // DEBUGln ("Using " + first_nonserial
265 // + " as starting point for constructing " + clazz);
268 obj = newObject (clazz, first_nonserial);
271 throw new ClassNotFoundException ("Instance of " + clazz +
272 " could not be created");
274 int handle = assignNewHandle (obj);
275 this.currentObject = obj;
276 ObjectStreamClass[] hierarchy =
277 ObjectStreamClass.getObjectStreamClasses (clazz);
279 // DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
282 for (int i=0; i < hierarchy.length; i++)
284 this.currentObjectStreamClass = hierarchy[i];
286 // DEBUGln ("Reading fields of "
287 // + this.currentObjectStreamClass.getName ());
293 this.currentObjectStreamClass.forClass ().
294 getDeclaredMethod ("readObject", readObjectParams);
296 catch (NoSuchMethodException e)
301 // XXX: should initialize fields in classes in the hierarchy
302 // that aren't in the stream
303 // should skip over classes in the stream that aren't in the
304 // real classes hierarchy
305 readFields (obj, this.currentObjectStreamClass.fields,
306 has_read, this.currentObjectStreamClass);
310 // DEBUG ("ENDBLOCKDATA? ");
311 if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
312 throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
316 this.currentObject = null;
317 this.currentObjectStreamClass = null;
318 ret_val = processResoultion (obj, handle);
324 ret_val = readObject ();
329 Exception e = (Exception)readObject ();
331 throw new WriteAbortedException ("Exception thrown during writing of stream", e);
335 throw new IOException ("Unknown marker on stream");
338 this.isDeserializing = was_deserializing;
340 if (! was_deserializing)
342 setBlockDataMode (true);
344 if (validators.size () > 0)
353 Reads the current objects non-transient, non-static fields from
354 the current class from the underlying output stream.
356 This method is intended to be called from within a object's
357 <code>private void readObject (ObjectInputStream)</code>
360 @exception ClassNotFoundException The class that an object being
361 read in belongs to cannot be found.
363 @exception NotActiveException This method was called from a
364 context other than from the current object's and current class's
365 <code>private void readObject (ObjectInputStream)</code>
368 @exception IOException Exception from underlying
369 <code>OutputStream</code>.
371 public void defaultReadObject ()
372 throws ClassNotFoundException, IOException, NotActiveException
374 if (this.currentObject == null || this.currentObjectStreamClass == null)
375 throw new NotActiveException ("defaultReadObject called by non-active class and/or object");
377 if (fieldsAlreadyRead)
378 throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
380 readFields (this.currentObject,
381 this.currentObjectStreamClass.fields,
382 false, this.currentObjectStreamClass);
384 fieldsAlreadyRead = true;
389 Registers a <code>ObjectInputValidation</code> to be carried out
390 on the object graph currently being deserialized before it is
391 returned to the original caller of <code>readObject ()</code>.
392 The order of validation for multiple
393 <code>ObjectInputValidation</code>s can be controled using
394 <code>priority</code>. Validators with higher priorities are
397 @see java.io.ObjectInputValidation
399 @exception InvalidObjectException <code>validator</code> is
402 @exception NotActiveException an attempt was made to add a
403 validator outside of the <code>readObject</code> method of the
404 object currently being deserialized
406 public void registerValidation (ObjectInputValidation validator,
408 throws InvalidObjectException, NotActiveException
410 if (this.currentObject == null || this.currentObjectStreamClass == null)
411 throw new NotActiveException ("registerValidation called by non-active class and/or object");
413 if (validator == null)
414 throw new InvalidObjectException ("attempt to add a null ObjectInputValidation object");
416 this.validators.addElement (new ValidatorAndPriority (validator,
422 Called when a class is being deserialized. This is a hook to
423 allow subclasses to read in information written by the
424 <code>annotateClass (Class)</code> method of an
425 <code>ObjectOutputStream</code>.
427 This implementation looks up the active call stack for a
428 <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
429 it is used to load the class associated with <code>osc</code>,
430 otherwise, the default system <code>ClassLoader</code> is used.
432 @exception IOException Exception from underlying
433 <code>OutputStream</code>.
435 @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
437 protected Class resolveClass (ObjectStreamClass osc)
438 throws ClassNotFoundException, IOException
440 // DEBUGln ("Resolving " + osc);
442 SecurityManager sm = System.getSecurityManager ();
445 sm = new SecurityManager () {};
447 ClassLoader cl = currentClassLoader (sm);
451 // DEBUGln ("No class loader found");
452 return Class.forName (osc.getName ());
456 // DEBUGln ("Using " + cl);
457 return cl.loadClass (osc.getName ());
463 Allows subclasses to resolve objects that are read from the
464 stream with other objects to be returned in their place. This
465 method is called the first time each object is encountered.
467 This method must be enabled before it will be called in the
468 serialization process.
470 @exception IOException Exception from underlying
471 <code>OutputStream</code>.
473 @see enableResolveObject (boolean)
475 protected Object resolveObject (Object obj) throws IOException
482 If <code>enable</code> is <code>true</code> and this object is
483 trusted, then <code>resolveObject (Object)</code> will be called
484 in subsequent calls to <code>readObject (Object)</code>.
485 Otherwise, <code>resolveObject (Object)</code> will not be called.
487 @exception SecurityException This class is not trusted.
489 protected boolean enableResolveObject (boolean enable)
490 throws SecurityException
493 if (getClass ().getClassLoader () != null)
494 throw new SecurityException ("Untrusted ObjectInputStream subclass attempted to enable object resolution");
496 boolean old_val = this.resolveEnabled;
497 this.resolveEnabled = enable;
503 Reads stream magic and stream version information from the
506 @exception IOException Exception from underlying stream.
508 @exception StreamCorruptedException An invalid stream magic
509 number or stream version was read from the stream.
511 protected void readStreamHeader ()
512 throws IOException, StreamCorruptedException
514 // DEBUG ("STREAM MAGIC ");
515 if (this.realInputStream.readShort () != STREAM_MAGIC)
516 throw new StreamCorruptedException ("Invalid stream magic number");
518 // DEBUG ("STREAM VERSION ");
519 if (this.realInputStream.readShort () != STREAM_VERSION)
520 throw new StreamCorruptedException ("Invalid stream version number");
524 public int read () throws IOException
526 if (this.readDataFromBlock)
528 if (this.blockDataPosition >= this.blockDataBytes)
530 return this.blockData[this.blockDataPosition++];
533 return this.realInputStream.read ();
536 public int read (byte data[], int offset, int length) throws IOException
538 if (this.readDataFromBlock)
540 if (this.blockDataPosition + length >= this.blockDataBytes)
543 System.arraycopy (this.blockData, this.blockDataPosition,
544 data, offset, length);
548 return this.realInputStream.read (data, offset, length);
551 public int available () throws IOException
553 if (this.readDataFromBlock)
555 if (this.blockDataPosition >= this.blockDataBytes)
558 return this.blockDataBytes - this.blockDataPosition;
561 return this.realInputStream.available ();
564 public void close () throws IOException
566 this.realInputStream.close ();
569 public boolean readBoolean () throws IOException
571 return this.dataInputStream.readBoolean ();
574 public byte readByte () throws IOException
576 return this.dataInputStream.readByte ();
579 public int readUnsignedByte () throws IOException
581 return this.dataInputStream.readUnsignedByte ();
584 public short readShort () throws IOException
586 return this.dataInputStream.readShort ();
589 public int readUnsignedShort () throws IOException
591 return this.dataInputStream.readUnsignedShort ();
594 public char readChar () throws IOException
596 return this.dataInputStream.readChar ();
599 public int readInt () throws IOException
601 return this.dataInputStream.readInt ();
604 public long readLong () throws IOException
606 return this.dataInputStream.readLong ();
609 public float readFloat () throws IOException
611 return this.dataInputStream.readFloat ();
614 public double readDouble () throws IOException
616 return this.dataInputStream.readDouble ();
619 public void readFully (byte data[]) throws IOException
621 this.dataInputStream.readFully (data);
624 public void readFully (byte data[], int offset, int size)
627 this.dataInputStream.readFully (data, offset, size);
630 public int skipBytes (int len) throws IOException
632 return this.dataInputStream.skipBytes (len);
637 @see java.io.DataInputStream#readLine ()
639 public String readLine () throws IOException
641 return this.dataInputStream.readLine ();
644 public String readUTF () throws IOException
646 return this.dataInputStream.readUTF ();
651 This class allows a class to specify exactly which fields should
652 be read, and what values should be read for these fields.
654 XXX: finish up comments
656 public static abstract class GetField
658 public abstract ObjectStreamClass getObjectStreamClass ();
660 public abstract boolean defaulted (String name)
661 throws IOException, IllegalArgumentException;
663 public abstract boolean get (String name, boolean defvalue)
664 throws IOException, IllegalArgumentException;
666 public abstract char get (String name, char defvalue)
667 throws IOException, IllegalArgumentException;
669 public abstract byte get (String name, byte defvalue)
670 throws IOException, IllegalArgumentException;
672 public abstract short get (String name, short defvalue)
673 throws IOException, IllegalArgumentException;
675 public abstract int get (String name, int defvalue)
676 throws IOException, IllegalArgumentException;
678 public abstract long get (String name, long defvalue)
679 throws IOException, IllegalArgumentException;
681 public abstract float get (String name, float defvalue)
682 throws IOException, IllegalArgumentException;
684 public abstract double get (String name, double defvalue)
685 throws IOException, IllegalArgumentException;
687 public abstract Object get (String name, Object defvalue)
688 throws IOException, IllegalArgumentException;
691 public GetField readFields ()
692 throws IOException, ClassNotFoundException, NotActiveException
694 if (this.currentObject == null || this.currentObjectStreamClass == null)
695 throw new NotActiveException ("readFields called by non-active class and/or object");
697 if (fieldsAlreadyRead)
698 throw new NotActiveException ("readFields called but fields already read from stream (by defaultReadObject or readFields)");
700 final ObjectStreamClass clazz = this.currentObjectStreamClass;
701 final byte[] prim_field_data = new byte[clazz.primFieldSize];
702 final Object[] objs = new Object[clazz.objectFieldCount];
703 readFully (prim_field_data);
704 for (int i = 0; i < objs.length; ++ i)
705 objs[i] = readObject ();
707 return new GetField ()
709 public ObjectStreamClass getObjectStreamClass ()
714 public boolean defaulted (String name)
715 throws IOException, IllegalArgumentException
717 return clazz.getField (name) == null;
720 public boolean get (String name, boolean defvalue)
721 throws IOException, IllegalArgumentException
723 ObjectStreamField field = getField (name, Boolean.TYPE);
728 return prim_field_data[field.getOffset ()] == 0 ? false : true;
731 public char get (String name, char defvalue)
732 throws IOException, IllegalArgumentException
734 ObjectStreamField field = getField (name, Character.TYPE);
739 int off = field.getOffset ();
741 return (char)(((prim_field_data[off++] & 0xFF) << 8)
742 | (prim_field_data[off] & 0xFF));
745 public byte get (String name, byte defvalue)
746 throws IOException, IllegalArgumentException
748 ObjectStreamField field = getField (name, Byte.TYPE);
753 return prim_field_data[field.getOffset ()];
756 public short get (String name, short defvalue)
757 throws IOException, IllegalArgumentException
759 ObjectStreamField field = getField (name, Short.TYPE);
764 int off = field.getOffset ();
766 return (short)(((prim_field_data[off++] & 0xFF) << 8)
767 | (prim_field_data[off] & 0xFF));
770 public int get (String name, int defvalue)
771 throws IOException, IllegalArgumentException
773 ObjectStreamField field = getField (name, Integer.TYPE);
778 int off = field.getOffset ();
780 return ((prim_field_data[off++] & 0xFF) << 24)
781 | ((prim_field_data[off++] & 0xFF) << 16)
782 | ((prim_field_data[off++] & 0xFF) << 8)
783 | (prim_field_data[off] & 0xFF);
786 public long get (String name, long defvalue)
787 throws IOException, IllegalArgumentException
789 ObjectStreamField field = getField (name, Long.TYPE);
794 int off = field.getOffset ();
796 return (long)(((prim_field_data[off++] & 0xFF) << 56)
797 | ((prim_field_data[off++] & 0xFF) << 48)
798 | ((prim_field_data[off++] & 0xFF) << 40)
799 | ((prim_field_data[off++] & 0xFF) << 32)
800 | ((prim_field_data[off++] & 0xFF) << 24)
801 | ((prim_field_data[off++] & 0xFF) << 16)
802 | ((prim_field_data[off++] & 0xFF) << 8)
803 | (prim_field_data[off] & 0xFF));
806 public float get (String name, float defvalue)
807 throws IOException, IllegalArgumentException
809 ObjectStreamField field = getField (name, Float.TYPE);
814 int off = field.getOffset ();
816 return Float.intBitsToFloat (((prim_field_data[off++] & 0xFF) << 24)
817 | ((prim_field_data[off++] & 0xFF) << 16)
818 | ((prim_field_data[off++] & 0xFF) << 8)
819 | (prim_field_data[off] & 0xFF));
822 public double get (String name, double defvalue)
823 throws IOException, IllegalArgumentException
825 ObjectStreamField field = getField (name, Double.TYPE);
830 int off = field.getOffset ();
832 return Double.longBitsToDouble (
833 (long)(((prim_field_data[off++] & 0xFF) << 56)
834 | ((prim_field_data[off++] & 0xFF) << 48)
835 | ((prim_field_data[off++] & 0xFF) << 40)
836 | ((prim_field_data[off++] & 0xFF) << 32)
837 | ((prim_field_data[off++] & 0xFF) << 24)
838 | ((prim_field_data[off++] & 0xFF) << 16)
839 | ((prim_field_data[off++] & 0xFF) << 8)
840 | (prim_field_data[off] & 0xFF)));
843 public Object get (String name, Object defvalue)
844 throws IOException, IllegalArgumentException
846 ObjectStreamField field = getField (name, null);
851 return objs[field.getOffset ()];
854 private ObjectStreamField getField (String name, Class type)
855 throws IllegalArgumentException
857 ObjectStreamField field = clazz.getField (name);
862 Class field_type = field.getType ();
864 if (type == field_type ||
865 (type != null && field_type.isPrimitive ()))
868 throw new IllegalArgumentException ("Field requested is of type "
869 + field_type.getName ()
870 + ", but requested type was "
872 "Object" : type.getName ()));
880 Protected constructor that allows subclasses to override
881 deserialization. This constructor should be called by subclasses
882 that wish to override <code>readObject (Object)</code>. This
883 method does a security check <i>NOTE: currently not
884 implemented</i>, then sets a flag that informs
885 <code>readObject (Object)</code> to call the subclasses
886 <code>readObjectOverride (Object)</code> method.
888 @see readObjectOverride (Object)
890 protected ObjectInputStream ()
891 throws IOException, SecurityException
893 SecurityManager sec_man = System.getSecurityManager ();
895 sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
896 this.useSubclassMethod = true;
901 This method allows subclasses to override the default
902 de serialization mechanism provided by
903 <code>ObjectInputStream</code>. To make this method be used for
904 writing objects, subclasses must invoke the 0-argument
905 constructor on this class from there constructor.
907 @see ObjectInputStream ()
909 protected Object readObjectOverride ()
910 throws ClassNotFoundException, IOException, OptionalDataException
912 throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
916 // assigns the next availible handle to OBJ
917 private int assignNewHandle (Object obj)
919 this.objectLookupTable.put (new Integer (this.nextOID),
920 new ObjectIdentityWrapper (obj));
924 // DEBUG ("Assigning handle " + this.nextOID);
925 // DEBUGln (" to " + obj);
927 // catch (Throwable t) {}
929 return this.nextOID++;
933 private Object processResoultion (Object obj, int handle)
936 if (obj instanceof Resolvable)
937 obj = ((Resolvable)obj).readResolve ();
939 if (this.resolveEnabled)
940 obj = resolveObject (obj);
942 this.objectLookupTable.put (new Integer (handle),
943 new ObjectIdentityWrapper (obj));
949 private void clearHandles ()
951 this.objectLookupTable.clear ();
952 this.nextOID = baseWireHandle;
956 private void readNextBlock () throws IOException
958 // DEBUG ("MARKER ");
959 readNextBlock (this.realInputStream.readByte ());
963 private void readNextBlock (byte marker) throws IOException
965 if (marker == TC_BLOCKDATA)
967 // DEBUG ("BLOCK DATA SIZE ");
968 this.blockDataBytes = this.realInputStream.readUnsignedByte ();
970 else if (marker == TC_BLOCKDATALONG)
972 // DEBUG ("BLOCK DATA LONG SIZE ");
973 this.blockDataBytes = this.realInputStream.readInt ();
977 throw new EOFException ("Attempt to read primitive data, but no data block is active.");
980 if (this.blockData.length < this.blockDataBytes)
981 this.blockData = new byte[this.blockDataBytes];
983 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
984 this.blockDataPosition = 0;
988 private void readArrayElements (Object array, Class clazz)
989 throws ClassNotFoundException, IOException
991 if (clazz.isPrimitive ())
993 if (clazz == Boolean.TYPE)
995 boolean[] cast_array = (boolean[])array;
996 for (int i=0; i < cast_array.length; i++)
997 cast_array[i] = this.realInputStream.readBoolean ();
1000 if (clazz == Byte.TYPE)
1002 byte[] cast_array = (byte[])array;
1003 for (int i=0; i < cast_array.length; i++)
1004 cast_array[i] = this.realInputStream.readByte ();
1007 if (clazz == Character.TYPE)
1009 char[] cast_array = (char[])array;
1010 for (int i=0; i < cast_array.length; i++)
1011 cast_array[i] = this.realInputStream.readChar ();
1014 if (clazz == Double.TYPE)
1016 double[] cast_array = (double[])array;
1017 for (int i=0; i < cast_array.length; i++)
1018 cast_array[i] = this.realInputStream.readDouble ();
1021 if (clazz == Float.TYPE)
1023 float[] cast_array = (float[])array;
1024 for (int i=0; i < cast_array.length; i++)
1025 cast_array[i] = this.realInputStream.readFloat ();
1028 if (clazz == Integer.TYPE)
1030 int[] cast_array = (int[])array;
1031 for (int i=0; i < cast_array.length; i++)
1032 cast_array[i] = this.realInputStream.readInt ();
1035 if (clazz == Long.TYPE)
1037 long[] cast_array = (long[])array;
1038 for (int i=0; i < cast_array.length; i++)
1039 cast_array[i] = this.realInputStream.readLong ();
1042 if (clazz == Short.TYPE)
1044 short[] cast_array = (short[])array;
1045 for (int i=0; i < cast_array.length; i++)
1046 cast_array[i] = this.realInputStream.readShort ();
1052 Object[] cast_array = (Object[])array;
1053 for (int i=0; i < cast_array.length; i++)
1054 cast_array[i] = readObject ();
1059 private void readFields (Object obj, ObjectStreamField[] stream_fields,
1060 boolean call_read_method,
1061 ObjectStreamClass stream_osc)
1062 throws ClassNotFoundException, IOException
1064 if (call_read_method)
1066 fieldsAlreadyRead = false;
1067 setBlockDataMode (true);
1068 callReadMethod (obj, stream_osc.forClass ());
1069 setBlockDataMode (false);
1073 ObjectStreamField[] real_fields =
1074 ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
1076 boolean default_initialize, set_value;
1077 String field_name = null;
1079 ObjectStreamField stream_field = null;
1080 ObjectStreamField real_field = null;
1084 while (stream_idx < stream_fields.length
1085 && real_idx < real_fields.length)
1087 default_initialize = false;
1090 if (stream_idx == stream_fields.length)
1091 default_initialize = true;
1094 stream_field = stream_fields[stream_idx];
1095 type = stream_field.getType ();
1098 if (real_idx == real_fields.length)
1102 real_field = real_fields[real_idx];
1103 type = real_field.getType ();
1104 field_name = real_field.getName ();
1107 if (set_value && !default_initialize)
1110 real_field.compareTo (stream_field);
1114 default_initialize = true;
1117 else if (comp_val > 0)
1129 if (type == Boolean.TYPE)
1132 default_initialize ? false : this.realInputStream.readBoolean ();
1134 setBooleanField (obj, field_name, value);
1136 else if (type == Byte.TYPE)
1139 default_initialize ? 0 : this.realInputStream.readByte ();
1141 setByteField (obj, field_name, value);
1143 else if (type == Character.TYPE)
1146 default_initialize ? (char)0 : this.realInputStream.readChar ();
1148 setCharField (obj, field_name, value);
1150 else if (type == Double.TYPE)
1153 default_initialize ? 0 : this.realInputStream.readDouble ();
1155 setDoubleField (obj, field_name, value);
1157 else if (type == Float.TYPE)
1160 default_initialize ? 0 : this.realInputStream.readFloat ();
1162 setFloatField (obj, field_name, value);
1164 else if (type == Integer.TYPE)
1167 default_initialize ? 0 : this.realInputStream.readInt ();
1169 setIntField (obj, field_name, value);
1171 else if (type == Long.TYPE)
1174 default_initialize ? 0 : this.realInputStream.readLong ();
1176 setLongField (obj, field_name, value);
1178 else if (type == Short.TYPE)
1181 default_initialize ? (short)0 : this.realInputStream.readShort ();
1183 setShortField (obj, field_name, value);
1188 default_initialize ? null : readObject ();
1190 setObjectField (obj, field_name,
1191 real_field.getTypeString (), value);
1197 // Toggles writing primitive data to block-data buffer.
1198 private void setBlockDataMode (boolean on)
1200 // DEBUGln ("Setting block data mode to " + on);
1202 this.readDataFromBlock = on;
1205 this.dataInputStream = this.blockDataInput;
1207 this.dataInputStream = this.realInputStream;
1211 // returns a new instance of REAL_CLASS that has been constructed
1212 // only to th level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1213 private Object newObject (Class real_class, Class constructor_class)
1217 Object obj = allocateObject (real_class);
1218 callConstructor (constructor_class, obj);
1221 catch (InstantiationException e)
1228 // runs all registered ObjectInputValidations in prioritized order
1230 private void invokeValidators () throws InvalidObjectException
1232 Object[] validators = new Object[this.validators.size ()];
1233 this.validators.copyInto (validators);
1234 Arrays.sort (validators);
1238 for (int i=0; i < validators.length; i++)
1239 ((ObjectInputValidation)validators[i]).validateObject ();
1243 this.validators.removeAllElements ();
1248 // this native method is used to get access to the protected method
1249 // of the same name in SecurityManger
1250 private static ClassLoader currentClassLoader (SecurityManager sm)
1252 // FIXME: This is too simple.
1253 return ClassLoader.getSystemClassLoader ();
1256 private static native Field getField (Class klass, String name)
1257 throws java.lang.NoSuchFieldException;
1259 private static native Method getMethod (Class klass, String name, Class args[])
1260 throws java.lang.NoSuchMethodException;
1262 private void callReadMethod (Object obj, Class klass) throws IOException
1266 Class classArgs[] = {Class.forName ("java.io.ObjectInputStream")};
1267 Method m = getMethod (klass, "readObject", classArgs);
1270 Object args[] = {this};
1271 m.invoke (obj, args);
1275 throw new IOException ();
1279 private native Object allocateObject (Class clazz)
1280 throws InstantiationException;
1282 private native void callConstructor (Class clazz, Object obj);
1284 private void setBooleanField (Object obj, String field_name,
1289 Class klass = obj.getClass ();
1290 Field f = getField (klass, field_name);
1291 f.setBoolean (obj, val);
1298 private void setByteField (Object obj, String field_name,
1303 Class klass = obj.getClass ();
1304 Field f = getField (klass, field_name);
1305 f.setByte (obj, val);
1312 private void setCharField (Object obj, String field_name,
1317 Class klass = obj.getClass ();
1318 Field f = getField (klass, field_name);
1319 f.setChar (obj, val);
1326 private void setDoubleField (Object obj, String field_name,
1331 Class klass = obj.getClass ();
1332 Field f = getField (klass, field_name);
1333 f.setDouble (obj, val);
1340 private void setFloatField (Object obj, String field_name,
1345 Class klass = obj.getClass ();
1346 Field f = getField (klass, field_name);
1347 f.setFloat (obj, val);
1354 private void setIntField (Object obj, String field_name,
1359 Class klass = obj.getClass ();
1360 Field f = getField (klass, field_name);
1361 f.setInt (obj, val);
1369 private void setLongField (Object obj, String field_name,
1374 Class klass = obj.getClass ();
1375 Field f = getField (klass, field_name);
1376 f.setLong (obj, val);
1384 private void setShortField (Object obj, String field_name,
1389 Class klass = obj.getClass ();
1390 Field f = getField (klass, field_name);
1391 f.setShort (obj, val);
1399 private void setObjectField (Object obj, String field_name, String type_code,
1404 Class klass = obj.getClass ();
1405 Field f = getField (klass, field_name);
1406 // FIXME: We should check the type_code here
1414 private static final int BUFFER_SIZE = 1024;
1415 private static final Class[] readObjectParams = { ObjectInputStream.class };
1417 private DataInputStream realInputStream;
1418 private DataInputStream dataInputStream;
1419 private DataInputStream blockDataInput;
1420 private int blockDataPosition;
1421 private int blockDataBytes;
1422 private byte[] blockData;
1423 private boolean useSubclassMethod;
1424 private int nextOID;
1425 private boolean resolveEnabled;
1426 private Hashtable objectLookupTable;
1427 private Object currentObject;
1428 private ObjectStreamClass currentObjectStreamClass;
1429 private boolean readDataFromBlock;
1430 private boolean isDeserializing;
1431 private boolean fieldsAlreadyRead;
1432 private Vector validators;
1435 /* FIXME: These 2 methods cause a build error on i686-pc-linux-gnu.
1436 private void DEBUG (String msg)
1438 System.out.print (msg);
1442 private void DEBUGln (String msg)
1444 System.out.println (msg);
1450 // used to keep a prioritized list of object validators
1451 class ValidatorAndPriority implements Comparable
1454 ObjectInputValidation validator;
1456 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1458 this.priority = priority;
1459 this.validator = validator;
1462 public int compareTo (Object o)
1464 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1465 return this.priority - vap.priority;