1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002 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 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
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. */
41 import gnu
.classpath
.Configuration
;
43 import java
.lang
.reflect
.Array
;
44 import java
.lang
.reflect
.Modifier
;
45 import java
.lang
.reflect
.Proxy
;
46 import java
.util
.Arrays
;
47 import java
.util
.Hashtable
;
48 import java
.util
.Vector
;
50 import gnu
.java
.io
.ObjectIdentityWrapper
;
51 import gnu
.java
.lang
.reflect
.TypeSignature
;
52 import java
.lang
.reflect
.Field
;
53 import java
.lang
.reflect
.Method
;
54 import java
.lang
.reflect
.InvocationTargetException
;
58 public class ObjectInputStream
extends InputStream
59 implements ObjectInput
, ObjectStreamConstants
62 Creates a new <code>ObjectInputStream</code> that will do all of
63 its reading from <code>in</code>. This method also checks
64 the stream by reading the header information (stream magic number
67 @exception IOException Reading stream header from underlying
68 stream cannot be completed.
70 @exception StreamCorruptedException An invalid stream magic
71 number or stream version was read from the stream.
73 @see readStreamHeader ()
75 public ObjectInputStream (InputStream in
)
76 throws IOException
, StreamCorruptedException
78 if (Configuration
.DEBUG
)
80 String val
= System
.getProperty("gcj.dumpobjects");
81 if (dump
== false && val
!= null && !val
.equals(""))
84 System
.out
.println ("Serialization debugging enabled");
86 else if (dump
== true && (val
== null || val
.equals("")))
89 System
.out
.println ("Serialization debugging disabled");
93 this.resolveEnabled
= false;
94 this.isDeserializing
= false;
95 this.blockDataPosition
= 0;
96 this.blockDataBytes
= 0;
97 this.blockData
= new byte[BUFFER_SIZE
];
98 this.blockDataInput
= new DataInputStream (this);
99 this.realInputStream
= new DataInputStream (in
);
100 this.nextOID
= baseWireHandle
;
101 this.objectLookupTable
= new Hashtable ();
102 this.validators
= new Vector ();
103 setBlockDataMode (true);
109 Returns the next deserialized object read from the underlying stream.
111 This method can be overriden by a class by implementing
112 <code>private void readObject (ObjectInputStream)</code>.
114 If an exception is thrown from this method, the stream is left in
117 @exception ClassNotFoundException The class that an object being
118 read in belongs to cannot be found.
120 @exception IOException Exception from underlying
121 <code>InputStream</code>.
123 public final Object
readObject () throws ClassNotFoundException
, IOException
125 if (this.useSubclassMethod
)
126 return readObjectOverride ();
128 boolean was_deserializing
;
131 was_deserializing
= this.isDeserializing
;
133 if (! was_deserializing
)
134 setBlockDataMode (false);
136 this.isDeserializing
= true;
138 byte marker
= this.realInputStream
.readByte ();
139 dumpElement ("MARKER: 0x" + Integer
.toHexString(marker
) + " ");
144 case TC_BLOCKDATALONG
:
145 if (marker
== TC_BLOCKDATALONG
)
146 dumpElementln ("BLOCKDATALONG");
148 dumpElementln ("BLOCKDATA");
149 readNextBlock (marker
);
150 throw new StreamCorruptedException ("Unexpected blockData");
153 dumpElementln ("NULL");
159 dumpElement ("REFERENCE ");
160 Integer oid
= new Integer (this.realInputStream
.readInt ());
161 dumpElementln (Integer
.toHexString(oid
.intValue()));
162 ret_val
= ((ObjectIdentityWrapper
)
163 this.objectLookupTable
.get (oid
)).object
;
169 dumpElementln ("CLASS");
170 ObjectStreamClass osc
= (ObjectStreamClass
)readObject ();
171 Class clazz
= osc
.forClass ();
172 assignNewHandle (clazz
);
179 dumpElement ("CLASSDESC NAME=");
180 String name
= this.realInputStream
.readUTF ();
181 dumpElement (name
+ "; UID=");
182 long uid
= this.realInputStream
.readLong ();
183 dumpElement (Long
.toHexString(uid
) + "; FLAGS=");
184 byte flags
= this.realInputStream
.readByte ();
185 dumpElement (Integer
.toHexString(flags
) + "; FIELD COUNT=");
186 short field_count
= this.realInputStream
.readShort ();
187 dumpElementln (Short
.toString(field_count
));
188 ObjectStreamField
[] fields
= new ObjectStreamField
[field_count
];
190 ObjectStreamClass osc
= new ObjectStreamClass (name
, uid
,
192 assignNewHandle (osc
);
194 for (int i
=0; i
< field_count
; i
++)
196 dumpElement (" TYPE CODE=");
197 char type_code
= (char)this.realInputStream
.readByte ();
198 dumpElement (type_code
+ "; FIELD NAME=");
199 String field_name
= this.realInputStream
.readUTF ();
200 dumpElementln (field_name
);
203 if (type_code
== 'L' || type_code
== '[')
204 class_name
= (String
)readObject ();
206 class_name
= String
.valueOf (type_code
);
209 new ObjectStreamField (field_name
,
210 TypeSignature
.getClassForEncoding
214 Class cl
= resolveClass (osc
);
216 setBlockDataMode (false);
218 if (this.realInputStream
.readByte () != TC_ENDBLOCKDATA
)
219 throw new IOException ("Data annotated to class was not consumed.");
220 dumpElementln ("ENDBLOCKDATA ");
222 osc
.setSuperclass ((ObjectStreamClass
)readObject ());
229 dumpElement ("STRING=");
230 String s
= this.realInputStream
.readUTF ();
232 ret_val
= processResolution (s
, assignNewHandle (s
));
238 dumpElementln ("ARRAY");
239 ObjectStreamClass osc
= (ObjectStreamClass
)readObject ();
240 Class componentType
= osc
.forClass ().getComponentType ();
241 dumpElement ("ARRAY LENGTH=");
242 int length
= this.realInputStream
.readInt ();
243 dumpElementln (length
+ "; COMPONENT TYPE=" + componentType
);
244 Object array
= Array
.newInstance (componentType
, length
);
245 int handle
= assignNewHandle (array
);
246 readArrayElements (array
, componentType
);
247 for (int i
=0, len
=Array
.getLength(array
); i
< len
; i
++)
248 dumpElementln (" ELEMENT[" + i
+ "]=" + Array
.get(array
, i
));
249 ret_val
= processResolution (array
, handle
);
255 dumpElementln ("OBJECT");
256 ObjectStreamClass osc
= (ObjectStreamClass
)readObject ();
257 Class clazz
= osc
.forClass ();
259 if (!Serializable
.class.isAssignableFrom (clazz
))
260 throw new NotSerializableException (clazz
+ " is not Serializable, and thus cannot be deserialized.");
262 if (Externalizable
.class.isAssignableFrom (clazz
))
264 Externalizable obj
= null;
268 obj
= (Externalizable
)clazz
.newInstance ();
270 catch (InstantiationException e
)
272 throw new ClassNotFoundException ("Instance of " + clazz
273 + " could not be created");
275 catch (IllegalAccessException e
)
277 throw new ClassNotFoundException ("Instance of " + clazz
278 + " could not be created because class or zero-argument constructor is not accessible");
280 catch (NoSuchMethodError e
)
282 throw new ClassNotFoundException ("Instance of " + clazz
283 + " could not be created because zero-argument constructor is not defined");
286 int handle
= assignNewHandle (obj
);
288 boolean read_from_blocks
= ((osc
.getFlags () & SC_BLOCK_DATA
) != 0);
290 if (read_from_blocks
)
291 setBlockDataMode (true);
293 obj
.readExternal (this);
295 if (read_from_blocks
)
296 setBlockDataMode (false);
298 ret_val
= processResolution (obj
, handle
);
300 } // end if (Externalizable.class.isAssignableFrom (clazz))
302 // find the first non-serializable, non-abstract
303 // class in clazz's inheritance hierarchy
304 Class first_nonserial
= clazz
.getSuperclass ();
305 while (Serializable
.class.isAssignableFrom (first_nonserial
)
306 || Modifier
.isAbstract (first_nonserial
.getModifiers ()))
307 first_nonserial
= first_nonserial
.getSuperclass ();
309 // DEBUGln ("Using " + first_nonserial
310 // + " as starting point for constructing " + clazz);
313 obj
= newObject (clazz
, first_nonserial
);
316 throw new ClassNotFoundException ("Instance of " + clazz
+
317 " could not be created");
319 int handle
= assignNewHandle (obj
);
320 this.currentObject
= obj
;
321 ObjectStreamClass
[] hierarchy
=
322 ObjectStreamClass
.getObjectStreamClasses (clazz
);
324 // DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
327 for (int i
=0; i
< hierarchy
.length
; i
++)
329 this.currentObjectStreamClass
= hierarchy
[i
];
331 dumpElementln ("Reading fields of "
332 + this.currentObjectStreamClass
.getName ());
338 this.currentObjectStreamClass
.forClass ().
339 getDeclaredMethod ("readObject", readObjectParams
);
341 catch (NoSuchMethodException e
)
346 // XXX: should initialize fields in classes in the hierarchy
347 // that aren't in the stream
348 // should skip over classes in the stream that aren't in the
349 // real classes hierarchy
350 readFields (obj
, this.currentObjectStreamClass
.fields
,
351 has_read
, this.currentObjectStreamClass
);
355 dumpElement ("ENDBLOCKDATA? ");
358 // FIXME: XXX: This try block is to catch EOF which is
359 // thrown for some objects. That indicates a bug in the logic.
360 if (this.realInputStream
.readByte () != TC_ENDBLOCKDATA
)
361 throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
362 dumpElementln ("yes");
364 catch (EOFException e
)
366 dumpElementln ("no, got EOFException");
368 catch (IOException e
)
370 dumpElementln ("no, got IOException");
375 this.currentObject
= null;
376 this.currentObjectStreamClass
= null;
377 ret_val
= processResolution (obj
, handle
);
382 dumpElementln ("RESET");
384 ret_val
= readObject ();
389 dumpElement ("EXCEPTION=");
390 Exception e
= (Exception
)readObject ();
391 dumpElementln (e
.toString());
393 throw new WriteAbortedException ("Exception thrown during writing of stream", e
);
397 throw new IOException ("Unknown marker on stream");
400 this.isDeserializing
= was_deserializing
;
402 if (! was_deserializing
)
404 setBlockDataMode (true);
406 if (validators
.size () > 0)
415 Reads the current objects non-transient, non-static fields from
416 the current class from the underlying output stream.
418 This method is intended to be called from within a object's
419 <code>private void readObject (ObjectInputStream)</code>
422 @exception ClassNotFoundException The class that an object being
423 read in belongs to cannot be found.
425 @exception NotActiveException This method was called from a
426 context other than from the current object's and current class's
427 <code>private void readObject (ObjectInputStream)</code>
430 @exception IOException Exception from underlying
431 <code>OutputStream</code>.
433 public void defaultReadObject ()
434 throws ClassNotFoundException
, IOException
, NotActiveException
436 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
437 throw new NotActiveException ("defaultReadObject called by non-active class and/or object");
439 if (fieldsAlreadyRead
)
440 throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
442 readFields (this.currentObject
,
443 this.currentObjectStreamClass
.fields
,
444 false, this.currentObjectStreamClass
);
446 fieldsAlreadyRead
= true;
451 Registers a <code>ObjectInputValidation</code> to be carried out
452 on the object graph currently being deserialized before it is
453 returned to the original caller of <code>readObject ()</code>.
454 The order of validation for multiple
455 <code>ObjectInputValidation</code>s can be controled using
456 <code>priority</code>. Validators with higher priorities are
459 @see java.io.ObjectInputValidation
461 @exception InvalidObjectException <code>validator</code> is
464 @exception NotActiveException an attempt was made to add a
465 validator outside of the <code>readObject</code> method of the
466 object currently being deserialized
468 public void registerValidation (ObjectInputValidation validator
,
470 throws InvalidObjectException
, NotActiveException
472 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
473 throw new NotActiveException ("registerValidation called by non-active class and/or object");
475 if (validator
== null)
476 throw new InvalidObjectException ("attempt to add a null ObjectInputValidation object");
478 this.validators
.addElement (new ValidatorAndPriority (validator
,
484 Called when a class is being deserialized. This is a hook to
485 allow subclasses to read in information written by the
486 <code>annotateClass (Class)</code> method of an
487 <code>ObjectOutputStream</code>.
489 This implementation looks up the active call stack for a
490 <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
491 it is used to load the class associated with <code>osc</code>,
492 otherwise, the default system <code>ClassLoader</code> is used.
494 @exception IOException Exception from underlying
495 <code>OutputStream</code>.
497 @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
499 protected Class
resolveClass (ObjectStreamClass osc
)
500 throws ClassNotFoundException
, IOException
502 SecurityManager sm
= System
.getSecurityManager ();
504 // FIXME: currentClassLoader doesn't yet do anything useful. We need
505 // to call forName() with the classloader of the class which called
506 // readObject(). See SecurityManager.getClassContext().
507 ClassLoader cl
= currentClassLoader (sm
);
509 return Class
.forName (osc
.getName (), true, cl
);
513 Allows subclasses to resolve objects that are read from the
514 stream with other objects to be returned in their place. This
515 method is called the first time each object is encountered.
517 This method must be enabled before it will be called in the
518 serialization process.
520 @exception IOException Exception from underlying
521 <code>OutputStream</code>.
523 @see enableResolveObject (boolean)
525 protected Object
resolveObject (Object obj
) throws IOException
531 protected Class
resolveProxyClass (String
[] intfs
)
532 throws IOException
, ClassNotFoundException
534 SecurityManager sm
= System
.getSecurityManager ();
537 sm
= new SecurityManager () {};
539 ClassLoader cl
= currentClassLoader (sm
);
541 Class
[] clss
= new Class
[intfs
.length
];
543 for (int i
= 0; i
< intfs
.length
; i
++)
544 clss
[i
] = Class
.forName(intfs
[i
]);
545 cl
= ClassLoader
.getSystemClassLoader();
548 for (int i
= 0; i
< intfs
.length
; i
++)
549 clss
[i
] = cl
.loadClass(intfs
[i
]);
551 return Proxy
.getProxyClass(cl
, clss
);
552 } catch (IllegalArgumentException e
) {
553 throw new ClassNotFoundException(null, e
);
558 If <code>enable</code> is <code>true</code> and this object is
559 trusted, then <code>resolveObject (Object)</code> will be called
560 in subsequent calls to <code>readObject (Object)</code>.
561 Otherwise, <code>resolveObject (Object)</code> will not be called.
563 @exception SecurityException This class is not trusted.
565 protected boolean enableResolveObject (boolean enable
)
566 throws SecurityException
570 SecurityManager sm
= System
.getSecurityManager ();
572 sm
.checkPermission (new SerializablePermission ("enableSubtitution"));
575 boolean old_val
= this.resolveEnabled
;
576 this.resolveEnabled
= enable
;
582 Reads stream magic and stream version information from the
585 @exception IOException Exception from underlying stream.
587 @exception StreamCorruptedException An invalid stream magic
588 number or stream version was read from the stream.
590 protected void readStreamHeader ()
591 throws IOException
, StreamCorruptedException
593 dumpElement ("STREAM MAGIC ");
594 if (this.realInputStream
.readShort () != STREAM_MAGIC
)
595 throw new StreamCorruptedException ("Invalid stream magic number");
597 dumpElementln ("STREAM VERSION ");
598 if (this.realInputStream
.readShort () != STREAM_VERSION
)
599 throw new StreamCorruptedException ("Invalid stream version number");
603 public int read () throws IOException
605 if (this.readDataFromBlock
)
607 if (this.blockDataPosition
>= this.blockDataBytes
)
609 return (this.blockData
[this.blockDataPosition
++] & 0xff);
612 return this.realInputStream
.read ();
615 public int read (byte[] data
, int offset
, int length
) throws IOException
617 if (this.readDataFromBlock
)
619 if (this.blockDataPosition
+ length
> this.blockDataBytes
)
622 System
.arraycopy (this.blockData
, this.blockDataPosition
,
623 data
, offset
, length
);
624 blockDataPosition
+= length
;
629 return this.realInputStream
.read (data
, offset
, length
);
632 public int available () throws IOException
634 if (this.readDataFromBlock
)
636 if (this.blockDataPosition
>= this.blockDataBytes
)
639 return this.blockDataBytes
- this.blockDataPosition
;
642 return this.realInputStream
.available ();
645 public void close () throws IOException
647 this.realInputStream
.close ();
650 public boolean readBoolean () throws IOException
652 return this.dataInputStream
.readBoolean ();
655 public byte readByte () throws IOException
657 return this.dataInputStream
.readByte ();
660 public int readUnsignedByte () throws IOException
662 return this.dataInputStream
.readUnsignedByte ();
665 public short readShort () throws IOException
667 return this.dataInputStream
.readShort ();
670 public int readUnsignedShort () throws IOException
672 return this.dataInputStream
.readUnsignedShort ();
675 public char readChar () throws IOException
677 return this.dataInputStream
.readChar ();
680 public int readInt () throws IOException
682 return this.dataInputStream
.readInt ();
685 public long readLong () throws IOException
687 return this.dataInputStream
.readLong ();
690 public float readFloat () throws IOException
692 return this.dataInputStream
.readFloat ();
695 public double readDouble () throws IOException
697 return this.dataInputStream
.readDouble ();
700 public void readFully (byte data
[]) throws IOException
702 this.dataInputStream
.readFully (data
);
705 public void readFully (byte data
[], int offset
, int size
)
708 this.dataInputStream
.readFully (data
, offset
, size
);
711 public int skipBytes (int len
) throws IOException
713 return this.dataInputStream
.skipBytes (len
);
718 @see java.io.DataInputStream#readLine ()
720 public String
readLine () throws IOException
722 return this.dataInputStream
.readLine ();
725 public String
readUTF () throws IOException
727 return this.dataInputStream
.readUTF ();
732 This class allows a class to specify exactly which fields should
733 be read, and what values should be read for these fields.
735 XXX: finish up comments
737 public static abstract class GetField
739 public abstract ObjectStreamClass
getObjectStreamClass ();
741 public abstract boolean defaulted (String name
)
742 throws IOException
, IllegalArgumentException
;
744 public abstract boolean get (String name
, boolean defvalue
)
745 throws IOException
, IllegalArgumentException
;
747 public abstract char get (String name
, char defvalue
)
748 throws IOException
, IllegalArgumentException
;
750 public abstract byte get (String name
, byte defvalue
)
751 throws IOException
, IllegalArgumentException
;
753 public abstract short get (String name
, short defvalue
)
754 throws IOException
, IllegalArgumentException
;
756 public abstract int get (String name
, int defvalue
)
757 throws IOException
, IllegalArgumentException
;
759 public abstract long get (String name
, long defvalue
)
760 throws IOException
, IllegalArgumentException
;
762 public abstract float get (String name
, float defvalue
)
763 throws IOException
, IllegalArgumentException
;
765 public abstract double get (String name
, double defvalue
)
766 throws IOException
, IllegalArgumentException
;
768 public abstract Object
get (String name
, Object defvalue
)
769 throws IOException
, IllegalArgumentException
;
772 public GetField
readFields ()
773 throws IOException
, ClassNotFoundException
, NotActiveException
775 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
776 throw new NotActiveException ("readFields called by non-active class and/or object");
778 if (fieldsAlreadyRead
)
779 throw new NotActiveException ("readFields called but fields already read from stream (by defaultReadObject or readFields)");
781 final ObjectStreamClass clazz
= this.currentObjectStreamClass
;
782 final byte[] prim_field_data
= new byte[clazz
.primFieldSize
];
783 final Object
[] objs
= new Object
[clazz
.objectFieldCount
];
785 // Apparently Block data is not used with GetField as per
786 // empirical evidence against JDK 1.2. Also see Mauve test
787 // java.io.ObjectInputOutput.Test.GetPutField.
788 setBlockDataMode (false);
789 readFully (prim_field_data
);
790 for (int i
= 0; i
< objs
.length
; ++ i
)
791 objs
[i
] = readObject ();
792 setBlockDataMode (true);
794 return new GetField ()
796 public ObjectStreamClass
getObjectStreamClass ()
801 public boolean defaulted (String name
)
802 throws IOException
, IllegalArgumentException
804 return clazz
.getField (name
) == null;
807 public boolean get (String name
, boolean defvalue
)
808 throws IOException
, IllegalArgumentException
810 ObjectStreamField field
= getField (name
, Boolean
.TYPE
);
815 return prim_field_data
[field
.getOffset ()] == 0 ?
false : true;
818 public char get (String name
, char defvalue
)
819 throws IOException
, IllegalArgumentException
821 ObjectStreamField field
= getField (name
, Character
.TYPE
);
826 int off
= field
.getOffset ();
828 return (char)(((prim_field_data
[off
++] & 0xFF) << 8)
829 | (prim_field_data
[off
] & 0xFF));
832 public byte get (String name
, byte defvalue
)
833 throws IOException
, IllegalArgumentException
835 ObjectStreamField field
= getField (name
, Byte
.TYPE
);
840 return prim_field_data
[field
.getOffset ()];
843 public short get (String name
, short defvalue
)
844 throws IOException
, IllegalArgumentException
846 ObjectStreamField field
= getField (name
, Short
.TYPE
);
851 int off
= field
.getOffset ();
853 return (short)(((prim_field_data
[off
++] & 0xFF) << 8)
854 | (prim_field_data
[off
] & 0xFF));
857 public int get (String name
, int defvalue
)
858 throws IOException
, IllegalArgumentException
860 ObjectStreamField field
= getField (name
, Integer
.TYPE
);
865 int off
= field
.getOffset ();
867 return ((prim_field_data
[off
++] & 0xFF) << 24)
868 | ((prim_field_data
[off
++] & 0xFF) << 16)
869 | ((prim_field_data
[off
++] & 0xFF) << 8)
870 | (prim_field_data
[off
] & 0xFF);
873 public long get (String name
, long defvalue
)
874 throws IOException
, IllegalArgumentException
876 ObjectStreamField field
= getField (name
, Long
.TYPE
);
881 int off
= field
.getOffset ();
883 return (long)(((prim_field_data
[off
++] & 0xFF) << 56)
884 | ((prim_field_data
[off
++] & 0xFF) << 48)
885 | ((prim_field_data
[off
++] & 0xFF) << 40)
886 | ((prim_field_data
[off
++] & 0xFF) << 32)
887 | ((prim_field_data
[off
++] & 0xFF) << 24)
888 | ((prim_field_data
[off
++] & 0xFF) << 16)
889 | ((prim_field_data
[off
++] & 0xFF) << 8)
890 | (prim_field_data
[off
] & 0xFF));
893 public float get (String name
, float defvalue
)
894 throws IOException
, IllegalArgumentException
896 ObjectStreamField field
= getField (name
, Float
.TYPE
);
901 int off
= field
.getOffset ();
903 return Float
.intBitsToFloat (((prim_field_data
[off
++] & 0xFF) << 24)
904 | ((prim_field_data
[off
++] & 0xFF) << 16)
905 | ((prim_field_data
[off
++] & 0xFF) << 8)
906 | (prim_field_data
[off
] & 0xFF));
909 public double get (String name
, double defvalue
)
910 throws IOException
, IllegalArgumentException
912 ObjectStreamField field
= getField (name
, Double
.TYPE
);
917 int off
= field
.getOffset ();
919 return Double
.longBitsToDouble (
920 (long)(((prim_field_data
[off
++] & 0xFF) << 56)
921 | ((prim_field_data
[off
++] & 0xFF) << 48)
922 | ((prim_field_data
[off
++] & 0xFF) << 40)
923 | ((prim_field_data
[off
++] & 0xFF) << 32)
924 | ((prim_field_data
[off
++] & 0xFF) << 24)
925 | ((prim_field_data
[off
++] & 0xFF) << 16)
926 | ((prim_field_data
[off
++] & 0xFF) << 8)
927 | (prim_field_data
[off
] & 0xFF)));
930 public Object
get (String name
, Object defvalue
)
931 throws IOException
, IllegalArgumentException
933 ObjectStreamField field
=
934 getField (name
, defvalue
== null ?
null : defvalue
.getClass ());
939 return objs
[field
.getOffset ()];
942 private ObjectStreamField
getField (String name
, Class type
)
943 throws IllegalArgumentException
945 ObjectStreamField field
= clazz
.getField (name
);
950 Class field_type
= field
.getType ();
952 if (type
== field_type
||
953 (type
== null && ! field_type
.isPrimitive ()))
956 throw new IllegalArgumentException ("Field requested is of type "
957 + field_type
.getName ()
958 + ", but requested type was "
960 "Object" : type
.getName ()));
968 Protected constructor that allows subclasses to override
969 deserialization. This constructor should be called by subclasses
970 that wish to override <code>readObject (Object)</code>. This
971 method does a security check <i>NOTE: currently not
972 implemented</i>, then sets a flag that informs
973 <code>readObject (Object)</code> to call the subclasses
974 <code>readObjectOverride (Object)</code> method.
976 @see readObjectOverride (Object)
978 protected ObjectInputStream ()
979 throws IOException
, SecurityException
981 SecurityManager sec_man
= System
.getSecurityManager ();
983 sec_man
.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION
);
984 this.useSubclassMethod
= true;
989 This method allows subclasses to override the default
990 de serialization mechanism provided by
991 <code>ObjectInputStream</code>. To make this method be used for
992 writing objects, subclasses must invoke the 0-argument
993 constructor on this class from there constructor.
995 @see ObjectInputStream ()
997 protected Object
readObjectOverride ()
998 throws ClassNotFoundException
, IOException
, OptionalDataException
1000 throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
1004 // assigns the next availible handle to OBJ
1005 private int assignNewHandle (Object obj
)
1007 this.objectLookupTable
.put (new Integer (this.nextOID
),
1008 new ObjectIdentityWrapper (obj
));
1012 // DEBUG ("Assigning handle " + this.nextOID);
1013 // DEBUGln (" to " + obj);
1015 // catch (Throwable t) {}
1017 return this.nextOID
++;
1021 private Object
processResolution (Object obj
, int handle
)
1024 if (obj
instanceof Serializable
)
1029 Class classArgs
[] = {};
1030 m
= obj
.getClass ().getDeclaredMethod ("readResolve", classArgs
);
1031 // m can't be null by definition since an exception would
1032 // have been thrown so a check for null is not needed.
1033 obj
= m
.invoke (obj
, new Object
[] {});
1035 catch (NoSuchMethodException ignore
)
1038 catch (IllegalAccessException ignore
)
1041 catch (InvocationTargetException ignore
)
1046 if (this.resolveEnabled
)
1047 obj
= resolveObject (obj
);
1049 this.objectLookupTable
.put (new Integer (handle
),
1050 new ObjectIdentityWrapper (obj
));
1056 private void clearHandles ()
1058 this.objectLookupTable
.clear ();
1059 this.nextOID
= baseWireHandle
;
1063 private void readNextBlock () throws IOException
1065 // DEBUGln ("In readNextBlock ");
1066 readNextBlock (this.realInputStream
.readByte ());
1070 private void readNextBlock (byte marker
) throws IOException
1072 if (marker
== TC_BLOCKDATA
)
1074 dumpElement ("BLOCK DATA SIZE=");
1075 this.blockDataBytes
= this.realInputStream
.readUnsignedByte ();
1076 dumpElementln (Integer
.toString(this.blockDataBytes
));
1078 else if (marker
== TC_BLOCKDATALONG
)
1080 dumpElement ("BLOCK DATA LONG SIZE=");
1081 this.blockDataBytes
= this.realInputStream
.readInt ();
1082 dumpElementln (Integer
.toString(this.blockDataBytes
));
1086 throw new EOFException ("Attempt to read primitive data, but no data block is active.");
1089 if (this.blockData
.length
< this.blockDataBytes
)
1090 this.blockData
= new byte[this.blockDataBytes
];
1092 this.realInputStream
.readFully (this.blockData
, 0, this.blockDataBytes
);
1093 this.blockDataPosition
= 0;
1097 private void readArrayElements (Object array
, Class clazz
)
1098 throws ClassNotFoundException
, IOException
1100 if (clazz
.isPrimitive ())
1102 if (clazz
== Boolean
.TYPE
)
1104 boolean[] cast_array
= (boolean[])array
;
1105 for (int i
=0; i
< cast_array
.length
; i
++)
1106 cast_array
[i
] = this.realInputStream
.readBoolean ();
1109 if (clazz
== Byte
.TYPE
)
1111 byte[] cast_array
= (byte[])array
;
1112 for (int i
=0; i
< cast_array
.length
; i
++)
1113 cast_array
[i
] = this.realInputStream
.readByte ();
1116 if (clazz
== Character
.TYPE
)
1118 char[] cast_array
= (char[])array
;
1119 for (int i
=0; i
< cast_array
.length
; i
++)
1120 cast_array
[i
] = this.realInputStream
.readChar ();
1123 if (clazz
== Double
.TYPE
)
1125 double[] cast_array
= (double[])array
;
1126 for (int i
=0; i
< cast_array
.length
; i
++)
1127 cast_array
[i
] = this.realInputStream
.readDouble ();
1130 if (clazz
== Float
.TYPE
)
1132 float[] cast_array
= (float[])array
;
1133 for (int i
=0; i
< cast_array
.length
; i
++)
1134 cast_array
[i
] = this.realInputStream
.readFloat ();
1137 if (clazz
== Integer
.TYPE
)
1139 int[] cast_array
= (int[])array
;
1140 for (int i
=0; i
< cast_array
.length
; i
++)
1141 cast_array
[i
] = this.realInputStream
.readInt ();
1144 if (clazz
== Long
.TYPE
)
1146 long[] cast_array
= (long[])array
;
1147 for (int i
=0; i
< cast_array
.length
; i
++)
1148 cast_array
[i
] = this.realInputStream
.readLong ();
1151 if (clazz
== Short
.TYPE
)
1153 short[] cast_array
= (short[])array
;
1154 for (int i
=0; i
< cast_array
.length
; i
++)
1155 cast_array
[i
] = this.realInputStream
.readShort ();
1161 Object
[] cast_array
= (Object
[])array
;
1162 for (int i
=0; i
< cast_array
.length
; i
++)
1163 cast_array
[i
] = readObject ();
1168 private void readFields (Object obj
, ObjectStreamField
[] stream_fields
,
1169 boolean call_read_method
,
1170 ObjectStreamClass stream_osc
)
1171 throws ClassNotFoundException
, IOException
1173 // DEBUGln ("In readFields");
1174 if (call_read_method
)
1176 // DEBUGln (" call_read_method is true");
1177 fieldsAlreadyRead
= false;
1178 setBlockDataMode (true);
1179 callReadMethod (obj
, stream_osc
.forClass ());
1180 setBlockDataMode (false);
1184 ObjectStreamField
[] real_fields
=
1185 ObjectStreamClass
.lookup (stream_osc
.forClass ()).fields
;
1187 boolean default_initialize
, set_value
;
1188 String field_name
= null;
1190 ObjectStreamField stream_field
= null;
1191 ObjectStreamField real_field
= null;
1195 while (stream_idx
< stream_fields
.length
1196 && real_idx
< real_fields
.length
)
1198 default_initialize
= false;
1201 if (stream_idx
== stream_fields
.length
)
1202 default_initialize
= true;
1205 stream_field
= stream_fields
[stream_idx
];
1206 type
= stream_field
.getType ();
1209 if (real_idx
== real_fields
.length
)
1213 real_field
= real_fields
[real_idx
];
1214 type
= real_field
.getType ();
1215 field_name
= real_field
.getName ();
1218 if (set_value
&& !default_initialize
)
1221 real_field
.compareTo (stream_field
);
1225 default_initialize
= true;
1228 else if (comp_val
> 0)
1240 if (type
== Boolean
.TYPE
)
1243 default_initialize ?
false : this.realInputStream
.readBoolean ();
1244 if (!default_initialize
&& set_value
)
1245 dumpElementln (" " + field_name
+ ": " + value
);
1247 setBooleanField (obj
, field_name
, value
);
1249 else if (type
== Byte
.TYPE
)
1252 default_initialize ?
0 : this.realInputStream
.readByte ();
1253 if (!default_initialize
&& set_value
)
1254 dumpElementln (" " + field_name
+ ": " + value
);
1256 setByteField (obj
, field_name
, value
);
1258 else if (type
== Character
.TYPE
)
1261 default_initialize ?
(char)0 : this.realInputStream
.readChar ();
1262 if (!default_initialize
&& set_value
)
1263 dumpElementln (" " + field_name
+ ": " + value
);
1265 setCharField (obj
, field_name
, value
);
1267 else if (type
== Double
.TYPE
)
1270 default_initialize ?
0 : this.realInputStream
.readDouble ();
1271 if (!default_initialize
&& set_value
)
1272 dumpElementln (" " + field_name
+ ": " + value
);
1274 setDoubleField (obj
, field_name
, value
);
1276 else if (type
== Float
.TYPE
)
1279 default_initialize ?
0 : this.realInputStream
.readFloat ();
1280 if (!default_initialize
&& set_value
)
1281 dumpElementln (" " + field_name
+ ": " + value
);
1283 setFloatField (obj
, field_name
, value
);
1285 else if (type
== Integer
.TYPE
)
1288 default_initialize ?
0 : this.realInputStream
.readInt ();
1289 if (!default_initialize
&& set_value
)
1290 dumpElementln (" " + field_name
+ ": " + value
);
1292 setIntField (obj
, field_name
, value
);
1294 else if (type
== Long
.TYPE
)
1297 default_initialize ?
0 : this.realInputStream
.readLong ();
1298 if (!default_initialize
&& set_value
)
1299 dumpElementln (" " + field_name
+ ": " + value
);
1301 setLongField (obj
, field_name
, value
);
1303 else if (type
== Short
.TYPE
)
1306 default_initialize ?
(short)0 : this.realInputStream
.readShort ();
1307 if (!default_initialize
&& set_value
)
1308 dumpElementln (" " + field_name
+ ": " + value
);
1310 setShortField (obj
, field_name
, value
);
1315 default_initialize ?
null : readObject ();
1317 setObjectField (obj
, field_name
,
1318 real_field
.getTypeString (), value
);
1324 // Toggles writing primitive data to block-data buffer.
1325 private void setBlockDataMode (boolean on
)
1327 // DEBUGln ("Setting block data mode to " + on);
1329 this.readDataFromBlock
= on
;
1332 this.dataInputStream
= this.blockDataInput
;
1334 this.dataInputStream
= this.realInputStream
;
1338 // returns a new instance of REAL_CLASS that has been constructed
1339 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1340 private Object
newObject (Class real_class
, Class constructor_class
)
1344 Object obj
= allocateObject (real_class
);
1345 callConstructor (constructor_class
, obj
);
1348 catch (InstantiationException e
)
1355 // runs all registered ObjectInputValidations in prioritized order
1357 private void invokeValidators () throws InvalidObjectException
1359 Object
[] validators
= new Object
[this.validators
.size ()];
1360 this.validators
.copyInto (validators
);
1361 Arrays
.sort (validators
);
1365 for (int i
=0; i
< validators
.length
; i
++)
1366 ((ObjectInputValidation
)validators
[i
]).validateObject ();
1370 this.validators
.removeAllElements ();
1375 // this native method is used to get access to the protected method
1376 // of the same name in SecurityManger
1377 private static ClassLoader
currentClassLoader (SecurityManager sm
)
1379 // FIXME: This is too simple.
1380 return ClassLoader
.getSystemClassLoader ();
1383 private static native Field
getField (Class klass
, String name
)
1384 throws java
.lang
.NoSuchFieldException
;
1386 private static native Method
getMethod (Class klass
, String name
, Class args
[])
1387 throws java
.lang
.NoSuchMethodException
;
1389 private void callReadMethod (Object obj
, Class klass
) throws IOException
1393 Class classArgs
[] = {ObjectInputStream
.class};
1394 Method m
= getMethod (klass
, "readObject", classArgs
);
1397 Object args
[] = {this};
1398 m
.invoke (obj
, args
);
1400 catch (InvocationTargetException x
)
1402 /* Rethrow if possible. */
1403 Throwable exception
= x
.getTargetException();
1404 if (exception
instanceof RuntimeException
)
1405 throw (RuntimeException
) exception
;
1406 if (exception
instanceof IOException
)
1407 throw (IOException
) exception
;
1409 throw new IOException ("Exception thrown from readObject() on " +
1410 klass
+ ": " + exception
.getClass().getName());
1414 throw new IOException ("Failure invoking readObject() on " +
1415 klass
+ ": " + x
.getClass().getName());
1419 private native Object
allocateObject (Class clazz
)
1420 throws InstantiationException
;
1422 private native void callConstructor (Class clazz
, Object obj
);
1424 private void setBooleanField (Object obj
, String field_name
,
1429 Class klass
= obj
.getClass ();
1430 Field f
= getField (klass
, field_name
);
1431 f
.setAccessible(true);
1432 f
.setBoolean (obj
, val
);
1439 private void setByteField (Object obj
, String field_name
,
1444 Class klass
= obj
.getClass ();
1445 Field f
= getField (klass
, field_name
);
1446 f
.setAccessible(true);
1447 f
.setByte (obj
, val
);
1454 private void setCharField (Object obj
, String field_name
,
1459 Class klass
= obj
.getClass ();
1460 Field f
= getField (klass
, field_name
);
1461 f
.setAccessible(true);
1462 f
.setChar (obj
, val
);
1469 private void setDoubleField (Object obj
, String field_name
,
1474 Class klass
= obj
.getClass ();
1475 Field f
= getField (klass
, field_name
);
1476 f
.setAccessible(true);
1477 f
.setDouble (obj
, val
);
1484 private void setFloatField (Object obj
, String field_name
,
1489 Class klass
= obj
.getClass ();
1490 Field f
= getField (klass
, field_name
);
1491 f
.setAccessible(true);
1492 f
.setFloat (obj
, val
);
1499 private void setIntField (Object obj
, String field_name
,
1504 Class klass
= obj
.getClass ();
1505 Field f
= getField (klass
, field_name
);
1506 f
.setAccessible(true);
1507 f
.setInt (obj
, val
);
1515 private void setLongField (Object obj
, String field_name
,
1520 Class klass
= obj
.getClass ();
1521 Field f
= getField (klass
, field_name
);
1522 f
.setAccessible(true);
1523 f
.setLong (obj
, val
);
1531 private void setShortField (Object obj
, String field_name
,
1536 Class klass
= obj
.getClass ();
1537 Field f
= getField (klass
, field_name
);
1538 f
.setAccessible(true);
1539 f
.setShort (obj
, val
);
1547 private void setObjectField (Object obj
, String field_name
, String type_code
,
1552 Class klass
= obj
.getClass ();
1553 Field f
= getField (klass
, field_name
);
1554 f
.setAccessible(true);
1555 // FIXME: We should check the type_code here
1563 private static final int BUFFER_SIZE
= 1024;
1564 private static final Class
[] readObjectParams
= { ObjectInputStream
.class };
1566 private DataInputStream realInputStream
;
1567 private DataInputStream dataInputStream
;
1568 private DataInputStream blockDataInput
;
1569 private int blockDataPosition
;
1570 private int blockDataBytes
;
1571 private byte[] blockData
;
1572 private boolean useSubclassMethod
;
1573 private int nextOID
;
1574 private boolean resolveEnabled
;
1575 private Hashtable objectLookupTable
;
1576 private Object currentObject
;
1577 private ObjectStreamClass currentObjectStreamClass
;
1578 private boolean readDataFromBlock
;
1579 private boolean isDeserializing
;
1580 private boolean fieldsAlreadyRead
;
1581 private Vector validators
;
1583 private static boolean dump
;
1585 private void dumpElement (String msg
)
1587 if (Configuration
.DEBUG
&& dump
)
1588 System
.out
.print(msg
);
1591 private void dumpElementln (String msg
)
1593 if (Configuration
.DEBUG
&& dump
)
1594 System
.out
.println(msg
);
1599 // used to keep a prioritized list of object validators
1600 class ValidatorAndPriority
implements Comparable
1603 ObjectInputValidation validator
;
1605 ValidatorAndPriority (ObjectInputValidation validator
, int priority
)
1607 this.priority
= priority
;
1608 this.validator
= validator
;
1611 public int compareTo (Object o
)
1613 ValidatorAndPriority vap
= (ValidatorAndPriority
)o
;
1614 return this.priority
- vap
.priority
;