FSF GCC merge 02/23/03
[official-gcc.git] / libjava / java / io / ObjectInputStream.java
blob08ce401fad822bc0337545aae9012376ad1d23bf
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)
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 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
61 /**
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
65 and stream version).
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(""))
83 dump = true;
84 System.out.println ("Serialization debugging enabled");
86 else if (dump == true && (val == null || val.equals("")))
88 dump = false;
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);
104 readStreamHeader ();
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
115 an undefined state.
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;
130 Object ret_val;
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) + " ");
141 switch (marker)
143 case TC_BLOCKDATA:
144 case TC_BLOCKDATALONG:
145 if (marker == TC_BLOCKDATALONG)
146 dumpElementln ("BLOCKDATALONG");
147 else
148 dumpElementln ("BLOCKDATA");
149 readNextBlock (marker);
150 throw new StreamCorruptedException ("Unexpected blockData");
152 case TC_NULL:
153 dumpElementln ("NULL");
154 ret_val = null;
155 break;
157 case TC_REFERENCE:
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;
164 break;
167 case TC_CLASS:
169 dumpElementln ("CLASS");
170 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
171 Class clazz = osc.forClass ();
172 assignNewHandle (clazz);
173 ret_val = clazz;
174 break;
177 case TC_CLASSDESC:
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,
191 flags, fields);
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);
201 String class_name;
203 if (type_code == 'L' || type_code == '[')
204 class_name = (String)readObject ();
205 else
206 class_name = String.valueOf (type_code);
208 fields[i] =
209 new ObjectStreamField (field_name,
210 TypeSignature.getClassForEncoding
211 (class_name));
214 Class cl = resolveClass (osc);
215 osc.setClass (cl);
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 ());
223 ret_val = osc;
224 break;
227 case TC_STRING:
229 dumpElement ("STRING=");
230 String s = this.realInputStream.readUTF ();
231 dumpElementln (s);
232 ret_val = processResolution (s, assignNewHandle (s));
233 break;
236 case TC_ARRAY:
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);
250 break;
253 case TC_OBJECT:
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);
299 break;
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);
312 Object obj = null;
313 obj = newObject (clazz, first_nonserial);
315 if (obj == null)
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);
326 boolean has_read;
327 for (int i=0; i < hierarchy.length; i++)
329 this.currentObjectStreamClass = hierarchy[i];
331 dumpElementln ("Reading fields of "
332 + this.currentObjectStreamClass.getName ());
334 has_read = true;
338 this.currentObjectStreamClass.forClass ().
339 getDeclaredMethod ("readObject", readObjectParams);
341 catch (NoSuchMethodException e)
343 has_read = false;
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);
353 if (has_read)
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);
378 break;
381 case TC_RESET:
382 dumpElementln ("RESET");
383 clearHandles ();
384 ret_val = readObject ();
385 break;
387 case TC_EXCEPTION:
389 dumpElement ("EXCEPTION=");
390 Exception e = (Exception)readObject ();
391 dumpElementln (e.toString());
392 clearHandles ();
393 throw new WriteAbortedException ("Exception thrown during writing of stream", e);
396 default:
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)
407 invokeValidators ();
410 return ret_val;
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>
420 method.
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>
428 method.
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
457 called first.
459 @see java.io.ObjectInputValidation
461 @exception InvalidObjectException <code>validator</code> is
462 <code>null</code>
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,
469 int priority)
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,
479 priority));
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
527 return obj;
531 protected Class resolveProxyClass (String[] intfs)
532 throws IOException, ClassNotFoundException
534 SecurityManager sm = System.getSecurityManager ();
536 if (sm == null)
537 sm = new SecurityManager () {};
539 ClassLoader cl = currentClassLoader (sm);
541 Class[] clss = new Class[intfs.length];
542 if(cl == null){
543 for (int i = 0; i < intfs.length; i++)
544 clss[i] = Class.forName(intfs[i]);
545 cl = ClassLoader.getSystemClassLoader();
547 else
548 for (int i = 0; i < intfs.length; i++)
549 clss[i] = cl.loadClass(intfs[i]);
550 try {
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
568 if (enable)
570 SecurityManager sm = System.getSecurityManager ();
571 if (sm != null)
572 sm.checkPermission (new SerializablePermission ("enableSubtitution"));
575 boolean old_val = this.resolveEnabled;
576 this.resolveEnabled = enable;
577 return old_val;
582 Reads stream magic and stream version information from the
583 underlying stream.
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)
608 readNextBlock ();
609 return (this.blockData[this.blockDataPosition++] & 0xff);
611 else
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)
620 readNextBlock ();
622 System.arraycopy (this.blockData, this.blockDataPosition,
623 data, offset, length);
624 blockDataPosition += length;
626 return length;
628 else
629 return this.realInputStream.read (data, offset, length);
632 public int available () throws IOException
634 if (this.readDataFromBlock)
636 if (this.blockDataPosition >= this.blockDataBytes)
637 readNextBlock ();
639 return this.blockDataBytes - this.blockDataPosition;
641 else
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)
706 throws IOException
708 this.dataInputStream.readFully (data, offset, size);
711 public int skipBytes (int len) throws IOException
713 return this.dataInputStream.skipBytes (len);
717 @deprecated
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 ()
798 return clazz;
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);
812 if (field == null)
813 return defvalue;
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);
823 if (field == null)
824 return defvalue;
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);
837 if (field == null)
838 return defvalue;
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);
848 if (field == null)
849 return defvalue;
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);
862 if (field == null)
863 return defvalue;
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);
878 if (field == null)
879 return defvalue;
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);
898 if (field == null)
899 return defvalue;
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);
914 if (field == null)
915 return defvalue;
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 ());
936 if (field == null)
937 return defvalue;
939 return objs[field.getOffset ()];
942 private ObjectStreamField getField (String name, Class type)
943 throws IllegalArgumentException
945 ObjectStreamField field = clazz.getField (name);
947 if (field == null)
948 return null;
950 Class field_type = field.getType ();
952 if (type == field_type ||
953 (type == null && ! field_type.isPrimitive ()))
954 return field;
956 throw new IllegalArgumentException ("Field requested is of type "
957 + field_type.getName ()
958 + ", but requested type was "
959 + (type == null ?
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 ();
982 if (sec_man != null)
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));
1010 // try
1011 // {
1012 // DEBUG ("Assigning handle " + this.nextOID);
1013 // DEBUGln (" to " + obj);
1014 // }
1015 // catch (Throwable t) {}
1017 return this.nextOID++;
1021 private Object processResolution (Object obj, int handle)
1022 throws IOException
1024 if (obj instanceof Serializable)
1026 Method m = null;
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));
1052 return 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));
1084 else
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 ();
1107 return;
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 ();
1114 return;
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 ();
1121 return;
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 ();
1128 return;
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 ();
1135 return;
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 ();
1142 return;
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 ();
1149 return;
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 ();
1156 return;
1159 else
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);
1181 return;
1184 ObjectStreamField[] real_fields =
1185 ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
1187 boolean default_initialize, set_value;
1188 String field_name = null;
1189 Class type = null;
1190 ObjectStreamField stream_field = null;
1191 ObjectStreamField real_field = null;
1192 int stream_idx = 0;
1193 int real_idx = 0;
1195 while (stream_idx < stream_fields.length
1196 && real_idx < real_fields.length)
1198 default_initialize = false;
1199 set_value = true;
1201 if (stream_idx == stream_fields.length)
1202 default_initialize = true;
1203 else
1205 stream_field = stream_fields[stream_idx];
1206 type = stream_field.getType ();
1209 if (real_idx == real_fields.length)
1210 set_value = false;
1211 else
1213 real_field = real_fields[real_idx];
1214 type = real_field.getType ();
1215 field_name = real_field.getName ();
1218 if (set_value && !default_initialize)
1220 int comp_val =
1221 real_field.compareTo (stream_field);
1223 if (comp_val < 0)
1225 default_initialize = true;
1226 real_idx++;
1228 else if (comp_val > 0)
1230 set_value = false;
1231 stream_idx++;
1233 else
1235 real_idx++;
1236 stream_idx++;
1240 if (type == Boolean.TYPE)
1242 boolean value =
1243 default_initialize ? false : this.realInputStream.readBoolean ();
1244 if (!default_initialize && set_value)
1245 dumpElementln (" " + field_name + ": " + value);
1246 if (set_value)
1247 setBooleanField (obj, field_name, value);
1249 else if (type == Byte.TYPE)
1251 byte value =
1252 default_initialize ? 0 : this.realInputStream.readByte ();
1253 if (!default_initialize && set_value)
1254 dumpElementln (" " + field_name + ": " + value);
1255 if (set_value)
1256 setByteField (obj, field_name, value);
1258 else if (type == Character.TYPE)
1260 char value =
1261 default_initialize ? (char)0 : this.realInputStream.readChar ();
1262 if (!default_initialize && set_value)
1263 dumpElementln (" " + field_name + ": " + value);
1264 if (set_value)
1265 setCharField (obj, field_name, value);
1267 else if (type == Double.TYPE)
1269 double value =
1270 default_initialize ? 0 : this.realInputStream.readDouble ();
1271 if (!default_initialize && set_value)
1272 dumpElementln (" " + field_name + ": " + value);
1273 if (set_value)
1274 setDoubleField (obj, field_name, value);
1276 else if (type == Float.TYPE)
1278 float value =
1279 default_initialize ? 0 : this.realInputStream.readFloat ();
1280 if (!default_initialize && set_value)
1281 dumpElementln (" " + field_name + ": " + value);
1282 if (set_value)
1283 setFloatField (obj, field_name, value);
1285 else if (type == Integer.TYPE)
1287 int value =
1288 default_initialize ? 0 : this.realInputStream.readInt ();
1289 if (!default_initialize && set_value)
1290 dumpElementln (" " + field_name + ": " + value);
1291 if (set_value)
1292 setIntField (obj, field_name, value);
1294 else if (type == Long.TYPE)
1296 long value =
1297 default_initialize ? 0 : this.realInputStream.readLong ();
1298 if (!default_initialize && set_value)
1299 dumpElementln (" " + field_name + ": " + value);
1300 if (set_value)
1301 setLongField (obj, field_name, value);
1303 else if (type == Short.TYPE)
1305 short value =
1306 default_initialize ? (short)0 : this.realInputStream.readShort ();
1307 if (!default_initialize && set_value)
1308 dumpElementln (" " + field_name + ": " + value);
1309 if (set_value)
1310 setShortField (obj, field_name, value);
1312 else
1314 Object value =
1315 default_initialize ? null : readObject ();
1316 if (set_value)
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;
1331 if (on)
1332 this.dataInputStream = this.blockDataInput;
1333 else
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);
1346 return obj;
1348 catch (InstantiationException e)
1350 return null;
1355 // runs all registered ObjectInputValidations in prioritized order
1356 // on OBJ
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 ();
1368 finally
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);
1395 if (m == null)
1396 return;
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());
1412 catch (Exception x)
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,
1425 boolean val)
1429 Class klass = obj.getClass ();
1430 Field f = getField (klass, field_name);
1431 f.setAccessible(true);
1432 f.setBoolean (obj, val);
1434 catch (Exception _)
1439 private void setByteField (Object obj, String field_name,
1440 byte val)
1444 Class klass = obj.getClass ();
1445 Field f = getField (klass, field_name);
1446 f.setAccessible(true);
1447 f.setByte (obj, val);
1449 catch (Exception _)
1454 private void setCharField (Object obj, String field_name,
1455 char val)
1459 Class klass = obj.getClass ();
1460 Field f = getField (klass, field_name);
1461 f.setAccessible(true);
1462 f.setChar (obj, val);
1464 catch (Exception _)
1469 private void setDoubleField (Object obj, String field_name,
1470 double val)
1474 Class klass = obj.getClass ();
1475 Field f = getField (klass, field_name);
1476 f.setAccessible(true);
1477 f.setDouble (obj, val);
1479 catch (Exception _)
1484 private void setFloatField (Object obj, String field_name,
1485 float val)
1489 Class klass = obj.getClass ();
1490 Field f = getField (klass, field_name);
1491 f.setAccessible(true);
1492 f.setFloat (obj, val);
1494 catch (Exception _)
1499 private void setIntField (Object obj, String field_name,
1500 int val)
1504 Class klass = obj.getClass ();
1505 Field f = getField (klass, field_name);
1506 f.setAccessible(true);
1507 f.setInt (obj, val);
1509 catch (Exception _)
1515 private void setLongField (Object obj, String field_name,
1516 long val)
1520 Class klass = obj.getClass ();
1521 Field f = getField (klass, field_name);
1522 f.setAccessible(true);
1523 f.setLong (obj, val);
1525 catch (Exception _)
1531 private void setShortField (Object obj, String field_name,
1532 short val)
1536 Class klass = obj.getClass ();
1537 Field f = getField (klass, field_name);
1538 f.setAccessible(true);
1539 f.setShort (obj, val);
1541 catch (Exception _)
1547 private void setObjectField (Object obj, String field_name, String type_code,
1548 Object val)
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
1556 f.set (obj, val);
1558 catch (Exception _)
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
1602 int priority;
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;