* Makefile.am (nat_source_files): Remove
[official-gcc.git] / libjava / java / io / ObjectInputStream.java
blobf2b2df8ed58de9aab4277c1cff50fb1afef3b224
1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.io;
41 import java.lang.reflect.Array;
42 import java.lang.reflect.Modifier;
43 import java.lang.reflect.Proxy;
44 import java.util.Arrays;
45 import java.util.Hashtable;
46 import java.util.Vector;
48 import gnu.java.io.ObjectIdentityWrapper;
49 import gnu.java.lang.reflect.TypeSignature;
50 import java.lang.reflect.Field;
51 import java.lang.reflect.Method;
52 import java.lang.reflect.InvocationTargetException;
54 import gnu.classpath.Configuration;
56 public class ObjectInputStream extends InputStream
57 implements ObjectInput, ObjectStreamConstants
59 /**
60 Creates a new <code>ObjectInputStream</code> that will do all of
61 its reading from <code>in</code>. This method also checks
62 the stream by reading the header information (stream magic number
63 and stream version).
65 @exception IOException Reading stream header from underlying
66 stream cannot be completed.
68 @exception StreamCorruptedException An invalid stream magic
69 number or stream version was read from the stream.
71 @see readStreamHeader ()
73 public ObjectInputStream (InputStream in)
74 throws IOException, StreamCorruptedException
76 if (Configuration.DEBUG)
78 String val = System.getProperty("gcj.dumpobjects");
79 if (dump == false && val != null && !val.equals(""))
81 dump = true;
82 System.out.println ("Serialization debugging enabled");
84 else if (dump == true && (val == null || val.equals("")))
86 dump = false;
87 System.out.println ("Serialization debugging disabled");
91 this.resolveEnabled = false;
92 this.isDeserializing = false;
93 this.blockDataPosition = 0;
94 this.blockDataBytes = 0;
95 this.blockData = new byte[BUFFER_SIZE];
96 this.blockDataInput = new DataInputStream (this);
97 this.realInputStream = new DataInputStream (in);
98 this.nextOID = baseWireHandle;
99 this.objectLookupTable = new Hashtable ();
100 this.validators = new Vector ();
101 setBlockDataMode (true);
102 readStreamHeader ();
107 Returns the next deserialized object read from the underlying stream.
109 This method can be overriden by a class by implementing
110 <code>private void readObject (ObjectInputStream)</code>.
112 If an exception is thrown from this method, the stream is left in
113 an undefined state.
115 @exception ClassNotFoundException The class that an object being
116 read in belongs to cannot be found.
118 @exception IOException Exception from underlying
119 <code>InputStream</code>.
121 public final Object readObject () throws ClassNotFoundException, IOException
123 if (this.useSubclassMethod)
124 return readObjectOverride ();
126 boolean was_deserializing;
128 Object ret_val;
129 was_deserializing = this.isDeserializing;
131 boolean is_consumed = false;
132 boolean old_mode = setBlockDataMode (false);
134 this.isDeserializing = true;
136 byte marker = this.realInputStream.readByte ();
137 dumpElement ("MARKER: 0x" + Integer.toHexString(marker) + " ");
141 switch (marker)
143 case TC_ENDBLOCKDATA:
145 ret_val = null;
146 is_consumed = true;
147 break;
150 case TC_BLOCKDATA:
151 case TC_BLOCKDATALONG:
153 if (marker == TC_BLOCKDATALONG)
154 dumpElementln ("BLOCKDATALONG");
155 else
156 dumpElementln ("BLOCKDATA");
157 readNextBlock (marker);
158 throw new StreamCorruptedException ("Unexpected blockData");
161 case TC_NULL:
163 dumpElementln ("NULL");
164 ret_val = null;
165 break;
168 case TC_REFERENCE:
170 dumpElement ("REFERENCE ");
171 Integer oid = new Integer (this.realInputStream.readInt ());
172 dumpElementln (Integer.toHexString(oid.intValue()));
173 ret_val = ((ObjectIdentityWrapper)
174 this.objectLookupTable.get (oid)).object;
175 break;
178 case TC_CLASS:
180 dumpElementln ("CLASS");
181 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
182 Class clazz = osc.forClass ();
183 assignNewHandle (clazz);
184 ret_val = clazz;
185 break;
188 case TC_PROXYCLASSDESC:
190 dumpElementln ("PROXYCLASS");
191 int n_intf = this.realInputStream.readInt();
192 String[] intfs = new String[n_intf];
193 for (int i = 0; i < n_intf; i++)
195 intfs[i] = this.realInputStream.readUTF();
196 System.out.println(intfs[i]);
199 boolean oldmode = setBlockDataMode (true);
200 Class cl = resolveProxyClass(intfs);
201 setBlockDataMode(oldmode);
203 ObjectStreamClass osc = ObjectStreamClass.lookup(cl);
204 assignNewHandle (osc);
206 if (!is_consumed)
208 byte b = this.realInputStream.readByte ();
209 if (b != TC_ENDBLOCKDATA)
210 throw new IOException ("Data annotated to class was not consumed." + b);
212 else
213 is_consumed = false;
214 ObjectStreamClass superosc = (ObjectStreamClass)readObject ();
215 osc.setSuperclass (superosc);
216 ret_val = osc;
217 break;
220 case TC_CLASSDESC:
222 dumpElement ("CLASSDESC NAME=");
223 String name = this.realInputStream.readUTF ();
224 dumpElement (name + "; UID=");
225 long uid = this.realInputStream.readLong ();
226 dumpElement (Long.toHexString(uid) + "; FLAGS=");
227 byte flags = this.realInputStream.readByte ();
228 dumpElement (Integer.toHexString(flags) + "; FIELD COUNT=");
229 short field_count = this.realInputStream.readShort ();
230 dumpElementln (Short.toString(field_count));
231 ObjectStreamField[] fields = new ObjectStreamField[field_count];
233 ObjectStreamClass osc = new ObjectStreamClass (name, uid,
234 flags, fields);
235 assignNewHandle (osc);
237 for (int i=0; i < field_count; i++)
239 dumpElement (" TYPE CODE=");
240 char type_code = (char)this.realInputStream.readByte ();
241 dumpElement (type_code + "; FIELD NAME=");
242 String field_name = this.realInputStream.readUTF ();
243 dumpElementln (field_name);
244 String class_name;
246 if (type_code == 'L' || type_code == '[')
247 class_name = (String)readObject ();
248 else
249 class_name = String.valueOf (type_code);
251 // There're many cases you can't get java.lang.Class from
252 // typename if your context class loader can't load it,
253 // then use typename to construct the field
254 fields[i] =
255 new ObjectStreamField (field_name, class_name);
258 boolean oldmode = setBlockDataMode (true);
259 osc.setClass (resolveClass (osc));
260 setBlockDataMode (oldmode);
262 if (!is_consumed)
264 byte b = this.realInputStream.readByte ();
265 if (b != TC_ENDBLOCKDATA)
266 throw new IOException ("Data annotated to class was not consumed." + b);
268 else
269 is_consumed = false;
271 osc.setSuperclass ((ObjectStreamClass)readObject ());
272 ret_val = osc;
273 break;
276 case TC_STRING:
277 case TC_LONGSTRING:
279 dumpElement ("STRING=");
280 String s = this.realInputStream.readUTF ();
281 dumpElementln (s);
282 ret_val = processResolution (s, assignNewHandle (s));
283 break;
286 case TC_ARRAY:
288 dumpElementln ("ARRAY");
289 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
290 Class componentType = osc.forClass ().getComponentType ();
291 dumpElement ("ARRAY LENGTH=");
292 int length = this.realInputStream.readInt ();
293 dumpElementln (length + "; COMPONENT TYPE=" + componentType);
294 Object array = Array.newInstance (componentType, length);
295 int handle = assignNewHandle (array);
296 readArrayElements (array, componentType);
297 for (int i=0, len=Array.getLength(array); i < len; i++)
298 dumpElementln (" ELEMENT[" + i + "]=" + Array.get(array, i));
299 ret_val = processResolution (array, handle);
300 break;
303 case TC_OBJECT:
305 dumpElementln ("OBJECT");
306 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
307 Class clazz = osc.forClass ();
309 if (!Serializable.class.isAssignableFrom (clazz))
310 throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
312 if (Externalizable.class.isAssignableFrom (clazz))
314 Externalizable obj = null;
318 obj = (Externalizable)clazz.newInstance ();
320 catch (InstantiationException e)
322 throw new ClassNotFoundException ("Instance of " + clazz
323 + " could not be created");
325 catch (IllegalAccessException e)
327 throw new ClassNotFoundException ("Instance of " + clazz
328 + " could not be created because class or zero-argument constructor is not accessible");
330 catch (NoSuchMethodError e)
332 throw new ClassNotFoundException ("Instance of " + clazz
333 + " could not be created because zero-argument constructor is not defined");
336 int handle = assignNewHandle (obj);
338 boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
340 boolean oldmode = this.readDataFromBlock;
341 if (read_from_blocks)
342 setBlockDataMode (true);
344 obj.readExternal (this);
346 if (read_from_blocks)
347 setBlockDataMode (oldmode);
349 ret_val = processResolution (obj, handle);
350 break;
351 } // end if (Externalizable.class.isAssignableFrom (clazz))
353 // find the first non-serializable, non-abstract
354 // class in clazz's inheritance hierarchy
355 Class first_nonserial = clazz.getSuperclass ();
356 while (Serializable.class.isAssignableFrom (first_nonserial)
357 || Modifier.isAbstract (first_nonserial.getModifiers ()))
358 first_nonserial = first_nonserial.getSuperclass ();
360 // DEBUGln ("Using " + first_nonserial
361 // + " as starting point for constructing " + clazz);
363 Object obj = null;
364 obj = newObject (clazz, first_nonserial);
366 if (obj == null)
367 throw new ClassNotFoundException ("Instance of " + clazz +
368 " could not be created");
370 int handle = assignNewHandle (obj);
371 this.currentObject = obj;
372 ObjectStreamClass[] hierarchy =
373 ObjectStreamClass.getObjectStreamClasses (clazz);
375 // DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
377 boolean has_read;
378 for (int i=0; i < hierarchy.length; i++)
380 this.currentObjectStreamClass = hierarchy[i];
382 dumpElementln ("Reading fields of "
383 + this.currentObjectStreamClass.getName ());
385 has_read = true;
389 this.currentObjectStreamClass.forClass ().
390 getDeclaredMethod ("readObject", readObjectParams);
392 catch (NoSuchMethodException e)
394 has_read = false;
397 // XXX: should initialize fields in classes in the hierarchy
398 // that aren't in the stream
399 // should skip over classes in the stream that aren't in the
400 // real classes hierarchy
401 readFields (obj, this.currentObjectStreamClass.fields,
402 has_read, this.currentObjectStreamClass);
404 if (has_read)
406 dumpElement ("ENDBLOCKDATA? ");
409 // FIXME: XXX: This try block is to catch EOF which is
410 // thrown for some objects. That indicates a bug in the logic.
411 if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
412 throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
413 dumpElementln ("yes");
415 catch (EOFException e)
417 dumpElementln ("no, got EOFException");
419 catch (IOException e)
421 dumpElementln ("no, got IOException");
426 this.currentObject = null;
427 this.currentObjectStreamClass = null;
428 ret_val = processResolution (obj, handle);
429 break;
432 case TC_RESET:
433 dumpElementln ("RESET");
434 clearHandles ();
435 ret_val = readObject ();
436 break;
438 case TC_EXCEPTION:
440 dumpElement ("EXCEPTION=");
441 Exception e = (Exception)readObject ();
442 dumpElementln (e.toString());
443 clearHandles ();
444 throw new WriteAbortedException ("Exception thrown during writing of stream", e);
447 default:
448 throw new IOException ("Unknown marker on stream: " + marker);
452 finally
454 setBlockDataMode (old_mode);
456 this.isDeserializing = was_deserializing;
458 if (! was_deserializing)
460 if (validators.size () > 0)
461 invokeValidators ();
465 return ret_val;
470 Reads the current objects non-transient, non-static fields from
471 the current class from the underlying output stream.
473 This method is intended to be called from within a object's
474 <code>private void readObject (ObjectInputStream)</code>
475 method.
477 @exception ClassNotFoundException The class that an object being
478 read in belongs to cannot be found.
480 @exception NotActiveException This method was called from a
481 context other than from the current object's and current class's
482 <code>private void readObject (ObjectInputStream)</code>
483 method.
485 @exception IOException Exception from underlying
486 <code>OutputStream</code>.
488 public void defaultReadObject ()
489 throws ClassNotFoundException, IOException, NotActiveException
491 if (this.currentObject == null || this.currentObjectStreamClass == null)
492 throw new NotActiveException ("defaultReadObject called by non-active class and/or object");
494 if (fieldsAlreadyRead)
495 throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
497 boolean oldmode = setBlockDataMode(false);
498 readFields (this.currentObject,
499 this.currentObjectStreamClass.fields,
500 false, this.currentObjectStreamClass);
501 setBlockDataMode(oldmode);
503 fieldsAlreadyRead = true;
508 Registers a <code>ObjectInputValidation</code> to be carried out
509 on the object graph currently being deserialized before it is
510 returned to the original caller of <code>readObject ()</code>.
511 The order of validation for multiple
512 <code>ObjectInputValidation</code>s can be controled using
513 <code>priority</code>. Validators with higher priorities are
514 called first.
516 @see java.io.ObjectInputValidation
518 @exception InvalidObjectException <code>validator</code> is
519 <code>null</code>
521 @exception NotActiveException an attempt was made to add a
522 validator outside of the <code>readObject</code> method of the
523 object currently being deserialized
525 public void registerValidation (ObjectInputValidation validator,
526 int priority)
527 throws InvalidObjectException, NotActiveException
529 if (this.currentObject == null || this.currentObjectStreamClass == null)
530 throw new NotActiveException ("registerValidation called by non-active class and/or object");
532 if (validator == null)
533 throw new InvalidObjectException ("attempt to add a null ObjectInputValidation object");
535 this.validators.addElement (new ValidatorAndPriority (validator,
536 priority));
541 Called when a class is being deserialized. This is a hook to
542 allow subclasses to read in information written by the
543 <code>annotateClass (Class)</code> method of an
544 <code>ObjectOutputStream</code>.
546 This implementation looks up the active call stack for a
547 <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
548 it is used to load the class associated with <code>osc</code>,
549 otherwise, the default system <code>ClassLoader</code> is used.
551 @exception IOException Exception from underlying
552 <code>OutputStream</code>.
554 @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
556 protected Class resolveClass (ObjectStreamClass osc)
557 throws ClassNotFoundException, IOException
559 SecurityManager sm = System.getSecurityManager ();
560 if (sm == null)
561 sm = new SecurityManager () {};
563 // FIXME: currentClassLoader doesn't yet do anything useful. We need
564 // to call forName() with the classloader of the class which called
565 // readObject(). See SecurityManager.getClassContext().
566 ClassLoader cl = currentClassLoader (sm);
568 if (cl == null)
569 return Class.forName (osc.getName ());
570 else
571 return cl.loadClass (osc.getName ());
575 Allows subclasses to resolve objects that are read from the
576 stream with other objects to be returned in their place. This
577 method is called the first time each object is encountered.
579 This method must be enabled before it will be called in the
580 serialization process.
582 @exception IOException Exception from underlying
583 <code>OutputStream</code>.
585 @see enableResolveObject (boolean)
587 protected Object resolveObject (Object obj) throws IOException
589 return obj;
593 protected Class resolveProxyClass (String[] intfs)
594 throws IOException, ClassNotFoundException
596 SecurityManager sm = System.getSecurityManager ();
598 if (sm == null)
599 sm = new SecurityManager () {};
601 ClassLoader cl = currentClassLoader (sm);
603 Class[] clss = new Class[intfs.length];
604 if(cl == null){
605 for (int i = 0; i < intfs.length; i++)
606 clss[i] = Class.forName(intfs[i]);
607 cl = ClassLoader.getSystemClassLoader();
609 else
610 for (int i = 0; i < intfs.length; i++)
611 clss[i] = cl.loadClass(intfs[i]);
612 try {
613 return Proxy.getProxyClass(cl, clss);
614 } catch (IllegalArgumentException e) {
615 throw new ClassNotFoundException(null, e);
620 If <code>enable</code> is <code>true</code> and this object is
621 trusted, then <code>resolveObject (Object)</code> will be called
622 in subsequent calls to <code>readObject (Object)</code>.
623 Otherwise, <code>resolveObject (Object)</code> will not be called.
625 @exception SecurityException This class is not trusted.
627 protected boolean enableResolveObject (boolean enable)
628 throws SecurityException
630 if (enable)
632 SecurityManager sm = System.getSecurityManager ();
633 if (sm != null)
634 sm.checkPermission (new SerializablePermission ("enableSubtitution"));
637 boolean old_val = this.resolveEnabled;
638 this.resolveEnabled = enable;
639 return old_val;
644 Reads stream magic and stream version information from the
645 underlying stream.
647 @exception IOException Exception from underlying stream.
649 @exception StreamCorruptedException An invalid stream magic
650 number or stream version was read from the stream.
652 protected void readStreamHeader ()
653 throws IOException, StreamCorruptedException
655 dumpElement ("STREAM MAGIC ");
656 if (this.realInputStream.readShort () != STREAM_MAGIC)
657 throw new StreamCorruptedException ("Invalid stream magic number");
659 dumpElementln ("STREAM VERSION ");
660 if (this.realInputStream.readShort () != STREAM_VERSION)
661 throw new StreamCorruptedException ("Invalid stream version number");
665 public int read () throws IOException
667 if (this.readDataFromBlock)
669 if (this.blockDataPosition >= this.blockDataBytes)
670 readNextBlock ();
671 return (this.blockData[this.blockDataPosition++] & 0xff);
673 else
674 return this.realInputStream.read ();
677 public int read (byte[] data, int offset, int length) throws IOException
679 if (this.readDataFromBlock)
681 if (this.blockDataPosition + length > this.blockDataBytes)
683 int remain = this.blockDataBytes - this.blockDataPosition;
684 if (remain != 0)
686 System.arraycopy (this.blockData, this.blockDataPosition,
687 data, offset, remain);
688 offset += remain;
689 length -= remain;
691 readNextBlock ();
694 System.arraycopy (this.blockData, this.blockDataPosition,
695 data, offset, length);
696 blockDataPosition += length;
698 return length;
700 else
701 return this.realInputStream.read (data, offset, length);
704 public int available () throws IOException
706 if (this.readDataFromBlock)
708 if (this.blockDataPosition >= this.blockDataBytes)
709 readNextBlock ();
711 return this.blockDataBytes - this.blockDataPosition;
713 else
714 return this.realInputStream.available ();
717 public void close () throws IOException
719 this.realInputStream.close ();
722 public boolean readBoolean () throws IOException
724 return this.dataInputStream.readBoolean ();
727 public byte readByte () throws IOException
729 return this.dataInputStream.readByte ();
732 public int readUnsignedByte () throws IOException
734 return this.dataInputStream.readUnsignedByte ();
737 public short readShort () throws IOException
739 return this.dataInputStream.readShort ();
742 public int readUnsignedShort () throws IOException
744 return this.dataInputStream.readUnsignedShort ();
747 public char readChar () throws IOException
749 return this.dataInputStream.readChar ();
752 public int readInt () throws IOException
754 return this.dataInputStream.readInt ();
757 public long readLong () throws IOException
759 return this.dataInputStream.readLong ();
762 public float readFloat () throws IOException
764 return this.dataInputStream.readFloat ();
767 public double readDouble () throws IOException
769 return this.dataInputStream.readDouble ();
772 public void readFully (byte data[]) throws IOException
774 this.dataInputStream.readFully (data);
777 public void readFully (byte data[], int offset, int size)
778 throws IOException
780 this.dataInputStream.readFully (data, offset, size);
783 public int skipBytes (int len) throws IOException
785 return this.dataInputStream.skipBytes (len);
789 @deprecated
790 @see java.io.DataInputStream#readLine ()
792 public String readLine () throws IOException
794 return this.dataInputStream.readLine ();
797 public String readUTF () throws IOException
799 return this.dataInputStream.readUTF ();
804 This class allows a class to specify exactly which fields should
805 be read, and what values should be read for these fields.
807 XXX: finish up comments
809 public static abstract class GetField
811 public abstract ObjectStreamClass getObjectStreamClass ();
813 public abstract boolean defaulted (String name)
814 throws IOException, IllegalArgumentException;
816 public abstract boolean get (String name, boolean defvalue)
817 throws IOException, IllegalArgumentException;
819 public abstract char get (String name, char defvalue)
820 throws IOException, IllegalArgumentException;
822 public abstract byte get (String name, byte defvalue)
823 throws IOException, IllegalArgumentException;
825 public abstract short get (String name, short defvalue)
826 throws IOException, IllegalArgumentException;
828 public abstract int get (String name, int defvalue)
829 throws IOException, IllegalArgumentException;
831 public abstract long get (String name, long defvalue)
832 throws IOException, IllegalArgumentException;
834 public abstract float get (String name, float defvalue)
835 throws IOException, IllegalArgumentException;
837 public abstract double get (String name, double defvalue)
838 throws IOException, IllegalArgumentException;
840 public abstract Object get (String name, Object defvalue)
841 throws IOException, IllegalArgumentException;
844 public GetField readFields ()
845 throws IOException, ClassNotFoundException, NotActiveException
847 if (this.currentObject == null || this.currentObjectStreamClass == null)
848 throw new NotActiveException ("readFields called by non-active class and/or object");
850 if (fieldsAlreadyRead)
851 throw new NotActiveException ("readFields called but fields already read from stream (by defaultReadObject or readFields)");
853 final ObjectStreamClass clazz = this.currentObjectStreamClass;
854 final byte[] prim_field_data = new byte[clazz.primFieldSize];
855 final Object[] objs = new Object[clazz.objectFieldCount];
857 // Apparently Block data is not used with GetField as per
858 // empirical evidence against JDK 1.2. Also see Mauve test
859 // java.io.ObjectInputOutput.Test.GetPutField.
860 boolean oldmode = setBlockDataMode (false);
861 readFully (prim_field_data);
862 for (int i = 0; i < objs.length; ++ i)
863 objs[i] = readObject ();
864 setBlockDataMode (oldmode);
866 return new GetField ()
868 public ObjectStreamClass getObjectStreamClass ()
870 return clazz;
873 public boolean defaulted (String name)
874 throws IOException, IllegalArgumentException
876 return clazz.getField (name) == null;
879 public boolean get (String name, boolean defvalue)
880 throws IOException, IllegalArgumentException
882 ObjectStreamField field = getField (name, Boolean.TYPE);
884 if (field == null)
885 return defvalue;
887 return prim_field_data[field.getOffset ()] == 0 ? false : true;
890 public char get (String name, char defvalue)
891 throws IOException, IllegalArgumentException
893 ObjectStreamField field = getField (name, Character.TYPE);
895 if (field == null)
896 return defvalue;
898 int off = field.getOffset ();
900 return (char)(((prim_field_data[off++] & 0xFF) << 8)
901 | (prim_field_data[off] & 0xFF));
904 public byte get (String name, byte defvalue)
905 throws IOException, IllegalArgumentException
907 ObjectStreamField field = getField (name, Byte.TYPE);
909 if (field == null)
910 return defvalue;
912 return prim_field_data[field.getOffset ()];
915 public short get (String name, short defvalue)
916 throws IOException, IllegalArgumentException
918 ObjectStreamField field = getField (name, Short.TYPE);
920 if (field == null)
921 return defvalue;
923 int off = field.getOffset ();
925 return (short)(((prim_field_data[off++] & 0xFF) << 8)
926 | (prim_field_data[off] & 0xFF));
929 public int get (String name, int defvalue)
930 throws IOException, IllegalArgumentException
932 ObjectStreamField field = getField (name, Integer.TYPE);
934 if (field == null)
935 return defvalue;
937 int off = field.getOffset ();
939 return ((prim_field_data[off++] & 0xFF) << 24)
940 | ((prim_field_data[off++] & 0xFF) << 16)
941 | ((prim_field_data[off++] & 0xFF) << 8)
942 | (prim_field_data[off] & 0xFF);
945 public long get (String name, long defvalue)
946 throws IOException, IllegalArgumentException
948 ObjectStreamField field = getField (name, Long.TYPE);
950 if (field == null)
951 return defvalue;
953 int off = field.getOffset ();
955 return (long)(((prim_field_data[off++] & 0xFF) << 56)
956 | ((prim_field_data[off++] & 0xFF) << 48)
957 | ((prim_field_data[off++] & 0xFF) << 40)
958 | ((prim_field_data[off++] & 0xFF) << 32)
959 | ((prim_field_data[off++] & 0xFF) << 24)
960 | ((prim_field_data[off++] & 0xFF) << 16)
961 | ((prim_field_data[off++] & 0xFF) << 8)
962 | (prim_field_data[off] & 0xFF));
965 public float get (String name, float defvalue)
966 throws IOException, IllegalArgumentException
968 ObjectStreamField field = getField (name, Float.TYPE);
970 if (field == null)
971 return defvalue;
973 int off = field.getOffset ();
975 return Float.intBitsToFloat (((prim_field_data[off++] & 0xFF) << 24)
976 | ((prim_field_data[off++] & 0xFF) << 16)
977 | ((prim_field_data[off++] & 0xFF) << 8)
978 | (prim_field_data[off] & 0xFF));
981 public double get (String name, double defvalue)
982 throws IOException, IllegalArgumentException
984 ObjectStreamField field = getField (name, Double.TYPE);
986 if (field == null)
987 return defvalue;
989 int off = field.getOffset ();
991 return Double.longBitsToDouble (
992 (long)(((prim_field_data[off++] & 0xFF) << 56)
993 | ((prim_field_data[off++] & 0xFF) << 48)
994 | ((prim_field_data[off++] & 0xFF) << 40)
995 | ((prim_field_data[off++] & 0xFF) << 32)
996 | ((prim_field_data[off++] & 0xFF) << 24)
997 | ((prim_field_data[off++] & 0xFF) << 16)
998 | ((prim_field_data[off++] & 0xFF) << 8)
999 | (prim_field_data[off] & 0xFF)));
1002 public Object get (String name, Object defvalue)
1003 throws IOException, IllegalArgumentException
1005 ObjectStreamField field =
1006 getField (name, defvalue == null ? null : defvalue.getClass ());
1008 if (field == null)
1009 return defvalue;
1011 return objs[field.getOffset ()];
1014 private ObjectStreamField getField (String name, Class type)
1015 throws IllegalArgumentException
1017 ObjectStreamField field = clazz.getField (name);
1019 if (field == null)
1020 return null;
1022 Class field_type = field.getType ();
1024 if (type == field_type ||
1025 (type == null && ! field_type.isPrimitive ()))
1026 return field;
1028 throw new IllegalArgumentException ("Field requested is of type "
1029 + field_type.getName ()
1030 + ", but requested type was "
1031 + (type == null ?
1032 "Object" : type.getName ()));
1040 Protected constructor that allows subclasses to override
1041 deserialization. This constructor should be called by subclasses
1042 that wish to override <code>readObject (Object)</code>. This
1043 method does a security check <i>NOTE: currently not
1044 implemented</i>, then sets a flag that informs
1045 <code>readObject (Object)</code> to call the subclasses
1046 <code>readObjectOverride (Object)</code> method.
1048 @see readObjectOverride (Object)
1050 protected ObjectInputStream ()
1051 throws IOException, SecurityException
1053 SecurityManager sec_man = System.getSecurityManager ();
1054 if (sec_man != null)
1055 sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
1056 this.useSubclassMethod = true;
1061 This method allows subclasses to override the default
1062 de serialization mechanism provided by
1063 <code>ObjectInputStream</code>. To make this method be used for
1064 writing objects, subclasses must invoke the 0-argument
1065 constructor on this class from their constructor.
1067 @see ObjectInputStream ()
1069 protected Object readObjectOverride ()
1070 throws ClassNotFoundException, IOException, OptionalDataException
1072 throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
1076 // assigns the next availible handle to OBJ
1077 private int assignNewHandle (Object obj)
1079 this.objectLookupTable.put (new Integer (this.nextOID),
1080 new ObjectIdentityWrapper (obj));
1082 // try
1083 // {
1084 // DEBUG ("Assigning handle " + this.nextOID);
1085 // DEBUGln (" to " + obj);
1086 // }
1087 // catch (Throwable t) {}
1089 return this.nextOID++;
1093 private Object processResolution (Object obj, int handle)
1094 throws IOException
1096 if (obj instanceof Serializable)
1098 Method m = null;
1101 Class classArgs[] = {};
1102 m = obj.getClass ().getDeclaredMethod ("readResolve", classArgs);
1103 // m can't be null by definition since an exception would
1104 // have been thrown so a check for null is not needed.
1105 obj = m.invoke (obj, new Object[] {});
1107 catch (NoSuchMethodException ignore)
1110 catch (IllegalAccessException ignore)
1113 catch (InvocationTargetException ignore)
1118 if (this.resolveEnabled)
1119 obj = resolveObject (obj);
1121 this.objectLookupTable.put (new Integer (handle),
1122 new ObjectIdentityWrapper (obj));
1124 return obj;
1128 private void clearHandles ()
1130 this.objectLookupTable.clear ();
1131 this.nextOID = baseWireHandle;
1135 private void readNextBlock () throws IOException
1137 // DEBUGln ("In readNextBlock ");
1138 readNextBlock (this.realInputStream.readByte ());
1142 private void readNextBlock (byte marker) throws IOException
1144 if (marker == TC_BLOCKDATA)
1146 dumpElement ("BLOCK DATA SIZE=");
1147 this.blockDataBytes = this.realInputStream.readUnsignedByte ();
1148 dumpElementln (Integer.toString(this.blockDataBytes));
1150 else if (marker == TC_BLOCKDATALONG)
1152 dumpElement ("BLOCK DATA LONG SIZE=");
1153 this.blockDataBytes = this.realInputStream.readInt ();
1154 dumpElementln (Integer.toString(this.blockDataBytes));
1156 else
1158 throw new EOFException ("Attempt to read primitive data, but no data block is active.");
1161 if (this.blockData.length < this.blockDataBytes)
1162 this.blockData = new byte[this.blockDataBytes];
1164 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1165 this.blockDataPosition = 0;
1169 private void readArrayElements (Object array, Class clazz)
1170 throws ClassNotFoundException, IOException
1172 if (clazz.isPrimitive ())
1174 if (clazz == Boolean.TYPE)
1176 boolean[] cast_array = (boolean[])array;
1177 for (int i=0; i < cast_array.length; i++)
1178 cast_array[i] = this.realInputStream.readBoolean ();
1179 return;
1181 if (clazz == Byte.TYPE)
1183 byte[] cast_array = (byte[])array;
1184 for (int i=0; i < cast_array.length; i++)
1185 cast_array[i] = this.realInputStream.readByte ();
1186 return;
1188 if (clazz == Character.TYPE)
1190 char[] cast_array = (char[])array;
1191 for (int i=0; i < cast_array.length; i++)
1192 cast_array[i] = this.realInputStream.readChar ();
1193 return;
1195 if (clazz == Double.TYPE)
1197 double[] cast_array = (double[])array;
1198 for (int i=0; i < cast_array.length; i++)
1199 cast_array[i] = this.realInputStream.readDouble ();
1200 return;
1202 if (clazz == Float.TYPE)
1204 float[] cast_array = (float[])array;
1205 for (int i=0; i < cast_array.length; i++)
1206 cast_array[i] = this.realInputStream.readFloat ();
1207 return;
1209 if (clazz == Integer.TYPE)
1211 int[] cast_array = (int[])array;
1212 for (int i=0; i < cast_array.length; i++)
1213 cast_array[i] = this.realInputStream.readInt ();
1214 return;
1216 if (clazz == Long.TYPE)
1218 long[] cast_array = (long[])array;
1219 for (int i=0; i < cast_array.length; i++)
1220 cast_array[i] = this.realInputStream.readLong ();
1221 return;
1223 if (clazz == Short.TYPE)
1225 short[] cast_array = (short[])array;
1226 for (int i=0; i < cast_array.length; i++)
1227 cast_array[i] = this.realInputStream.readShort ();
1228 return;
1231 else
1233 Object[] cast_array = (Object[])array;
1234 for (int i=0; i < cast_array.length; i++)
1235 cast_array[i] = readObject ();
1240 private void readFields (Object obj, ObjectStreamField[] stream_fields,
1241 boolean call_read_method,
1242 ObjectStreamClass stream_osc)
1243 throws ClassNotFoundException, IOException
1245 // DEBUGln ("In readFields");
1246 if (call_read_method)
1248 // DEBUGln (" call_read_method is true");
1249 fieldsAlreadyRead = false;
1250 boolean oldmode = setBlockDataMode (true);
1251 callReadMethod (obj, stream_osc.forClass ());
1252 setBlockDataMode (oldmode);
1253 return;
1256 ObjectStreamField[] real_fields =
1257 ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
1259 boolean default_initialize, set_value;
1260 String field_name = null;
1261 Class type = null;
1262 ObjectStreamField stream_field = null;
1263 ObjectStreamField real_field = null;
1264 int stream_idx = 0;
1265 int real_idx = 0;
1267 while (stream_idx < stream_fields.length
1268 && real_idx < real_fields.length)
1270 default_initialize = false;
1271 set_value = true;
1273 if (stream_idx == stream_fields.length)
1274 default_initialize = true;
1275 else
1277 stream_field = stream_fields[stream_idx];
1278 type = stream_field.getType ();
1281 if (real_idx == real_fields.length)
1282 set_value = false;
1283 else
1285 real_field = real_fields[real_idx];
1286 type = real_field.getType ();
1287 field_name = real_field.getName ();
1290 if (set_value && !default_initialize)
1292 int comp_val =
1293 real_field.compareTo (stream_field);
1295 if (comp_val < 0)
1297 default_initialize = true;
1298 real_idx++;
1300 else if (comp_val > 0)
1302 set_value = false;
1303 stream_idx++;
1305 else
1307 real_idx++;
1308 stream_idx++;
1314 if (type == Boolean.TYPE)
1316 boolean value =
1317 default_initialize ? false : this.realInputStream.readBoolean ();
1318 if (!default_initialize && set_value)
1319 dumpElementln (" " + field_name + ": " + value);
1320 if (set_value)
1321 setBooleanField (obj, field_name, value);
1323 else if (type == Byte.TYPE)
1325 byte value =
1326 default_initialize ? 0 : this.realInputStream.readByte ();
1327 if (!default_initialize && set_value)
1328 dumpElementln (" " + field_name + ": " + value);
1329 if (set_value)
1330 setByteField (obj, field_name, value);
1332 else if (type == Character.TYPE)
1334 char value =
1335 default_initialize ? (char)0 : this.realInputStream.readChar ();
1336 if (!default_initialize && set_value)
1337 dumpElementln (" " + field_name + ": " + value);
1338 if (set_value)
1339 setCharField (obj, field_name, value);
1341 else if (type == Double.TYPE)
1343 double value =
1344 default_initialize ? 0 : this.realInputStream.readDouble ();
1345 if (!default_initialize && set_value)
1346 dumpElementln (" " + field_name + ": " + value);
1347 if (set_value)
1348 setDoubleField (obj, field_name, value);
1350 else if (type == Float.TYPE)
1352 float value =
1353 default_initialize ? 0 : this.realInputStream.readFloat ();
1354 if (!default_initialize && set_value)
1355 dumpElementln (" " + field_name + ": " + value);
1356 if (set_value)
1357 setFloatField (obj, field_name, value);
1359 else if (type == Integer.TYPE)
1361 int value =
1362 default_initialize ? 0 : this.realInputStream.readInt ();
1363 if (!default_initialize && set_value)
1364 dumpElementln (" " + field_name + ": " + value);
1365 if (set_value)
1366 setIntField (obj, field_name, value);
1368 else if (type == Long.TYPE)
1370 long value =
1371 default_initialize ? 0 : this.realInputStream.readLong ();
1372 if (!default_initialize && set_value)
1373 dumpElementln (" " + field_name + ": " + value);
1374 if (set_value)
1375 setLongField (obj, field_name, value);
1377 else if (type == Short.TYPE)
1379 short value =
1380 default_initialize ? (short)0 : this.realInputStream.readShort ();
1381 if (!default_initialize && set_value)
1382 dumpElementln (" " + field_name + ": " + value);
1383 if (set_value)
1384 setShortField (obj, field_name, value);
1386 else
1388 Object value =
1389 default_initialize ? null : readObject ();
1390 if (set_value)
1391 setObjectField (obj, field_name,
1392 real_field.getTypeString (), value);
1395 catch (NoSuchFieldError e)
1397 dumpElementln("XXXX " + field_name + " does not exist.");
1403 // Toggles writing primitive data to block-data buffer.
1404 private boolean setBlockDataMode (boolean on)
1406 // DEBUGln ("Setting block data mode to " + on);
1407 boolean oldmode = this.readDataFromBlock;
1408 this.readDataFromBlock = on;
1410 if (on)
1411 this.dataInputStream = this.blockDataInput;
1412 else
1413 this.dataInputStream = this.realInputStream;
1414 return oldmode;
1418 // returns a new instance of REAL_CLASS that has been constructed
1419 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1420 private Object newObject (Class real_class, Class constructor_class)
1424 Object obj = allocateObject (real_class);
1425 callConstructor (constructor_class, obj);
1426 return obj;
1428 catch (InstantiationException e)
1430 return null;
1435 // runs all registered ObjectInputValidations in prioritized order
1436 // on OBJ
1437 private void invokeValidators () throws InvalidObjectException
1439 Object[] validators = new Object[this.validators.size ()];
1440 this.validators.copyInto (validators);
1441 Arrays.sort (validators);
1445 for (int i=0; i < validators.length; i++)
1446 ((ObjectInputValidation)validators[i]).validateObject ();
1448 finally
1450 this.validators.removeAllElements ();
1455 // this native method is used to get access to the protected method
1456 // of the same name in SecurityManger
1457 private static ClassLoader currentClassLoader (SecurityManager sm)
1459 // FIXME: This is too simple.
1460 return ClassLoader.getSystemClassLoader ();
1463 private static Field getField (Class klass, String name)
1464 throws java.lang.NoSuchFieldException
1466 return klass.getDeclaredField(name);
1469 private static Method getMethod (Class klass, String name, Class args[])
1470 throws java.lang.NoSuchMethodException
1472 return klass.getDeclaredMethod(name, args);
1475 private void callReadMethod (Object obj, Class klass) throws IOException
1479 Class classArgs[] = {ObjectInputStream.class};
1480 Method m = getMethod (klass, "readObject", classArgs);
1481 if (m == null)
1482 return;
1483 Object args[] = {this};
1484 m.invoke (obj, args);
1486 catch (InvocationTargetException x)
1488 /* Rethrow if possible. */
1489 Throwable exception = x.getTargetException();
1490 if (exception instanceof RuntimeException)
1491 throw (RuntimeException) exception;
1492 if (exception instanceof IOException)
1493 throw (IOException) exception;
1495 throw new IOException ("Exception thrown from readObject() on " +
1496 klass + ": " + exception.getClass().getName());
1498 catch (Exception x)
1500 throw new IOException ("Failure invoking readObject() on " +
1501 klass + ": " + x.getClass().getName());
1505 private native Object allocateObject (Class clazz)
1506 throws InstantiationException;
1508 private native void callConstructor (Class clazz, Object obj);
1510 private void setBooleanField (Object obj, String field_name,
1511 boolean val)
1515 Class klass = obj.getClass ();
1516 Field f = getField (klass, field_name);
1517 f.setAccessible(true);
1518 f.setBoolean (obj, val);
1520 catch (Exception _)
1525 private void setByteField (Object obj, String field_name,
1526 byte val)
1530 Class klass = obj.getClass ();
1531 Field f = getField (klass, field_name);
1532 f.setAccessible(true);
1533 f.setByte (obj, val);
1535 catch (Exception _)
1540 private void setCharField (Object obj, String field_name,
1541 char val)
1545 Class klass = obj.getClass ();
1546 Field f = getField (klass, field_name);
1547 f.setAccessible(true);
1548 f.setChar (obj, val);
1550 catch (Exception _)
1555 private void setDoubleField (Object obj, String field_name,
1556 double val)
1560 Class klass = obj.getClass ();
1561 Field f = getField (klass, field_name);
1562 f.setAccessible(true);
1563 f.setDouble (obj, val);
1565 catch (Exception _)
1570 private void setFloatField (Object obj, String field_name,
1571 float val)
1575 Class klass = obj.getClass ();
1576 Field f = getField (klass, field_name);
1577 f.setAccessible(true);
1578 f.setFloat (obj, val);
1580 catch (Exception _)
1585 private void setIntField (Object obj, String field_name,
1586 int val)
1590 Class klass = obj.getClass ();
1591 Field f = getField (klass, field_name);
1592 f.setAccessible(true);
1593 f.setInt (obj, val);
1595 catch (Exception _)
1601 private void setLongField (Object obj, String field_name,
1602 long val)
1606 Class klass = obj.getClass ();
1607 Field f = getField (klass, field_name);
1608 f.setAccessible(true);
1609 f.setLong (obj, val);
1611 catch (Exception _)
1617 private void setShortField (Object obj, String field_name,
1618 short val)
1622 Class klass = obj.getClass ();
1623 Field f = getField (klass, field_name);
1624 f.setAccessible(true);
1625 f.setShort (obj, val);
1627 catch (Exception _)
1633 private void setObjectField (Object obj, String field_name, String type_code,
1634 Object val)
1638 Class klass = obj.getClass ();
1639 Field f = getField (klass, field_name);
1640 f.setAccessible(true);
1641 // FIXME: We should check the type_code here
1642 f.set (obj, val);
1644 catch (Exception _)
1649 private static final int BUFFER_SIZE = 1024;
1650 private static final Class[] readObjectParams = { ObjectInputStream.class };
1652 private DataInputStream realInputStream;
1653 private DataInputStream dataInputStream;
1654 private DataInputStream blockDataInput;
1655 private int blockDataPosition;
1656 private int blockDataBytes;
1657 private byte[] blockData;
1658 private boolean useSubclassMethod;
1659 private int nextOID;
1660 private boolean resolveEnabled;
1661 private Hashtable objectLookupTable;
1662 private Object currentObject;
1663 private ObjectStreamClass currentObjectStreamClass;
1664 private boolean readDataFromBlock;
1665 private boolean isDeserializing;
1666 private boolean fieldsAlreadyRead;
1667 private Vector validators;
1669 private static boolean dump;
1671 private void dumpElement (String msg)
1673 if (Configuration.DEBUG && dump)
1674 System.out.print(msg);
1677 private void dumpElementln (String msg)
1679 if (Configuration.DEBUG && dump)
1680 System.out.println(msg);
1683 static
1685 if (Configuration.INIT_LOAD_LIBRARY)
1687 System.loadLibrary ("javaio");
1693 // used to keep a prioritized list of object validators
1694 class ValidatorAndPriority implements Comparable
1696 int priority;
1697 ObjectInputValidation validator;
1699 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1701 this.priority = priority;
1702 this.validator = validator;
1705 public int compareTo (Object o)
1707 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1708 return this.priority - vap.priority;