2005-11-15 Jeroen Frijters <jeroen@frijters.net>
[official-gcc.git] / libjava / java / io / ObjectInputStream.java
blob54661a9bc53272d7342254b7f737bd072a735868
1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.io;
42 import gnu.classpath.Configuration;
43 import gnu.java.io.ObjectIdentityWrapper;
45 import java.lang.reflect.Array;
46 import java.lang.reflect.Constructor;
47 import java.lang.reflect.Field;
48 import java.lang.reflect.InvocationTargetException;
49 import java.lang.reflect.Method;
50 import java.lang.reflect.Modifier;
51 import java.lang.reflect.Proxy;
52 import java.security.AccessController;
53 import java.security.PrivilegedAction;
54 import java.util.Arrays;
55 import java.util.Hashtable;
56 import java.util.Vector;
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 this.classLookupTable = new Hashtable();
104 setBlockDataMode(true);
105 readStreamHeader();
110 * Returns the next deserialized object read from the underlying stream.
112 * This method can be overriden by a class by implementing
113 * <code>private void readObject (ObjectInputStream)</code>.
115 * If an exception is thrown from this method, the stream is left in
116 * an undefined state. This method can also throw Errors and
117 * RuntimeExceptions if caused by existing readResolve() user code.
119 * @return The object read from the underlying stream.
121 * @exception ClassNotFoundException The class that an object being
122 * read in belongs to cannot be found.
124 * @exception IOException Exception from underlying
125 * <code>InputStream</code>.
127 public final Object readObject() throws ClassNotFoundException, IOException
129 if (this.useSubclassMethod)
130 return readObjectOverride();
132 boolean was_deserializing;
134 Object ret_val;
135 was_deserializing = this.isDeserializing;
137 boolean is_consumed = false;
138 boolean old_mode = setBlockDataMode(false);
140 this.isDeserializing = true;
142 byte marker = this.realInputStream.readByte();
144 depth += 2;
146 if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
150 switch (marker)
152 case TC_ENDBLOCKDATA:
154 ret_val = null;
155 is_consumed = true;
156 break;
159 case TC_BLOCKDATA:
160 case TC_BLOCKDATALONG:
162 if (marker == TC_BLOCKDATALONG)
163 { if(dump) dumpElementln("BLOCKDATALONG"); }
164 else
165 { if(dump) dumpElementln("BLOCKDATA"); }
166 readNextBlock(marker);
167 throw new StreamCorruptedException("Unexpected blockData");
170 case TC_NULL:
172 if(dump) dumpElementln("NULL");
173 ret_val = null;
174 break;
177 case TC_REFERENCE:
179 if(dump) dumpElement("REFERENCE ");
180 Integer oid = new Integer(this.realInputStream.readInt());
181 if(dump) dumpElementln(Integer.toHexString(oid.intValue()));
182 ret_val = ((ObjectIdentityWrapper)
183 this.objectLookupTable.get(oid)).object;
184 break;
187 case TC_CLASS:
189 if(dump) dumpElementln("CLASS");
190 ObjectStreamClass osc = (ObjectStreamClass)readObject();
191 Class clazz = osc.forClass();
192 assignNewHandle(clazz);
193 ret_val = clazz;
194 break;
197 case TC_PROXYCLASSDESC:
199 if(dump) dumpElementln("PROXYCLASS");
200 int n_intf = this.realInputStream.readInt();
201 String[] intfs = new String[n_intf];
202 for (int i = 0; i < n_intf; i++)
204 intfs[i] = this.realInputStream.readUTF();
207 boolean oldmode = setBlockDataMode(true);
208 Class cl = resolveProxyClass(intfs);
209 setBlockDataMode(oldmode);
211 ObjectStreamClass osc = lookupClass(cl);
212 if (osc.firstNonSerializableParentConstructor == null)
214 osc.realClassIsSerializable = true;
215 osc.fields = osc.fieldMapping = new ObjectStreamField[0];
218 osc.firstNonSerializableParentConstructor =
219 Object.class.getConstructor(new Class[0]);
221 catch (NoSuchMethodException x)
223 throw (InternalError)
224 new InternalError("Object ctor missing").initCause(x);
227 assignNewHandle(osc);
229 if (!is_consumed)
231 byte b = this.realInputStream.readByte();
232 if (b != TC_ENDBLOCKDATA)
233 throw new IOException("Data annotated to class was not consumed." + b);
235 else
236 is_consumed = false;
237 ObjectStreamClass superosc = (ObjectStreamClass)readObject();
238 osc.setSuperclass(superosc);
239 ret_val = osc;
240 break;
243 case TC_CLASSDESC:
245 ObjectStreamClass osc = readClassDescriptor();
247 if (!is_consumed)
249 byte b = this.realInputStream.readByte();
250 if (b != TC_ENDBLOCKDATA)
251 throw new IOException("Data annotated to class was not consumed." + b);
253 else
254 is_consumed = false;
256 osc.setSuperclass ((ObjectStreamClass)readObject());
257 ret_val = osc;
258 break;
261 case TC_STRING:
262 case TC_LONGSTRING:
264 if(dump) dumpElement("STRING=");
265 String s = this.realInputStream.readUTF();
266 if(dump) dumpElementln(s);
267 ret_val = processResolution(null, s, assignNewHandle(s));
268 break;
271 case TC_ARRAY:
273 if(dump) dumpElementln("ARRAY");
274 ObjectStreamClass osc = (ObjectStreamClass)readObject();
275 Class componentType = osc.forClass().getComponentType();
276 if(dump) dumpElement("ARRAY LENGTH=");
277 int length = this.realInputStream.readInt();
278 if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
279 Object array = Array.newInstance(componentType, length);
280 int handle = assignNewHandle(array);
281 readArrayElements(array, componentType);
282 if(dump)
283 for (int i = 0, len = Array.getLength(array); i < len; i++)
284 dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i));
285 ret_val = processResolution(null, array, handle);
286 break;
289 case TC_OBJECT:
291 if(dump) dumpElementln("OBJECT");
292 ObjectStreamClass osc = (ObjectStreamClass)readObject();
293 Class clazz = osc.forClass();
295 if (!osc.realClassIsSerializable)
296 throw new NotSerializableException
297 (clazz + " is not Serializable, and thus cannot be deserialized.");
299 if (osc.realClassIsExternalizable)
301 Externalizable obj = osc.newInstance();
303 int handle = assignNewHandle(obj);
305 boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
307 boolean oldmode = this.readDataFromBlock;
308 if (read_from_blocks)
309 setBlockDataMode(true);
311 obj.readExternal(this);
313 if (read_from_blocks)
315 setBlockDataMode(oldmode);
316 if (!oldmode)
317 if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
318 throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
321 ret_val = processResolution(osc, obj, handle);
322 break;
323 } // end if (osc.realClassIsExternalizable)
325 Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
327 int handle = assignNewHandle(obj);
328 Object prevObject = this.currentObject;
329 ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
331 this.currentObject = obj;
332 ObjectStreamClass[] hierarchy =
333 inputGetObjectStreamClasses(clazz);
335 for (int i = 0; i < hierarchy.length; i++)
337 this.currentObjectStreamClass = hierarchy[i];
339 if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
341 // XXX: should initialize fields in classes in the hierarchy
342 // that aren't in the stream
343 // should skip over classes in the stream that aren't in the
344 // real classes hierarchy
346 Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
347 if (readObjectMethod != null)
349 fieldsAlreadyRead = false;
350 boolean oldmode = setBlockDataMode(true);
351 callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
352 setBlockDataMode(oldmode);
354 else
356 readFields(obj, currentObjectStreamClass);
359 if (this.currentObjectStreamClass.hasWriteMethod())
361 if(dump) dumpElement("ENDBLOCKDATA? ");
364 // FIXME: XXX: This try block is to
365 // catch EOF which is thrown for some
366 // objects. That indicates a bug in
367 // the logic.
369 if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
370 throw new IOException
371 ("No end of block data seen for class with readObject (ObjectInputStream) method.");
372 if(dump) dumpElementln("yes");
374 // catch (EOFException e)
375 // {
376 // if(dump) dumpElementln("no, got EOFException");
377 // }
378 catch (IOException e)
380 if(dump) dumpElementln("no, got IOException");
385 this.currentObject = prevObject;
386 this.currentObjectStreamClass = prevObjectStreamClass;
387 ret_val = processResolution(osc, obj, handle);
389 break;
392 case TC_RESET:
393 if(dump) dumpElementln("RESET");
394 clearHandles();
395 ret_val = readObject();
396 break;
398 case TC_EXCEPTION:
400 if(dump) dumpElement("EXCEPTION=");
401 Exception e = (Exception)readObject();
402 if(dump) dumpElementln(e.toString());
403 clearHandles();
404 throw new WriteAbortedException("Exception thrown during writing of stream", e);
407 default:
408 throw new IOException("Unknown marker on stream: " + marker);
411 finally
413 setBlockDataMode(old_mode);
415 this.isDeserializing = was_deserializing;
417 depth -= 2;
419 if (! was_deserializing)
421 if (validators.size() > 0)
422 invokeValidators();
426 return ret_val;
430 * This method makes a partial check of types for the fields
431 * contained given in arguments. It checks primitive types of
432 * fields1 against non primitive types of fields2. This method
433 * assumes the two lists has already been sorted according to
434 * the Java specification.
436 * @param name Name of the class owning the given fields.
437 * @param fields1 First list to check.
438 * @param fields2 Second list to check.
439 * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
440 * in the non primitive part in fields2.
442 private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
443 throws InvalidClassException
445 int nonPrimitive = 0;
447 for (nonPrimitive = 0;
448 nonPrimitive < fields1.length
449 && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
453 if (nonPrimitive == fields1.length)
454 return;
456 int i = 0;
457 ObjectStreamField f1;
458 ObjectStreamField f2;
460 while (i < fields2.length
461 && nonPrimitive < fields1.length)
463 f1 = fields1[nonPrimitive];
464 f2 = fields2[i];
466 if (!f2.isPrimitive())
467 break;
469 int compVal = f1.getName().compareTo (f2.getName());
471 if (compVal < 0)
473 nonPrimitive++;
475 else if (compVal > 0)
477 i++;
479 else
481 throw new InvalidClassException
482 ("invalid field type for " + f2.getName() +
483 " in class " + name);
489 * This method reads a class descriptor from the real input stream
490 * and use these data to create a new instance of ObjectStreamClass.
491 * Fields are sorted and ordered for the real read which occurs for
492 * each instance of the described class. Be aware that if you call that
493 * method you must ensure that the stream is synchronized, in the other
494 * case it may be completely desynchronized.
496 * @return A new instance of ObjectStreamClass containing the freshly
497 * created descriptor.
498 * @throws ClassNotFoundException if the required class to build the
499 * descriptor has not been found in the system.
500 * @throws IOException An input/output error occured.
501 * @throws InvalidClassException If there was a compatibility problem
502 * between the class present in the system and the serialized class.
504 protected ObjectStreamClass readClassDescriptor()
505 throws ClassNotFoundException, IOException
507 if(dump) dumpElement("CLASSDESC NAME=");
508 String name = this.realInputStream.readUTF();
509 if(dump) dumpElement(name + "; UID=");
510 long uid = this.realInputStream.readLong ();
511 if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
512 byte flags = this.realInputStream.readByte ();
513 if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
514 short field_count = this.realInputStream.readShort();
515 if(dump) dumpElementln(Short.toString(field_count));
516 ObjectStreamField[] fields = new ObjectStreamField[field_count];
517 ObjectStreamClass osc = new ObjectStreamClass(name, uid,
518 flags, fields);
519 assignNewHandle(osc);
521 if (callersClassLoader == null)
522 callersClassLoader = currentLoader();
524 for (int i = 0; i < field_count; i++)
526 if(dump) dumpElement(" TYPE CODE=");
527 char type_code = (char)this.realInputStream.readByte();
528 if(dump) dumpElement(type_code + "; FIELD NAME=");
529 String field_name = this.realInputStream.readUTF();
530 if(dump) dumpElementln(field_name);
531 String class_name;
533 // If the type code is an array or an object we must
534 // decode a String here. In the other case we convert
535 // the type code and pass it to ObjectStreamField.
536 // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
537 if (type_code == 'L' || type_code == '[')
538 class_name = (String)readObject();
539 else
540 class_name = String.valueOf(type_code);
542 fields[i] =
543 new ObjectStreamField(field_name, class_name, callersClassLoader);
546 /* Now that fields have been read we may resolve the class
547 * (and read annotation if needed). */
548 Class clazz;
551 clazz = resolveClass(osc);
553 catch (ClassNotFoundException cnfe)
555 // Maybe it was an primitive class?
556 if (name.equals("void"))
557 clazz = Void.TYPE;
558 else if (name.equals("boolean"))
559 clazz = Boolean.TYPE;
560 else if (name.equals("byte"))
561 clazz = Byte.TYPE;
562 else if (name.equals("short"))
563 clazz = Short.TYPE;
564 else if (name.equals("char"))
565 clazz = Character.TYPE;
566 else if (name.equals("int"))
567 clazz = Integer.TYPE;
568 else if (name.equals("long"))
569 clazz = Long.TYPE;
570 else if (name.equals("float"))
571 clazz = Float.TYPE;
572 else if (name.equals("double"))
573 clazz = Double.TYPE;
574 else
575 throw cnfe;
578 boolean oldmode = setBlockDataMode(true);
579 osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
580 classLookupTable.put(clazz, osc);
581 setBlockDataMode(oldmode);
583 // find the first non-serializable, non-abstract
584 // class in clazz's inheritance hierarchy
585 Class first_nonserial = clazz.getSuperclass();
586 // Maybe it is a primitive class, those don't have a super class,
587 // or Object itself. Otherwise we can keep getting the superclass
588 // till we hit the Object class, or some other non-serializable class.
590 if (first_nonserial == null)
591 first_nonserial = clazz;
592 else
593 while (Serializable.class.isAssignableFrom(first_nonserial)
594 || Modifier.isAbstract(first_nonserial.getModifiers()))
595 first_nonserial = first_nonserial.getSuperclass();
597 final Class local_constructor_class = first_nonserial;
599 osc.firstNonSerializableParentConstructor =
600 (Constructor)AccessController.doPrivileged(new PrivilegedAction()
602 public Object run()
606 Constructor c = local_constructor_class.
607 getDeclaredConstructor(new Class[0]);
608 if (Modifier.isPrivate(c.getModifiers()))
609 return null;
610 return c;
612 catch (NoSuchMethodException e)
614 // error will be reported later, in newObject()
615 return null;
620 osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
621 osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
623 ObjectStreamField[] stream_fields = osc.fields;
624 ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
625 ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
627 int stream_idx = 0;
628 int real_idx = 0;
629 int map_idx = 0;
632 * Check that there is no type inconsistencies between the lists.
633 * A special checking must be done for the two groups: primitive types and
634 * not primitive types.
636 checkTypeConsistency(name, real_fields, stream_fields);
637 checkTypeConsistency(name, stream_fields, real_fields);
640 while (stream_idx < stream_fields.length
641 || real_idx < real_fields.length)
643 ObjectStreamField stream_field = null;
644 ObjectStreamField real_field = null;
646 if (stream_idx == stream_fields.length)
648 real_field = real_fields[real_idx++];
650 else if (real_idx == real_fields.length)
652 stream_field = stream_fields[stream_idx++];
654 else
656 int comp_val =
657 real_fields[real_idx].compareTo (stream_fields[stream_idx]);
659 if (comp_val < 0)
661 real_field = real_fields[real_idx++];
663 else if (comp_val > 0)
665 stream_field = stream_fields[stream_idx++];
667 else
669 stream_field = stream_fields[stream_idx++];
670 real_field = real_fields[real_idx++];
671 if (stream_field.getType() != real_field.getType())
672 throw new InvalidClassException
673 ("invalid field type for " + real_field.getName() +
674 " in class " + name);
678 /* If some of stream_fields does not correspond to any of real_fields,
679 * or the opposite, then fieldmapping will go short.
681 if (map_idx == fieldmapping.length)
683 ObjectStreamField[] newfieldmapping =
684 new ObjectStreamField[fieldmapping.length + 2];
685 System.arraycopy(fieldmapping, 0,
686 newfieldmapping, 0, fieldmapping.length);
687 fieldmapping = newfieldmapping;
689 fieldmapping[map_idx++] = stream_field;
690 fieldmapping[map_idx++] = real_field;
692 osc.fieldMapping = fieldmapping;
694 return osc;
698 * Reads the current objects non-transient, non-static fields from
699 * the current class from the underlying output stream.
701 * This method is intended to be called from within a object's
702 * <code>private void readObject (ObjectInputStream)</code>
703 * method.
705 * @exception ClassNotFoundException The class that an object being
706 * read in belongs to cannot be found.
708 * @exception NotActiveException This method was called from a
709 * context other than from the current object's and current class's
710 * <code>private void readObject (ObjectInputStream)</code>
711 * method.
713 * @exception IOException Exception from underlying
714 * <code>OutputStream</code>.
716 public void defaultReadObject()
717 throws ClassNotFoundException, IOException, NotActiveException
719 if (this.currentObject == null || this.currentObjectStreamClass == null)
720 throw new NotActiveException("defaultReadObject called by non-active"
721 + " class and/or object");
723 if (fieldsAlreadyRead)
724 throw new NotActiveException("defaultReadObject called but fields "
725 + "already read from stream (by "
726 + "defaultReadObject or readFields)");
728 boolean oldmode = setBlockDataMode(false);
729 readFields(this.currentObject, this.currentObjectStreamClass);
730 setBlockDataMode(oldmode);
732 fieldsAlreadyRead = true;
737 * Registers a <code>ObjectInputValidation</code> to be carried out
738 * on the object graph currently being deserialized before it is
739 * returned to the original caller of <code>readObject ()</code>.
740 * The order of validation for multiple
741 * <code>ObjectInputValidation</code>s can be controled using
742 * <code>priority</code>. Validators with higher priorities are
743 * called first.
745 * @see java.io.ObjectInputValidation
747 * @exception InvalidObjectException <code>validator</code> is
748 * <code>null</code>
750 * @exception NotActiveException an attempt was made to add a
751 * validator outside of the <code>readObject</code> method of the
752 * object currently being deserialized
754 public void registerValidation(ObjectInputValidation validator,
755 int priority)
756 throws InvalidObjectException, NotActiveException
758 if (this.currentObject == null || this.currentObjectStreamClass == null)
759 throw new NotActiveException("registerValidation called by non-active "
760 + "class and/or object");
762 if (validator == null)
763 throw new InvalidObjectException("attempt to add a null "
764 + "ObjectInputValidation object");
766 this.validators.addElement(new ValidatorAndPriority (validator,
767 priority));
772 * Called when a class is being deserialized. This is a hook to
773 * allow subclasses to read in information written by the
774 * <code>annotateClass (Class)</code> method of an
775 * <code>ObjectOutputStream</code>.
777 * This implementation looks up the active call stack for a
778 * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
779 * it is used to load the class associated with <code>osc</code>,
780 * otherwise, the default system <code>ClassLoader</code> is used.
782 * @exception IOException Exception from underlying
783 * <code>OutputStream</code>.
785 * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
787 protected Class resolveClass(ObjectStreamClass osc)
788 throws ClassNotFoundException, IOException
790 if (callersClassLoader == null)
792 callersClassLoader = currentLoader ();
793 if (Configuration.DEBUG && dump)
795 dumpElementln ("CallersClassLoader = " + callersClassLoader);
799 return Class.forName(osc.getName(), true, callersClassLoader);
803 * Returns the most recent user defined ClassLoader on the execution stack
804 * or null if none is found.
806 // GCJ LOCAL: native method.
807 private native ClassLoader currentLoader();
810 * Lookup a class stored in the local hashtable. If it is not
811 * use the global lookup function in ObjectStreamClass to build
812 * the ObjectStreamClass. This method is requested according to
813 * the behaviour detected in the JDK by Kaffe's team.
815 * @param clazz Class to lookup in the hash table or for which
816 * we must build a descriptor.
817 * @return A valid instance of ObjectStreamClass corresponding
818 * to the specified class.
820 private ObjectStreamClass lookupClass(Class clazz)
822 if (clazz == null)
823 return null;
825 ObjectStreamClass oclazz;
826 oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
827 if (oclazz == null)
828 return ObjectStreamClass.lookup(clazz);
829 else
830 return oclazz;
834 * Reconstruct class hierarchy the same way
835 * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
836 * but using lookupClass instead of ObjectStreamClass.lookup. This
837 * dup is necessary localize the lookup table. Hopefully some future
838 * rewritings will be able to prevent this.
840 * @param clazz This is the class for which we want the hierarchy.
842 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
843 * represent the class hierarchy for clazz.
845 private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
847 ObjectStreamClass osc = lookupClass(clazz);
849 if (osc == null)
850 return new ObjectStreamClass[0];
851 else
853 Vector oscs = new Vector();
855 while (osc != null)
857 oscs.addElement(osc);
858 osc = osc.getSuper();
861 int count = oscs.size();
862 ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
864 for (int i = count - 1; i >= 0; i--)
865 sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
867 return sorted_oscs;
872 * Allows subclasses to resolve objects that are read from the
873 * stream with other objects to be returned in their place. This
874 * method is called the first time each object is encountered.
876 * This method must be enabled before it will be called in the
877 * serialization process.
879 * @exception IOException Exception from underlying
880 * <code>OutputStream</code>.
882 * @see #enableResolveObject(boolean)
884 protected Object resolveObject(Object obj) throws IOException
886 return obj;
890 protected Class resolveProxyClass(String[] intfs)
891 throws IOException, ClassNotFoundException
893 ClassLoader cl = currentLoader();
895 Class[] clss = new Class[intfs.length];
896 if(cl == null)
898 for (int i = 0; i < intfs.length; i++)
899 clss[i] = Class.forName(intfs[i]);
900 cl = ClassLoader.getSystemClassLoader();
902 else
903 for (int i = 0; i < intfs.length; i++)
904 clss[i] = cl.loadClass(intfs[i]);
905 try
907 return Proxy.getProxyClass(cl, clss);
909 catch (IllegalArgumentException e)
911 throw new ClassNotFoundException(null, e);
916 * If <code>enable</code> is <code>true</code> and this object is
917 * trusted, then <code>resolveObject (Object)</code> will be called
918 * in subsequent calls to <code>readObject (Object)</code>.
919 * Otherwise, <code>resolveObject (Object)</code> will not be called.
921 * @exception SecurityException This class is not trusted.
923 protected boolean enableResolveObject (boolean enable)
924 throws SecurityException
926 if (enable)
928 SecurityManager sm = System.getSecurityManager();
929 if (sm != null)
930 sm.checkPermission(new SerializablePermission("enableSubstitution"));
933 boolean old_val = this.resolveEnabled;
934 this.resolveEnabled = enable;
935 return old_val;
939 * Reads stream magic and stream version information from the
940 * underlying stream.
942 * @exception IOException Exception from underlying stream.
944 * @exception StreamCorruptedException An invalid stream magic
945 * number or stream version was read from the stream.
947 protected void readStreamHeader()
948 throws IOException, StreamCorruptedException
950 if(dump) dumpElement("STREAM MAGIC ");
951 if (this.realInputStream.readShort() != STREAM_MAGIC)
952 throw new StreamCorruptedException("Invalid stream magic number");
954 if(dump) dumpElementln("STREAM VERSION ");
955 if (this.realInputStream.readShort() != STREAM_VERSION)
956 throw new StreamCorruptedException("Invalid stream version number");
959 public int read() throws IOException
961 if (this.readDataFromBlock)
963 if (this.blockDataPosition >= this.blockDataBytes)
964 readNextBlock();
965 return (this.blockData[this.blockDataPosition++] & 0xff);
967 else
968 return this.realInputStream.read();
971 public int read(byte[] data, int offset, int length) throws IOException
973 if (this.readDataFromBlock)
975 if (this.blockDataPosition + length > this.blockDataBytes)
977 int remain = this.blockDataBytes - this.blockDataPosition;
978 if (remain != 0)
980 System.arraycopy(this.blockData, this.blockDataPosition,
981 data, offset, remain);
982 offset += remain;
983 length -= remain;
985 readNextBlock ();
988 System.arraycopy(this.blockData, this.blockDataPosition,
989 data, offset, length);
990 this.blockDataPosition += length;
992 return length;
994 else
995 return this.realInputStream.read(data, offset, length);
998 public int available() throws IOException
1000 if (this.readDataFromBlock)
1002 if (this.blockDataPosition >= this.blockDataBytes)
1003 readNextBlock ();
1005 return this.blockDataBytes - this.blockDataPosition;
1007 else
1008 return this.realInputStream.available();
1011 public void close() throws IOException
1013 this.realInputStream.close();
1016 public boolean readBoolean() throws IOException
1018 boolean switchmode = true;
1019 boolean oldmode = this.readDataFromBlock;
1020 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1021 switchmode = false;
1022 if (switchmode)
1023 oldmode = setBlockDataMode (true);
1024 boolean value = this.dataInputStream.readBoolean ();
1025 if (switchmode)
1026 setBlockDataMode (oldmode);
1027 return value;
1030 public byte readByte() throws IOException
1032 boolean switchmode = true;
1033 boolean oldmode = this.readDataFromBlock;
1034 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1035 switchmode = false;
1036 if (switchmode)
1037 oldmode = setBlockDataMode(true);
1038 byte value = this.dataInputStream.readByte();
1039 if (switchmode)
1040 setBlockDataMode(oldmode);
1041 return value;
1044 public int readUnsignedByte() throws IOException
1046 boolean switchmode = true;
1047 boolean oldmode = this.readDataFromBlock;
1048 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1049 switchmode = false;
1050 if (switchmode)
1051 oldmode = setBlockDataMode(true);
1052 int value = this.dataInputStream.readUnsignedByte();
1053 if (switchmode)
1054 setBlockDataMode(oldmode);
1055 return value;
1058 public short readShort() throws IOException
1060 boolean switchmode = true;
1061 boolean oldmode = this.readDataFromBlock;
1062 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1063 switchmode = false;
1064 if (switchmode)
1065 oldmode = setBlockDataMode(true);
1066 short value = this.dataInputStream.readShort();
1067 if (switchmode)
1068 setBlockDataMode(oldmode);
1069 return value;
1072 public int readUnsignedShort() throws IOException
1074 boolean switchmode = true;
1075 boolean oldmode = this.readDataFromBlock;
1076 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1077 switchmode = false;
1078 if (switchmode)
1079 oldmode = setBlockDataMode(true);
1080 int value = this.dataInputStream.readUnsignedShort();
1081 if (switchmode)
1082 setBlockDataMode(oldmode);
1083 return value;
1086 public char readChar() throws IOException
1088 boolean switchmode = true;
1089 boolean oldmode = this.readDataFromBlock;
1090 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1091 switchmode = false;
1092 if (switchmode)
1093 oldmode = setBlockDataMode(true);
1094 char value = this.dataInputStream.readChar();
1095 if (switchmode)
1096 setBlockDataMode(oldmode);
1097 return value;
1100 public int readInt() throws IOException
1102 boolean switchmode = true;
1103 boolean oldmode = this.readDataFromBlock;
1104 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1105 switchmode = false;
1106 if (switchmode)
1107 oldmode = setBlockDataMode(true);
1108 int value = this.dataInputStream.readInt();
1109 if (switchmode)
1110 setBlockDataMode(oldmode);
1111 return value;
1114 public long readLong() throws IOException
1116 boolean switchmode = true;
1117 boolean oldmode = this.readDataFromBlock;
1118 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1119 switchmode = false;
1120 if (switchmode)
1121 oldmode = setBlockDataMode(true);
1122 long value = this.dataInputStream.readLong();
1123 if (switchmode)
1124 setBlockDataMode(oldmode);
1125 return value;
1128 public float readFloat() throws IOException
1130 boolean switchmode = true;
1131 boolean oldmode = this.readDataFromBlock;
1132 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1133 switchmode = false;
1134 if (switchmode)
1135 oldmode = setBlockDataMode(true);
1136 float value = this.dataInputStream.readFloat();
1137 if (switchmode)
1138 setBlockDataMode(oldmode);
1139 return value;
1142 public double readDouble() throws IOException
1144 boolean switchmode = true;
1145 boolean oldmode = this.readDataFromBlock;
1146 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1147 switchmode = false;
1148 if (switchmode)
1149 oldmode = setBlockDataMode(true);
1150 double value = this.dataInputStream.readDouble();
1151 if (switchmode)
1152 setBlockDataMode(oldmode);
1153 return value;
1156 public void readFully(byte data[]) throws IOException
1158 this.dataInputStream.readFully(data);
1161 public void readFully(byte data[], int offset, int size)
1162 throws IOException
1164 this.dataInputStream.readFully(data, offset, size);
1167 public int skipBytes(int len) throws IOException
1169 return this.dataInputStream.skipBytes(len);
1173 * @deprecated
1174 * @see java.io.DataInputStream#readLine ()
1176 public String readLine() throws IOException
1178 return this.dataInputStream.readLine();
1181 public String readUTF() throws IOException
1183 return this.dataInputStream.readUTF();
1187 * This class allows a class to specify exactly which fields should
1188 * be read, and what values should be read for these fields.
1190 * XXX: finish up comments
1192 public abstract static class GetField
1194 public abstract ObjectStreamClass getObjectStreamClass();
1196 public abstract boolean defaulted(String name)
1197 throws IOException, IllegalArgumentException;
1199 public abstract boolean get(String name, boolean defvalue)
1200 throws IOException, IllegalArgumentException;
1202 public abstract char get(String name, char defvalue)
1203 throws IOException, IllegalArgumentException;
1205 public abstract byte get(String name, byte defvalue)
1206 throws IOException, IllegalArgumentException;
1208 public abstract short get(String name, short defvalue)
1209 throws IOException, IllegalArgumentException;
1211 public abstract int get(String name, int defvalue)
1212 throws IOException, IllegalArgumentException;
1214 public abstract long get(String name, long defvalue)
1215 throws IOException, IllegalArgumentException;
1217 public abstract float get(String name, float defvalue)
1218 throws IOException, IllegalArgumentException;
1220 public abstract double get(String name, double defvalue)
1221 throws IOException, IllegalArgumentException;
1223 public abstract Object get(String name, Object defvalue)
1224 throws IOException, IllegalArgumentException;
1228 * This method should be called by a method called 'readObject' in the
1229 * deserializing class (if present). It cannot (and should not)be called
1230 * outside of it. Its goal is to read all fields in the real input stream
1231 * and keep them accessible through the {@link #GetField} class. Calling
1232 * this method will not alter the deserializing object.
1234 * @return A valid freshly created 'GetField' instance to get access to
1235 * the deserialized stream.
1236 * @throws IOException An input/output exception occured.
1237 * @throws ClassNotFoundException
1238 * @throws NotActiveException
1240 public GetField readFields()
1241 throws IOException, ClassNotFoundException, NotActiveException
1243 if (this.currentObject == null || this.currentObjectStreamClass == null)
1244 throw new NotActiveException("readFields called by non-active class and/or object");
1246 if (prereadFields != null)
1247 return prereadFields;
1249 if (fieldsAlreadyRead)
1250 throw new NotActiveException("readFields called but fields already read from"
1251 + " stream (by defaultReadObject or readFields)");
1253 final ObjectStreamClass clazz = this.currentObjectStreamClass;
1254 final byte[] prim_field_data = new byte[clazz.primFieldSize];
1255 final Object[] objs = new Object[clazz.objectFieldCount];
1257 // Apparently Block data is not used with GetField as per
1258 // empirical evidence against JDK 1.2. Also see Mauve test
1259 // java.io.ObjectInputOutput.Test.GetPutField.
1260 boolean oldmode = setBlockDataMode(false);
1261 readFully(prim_field_data);
1262 for (int i = 0; i < objs.length; ++ i)
1263 objs[i] = readObject();
1264 setBlockDataMode(oldmode);
1266 prereadFields = new GetField()
1268 public ObjectStreamClass getObjectStreamClass()
1270 return clazz;
1273 public boolean defaulted(String name)
1274 throws IOException, IllegalArgumentException
1276 ObjectStreamField f = clazz.getField(name);
1278 /* First if we have a serialized field use the descriptor */
1279 if (f != null)
1281 /* It is in serialPersistentFields but setClass tells us
1282 * it should not be set. This value is defaulted.
1284 if (f.isPersistent() && !f.isToSet())
1285 return true;
1287 return false;
1290 /* This is not a serialized field. There should be
1291 * a default value only if the field really exists.
1295 return (clazz.forClass().getDeclaredField (name) != null);
1297 catch (NoSuchFieldException e)
1299 throw new IllegalArgumentException(e.getMessage());
1303 public boolean get(String name, boolean defvalue)
1304 throws IOException, IllegalArgumentException
1306 ObjectStreamField field = getField(name, Boolean.TYPE);
1308 if (field == null)
1309 return defvalue;
1311 return prim_field_data[field.getOffset()] == 0 ? false : true;
1314 public char get(String name, char defvalue)
1315 throws IOException, IllegalArgumentException
1317 ObjectStreamField field = getField(name, Character.TYPE);
1319 if (field == null)
1320 return defvalue;
1322 int off = field.getOffset();
1324 return (char)(((prim_field_data[off++] & 0xFF) << 8)
1325 | (prim_field_data[off] & 0xFF));
1328 public byte get(String name, byte defvalue)
1329 throws IOException, IllegalArgumentException
1331 ObjectStreamField field = getField(name, Byte.TYPE);
1333 if (field == null)
1334 return defvalue;
1336 return prim_field_data[field.getOffset()];
1339 public short get(String name, short defvalue)
1340 throws IOException, IllegalArgumentException
1342 ObjectStreamField field = getField(name, Short.TYPE);
1344 if (field == null)
1345 return defvalue;
1347 int off = field.getOffset();
1349 return (short)(((prim_field_data[off++] & 0xFF) << 8)
1350 | (prim_field_data[off] & 0xFF));
1353 public int get(String name, int defvalue)
1354 throws IOException, IllegalArgumentException
1356 ObjectStreamField field = getField(name, Integer.TYPE);
1358 if (field == null)
1359 return defvalue;
1361 int off = field.getOffset();
1363 return ((prim_field_data[off++] & 0xFF) << 24)
1364 | ((prim_field_data[off++] & 0xFF) << 16)
1365 | ((prim_field_data[off++] & 0xFF) << 8)
1366 | (prim_field_data[off] & 0xFF);
1369 public long get(String name, long defvalue)
1370 throws IOException, IllegalArgumentException
1372 ObjectStreamField field = getField(name, Long.TYPE);
1374 if (field == null)
1375 return defvalue;
1377 int off = field.getOffset();
1379 return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1380 | ((prim_field_data[off++] & 0xFFL) << 48)
1381 | ((prim_field_data[off++] & 0xFFL) << 40)
1382 | ((prim_field_data[off++] & 0xFFL) << 32)
1383 | ((prim_field_data[off++] & 0xFF) << 24)
1384 | ((prim_field_data[off++] & 0xFF) << 16)
1385 | ((prim_field_data[off++] & 0xFF) << 8)
1386 | (prim_field_data[off] & 0xFF));
1389 public float get(String name, float defvalue)
1390 throws IOException, IllegalArgumentException
1392 ObjectStreamField field = getField(name, Float.TYPE);
1394 if (field == null)
1395 return defvalue;
1397 int off = field.getOffset();
1399 return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1400 | ((prim_field_data[off++] & 0xFF) << 16)
1401 | ((prim_field_data[off++] & 0xFF) << 8)
1402 | (prim_field_data[off] & 0xFF));
1405 public double get(String name, double defvalue)
1406 throws IOException, IllegalArgumentException
1408 ObjectStreamField field = getField(name, Double.TYPE);
1410 if (field == null)
1411 return defvalue;
1413 int off = field.getOffset();
1415 return Double.longBitsToDouble
1416 ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1417 | ((prim_field_data[off++] & 0xFFL) << 48)
1418 | ((prim_field_data[off++] & 0xFFL) << 40)
1419 | ((prim_field_data[off++] & 0xFFL) << 32)
1420 | ((prim_field_data[off++] & 0xFF) << 24)
1421 | ((prim_field_data[off++] & 0xFF) << 16)
1422 | ((prim_field_data[off++] & 0xFF) << 8)
1423 | (prim_field_data[off] & 0xFF)));
1426 public Object get(String name, Object defvalue)
1427 throws IOException, IllegalArgumentException
1429 ObjectStreamField field =
1430 getField(name, defvalue == null ? null : defvalue.getClass ());
1432 if (field == null)
1433 return defvalue;
1435 return objs[field.getOffset()];
1438 private ObjectStreamField getField(String name, Class type)
1439 throws IllegalArgumentException
1441 ObjectStreamField field = clazz.getField(name);
1442 boolean illegal = false;
1448 Class field_type = field.getType();
1450 if (type == field_type ||
1451 (type == null && !field_type.isPrimitive()))
1453 /* See defaulted */
1454 return field;
1457 illegal = true;
1458 throw new IllegalArgumentException
1459 ("Field requested is of type "
1460 + field_type.getName()
1461 + ", but requested type was "
1462 + (type == null ? "Object" : type.getName()));
1464 catch (NullPointerException _)
1466 /* Here we catch NullPointerException, because it may
1467 only come from the call 'field.getType()'. If field
1468 is null, we have to return null and classpath ethic
1469 say we must try to avoid 'if (xxx == null)'.
1472 catch (IllegalArgumentException e)
1474 throw e;
1477 return null;
1479 finally
1481 /* If this is an unassigned field we should return
1482 * the default value.
1484 if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1485 return null;
1487 /* We do not want to modify transient fields. They should
1488 * be left to 0.
1492 Field f = clazz.forClass().getDeclaredField(name);
1493 if (Modifier.isTransient(f.getModifiers()))
1494 throw new IllegalArgumentException
1495 ("no such field (non transient) " + name);
1496 if (field == null && f.getType() != type)
1497 throw new IllegalArgumentException
1498 ("Invalid requested type for field " + name);
1500 catch (NoSuchFieldException e)
1502 if (field == null)
1503 throw new IllegalArgumentException(e.getMessage());
1510 fieldsAlreadyRead = true;
1511 return prereadFields;
1515 * Protected constructor that allows subclasses to override
1516 * deserialization. This constructor should be called by subclasses
1517 * that wish to override <code>readObject (Object)</code>. This
1518 * method does a security check <i>NOTE: currently not
1519 * implemented</i>, then sets a flag that informs
1520 * <code>readObject (Object)</code> to call the subclasses
1521 * <code>readObjectOverride (Object)</code> method.
1523 * @see #readObjectOverride()
1525 protected ObjectInputStream()
1526 throws IOException, SecurityException
1528 SecurityManager sec_man = System.getSecurityManager();
1529 if (sec_man != null)
1530 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1531 this.useSubclassMethod = true;
1535 * This method allows subclasses to override the default
1536 * de serialization mechanism provided by
1537 * <code>ObjectInputStream</code>. To make this method be used for
1538 * writing objects, subclasses must invoke the 0-argument
1539 * constructor on this class from their constructor.
1541 * @see #ObjectInputStream()
1543 protected Object readObjectOverride()
1544 throws ClassNotFoundException, IOException, OptionalDataException
1546 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1550 * Assigns the next available handle to <code>obj</code>.
1552 * @param obj The object for which we want a new handle.
1553 * @return A valid handle for the specified object.
1555 private int assignNewHandle(Object obj)
1557 this.objectLookupTable.put(new Integer(this.nextOID),
1558 new ObjectIdentityWrapper(obj));
1559 return this.nextOID++;
1562 private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
1563 throws IOException
1565 if (osc != null && obj instanceof Serializable)
1569 Method m = osc.readResolveMethod;
1570 if(m != null)
1572 obj = m.invoke(obj, new Object[] {});
1575 catch (IllegalAccessException ignore)
1578 catch (InvocationTargetException exception)
1580 Throwable cause = exception.getCause();
1581 if (cause instanceof ObjectStreamException)
1582 throw (ObjectStreamException) cause;
1583 else if (cause instanceof RuntimeException)
1584 throw (RuntimeException) cause;
1585 else if (cause instanceof Error)
1586 throw (Error) cause;
1590 if (this.resolveEnabled)
1591 obj = resolveObject(obj);
1593 this.objectLookupTable.put(new Integer(handle),
1594 new ObjectIdentityWrapper(obj));
1596 return obj;
1599 private void clearHandles()
1601 this.objectLookupTable.clear();
1602 this.nextOID = baseWireHandle;
1605 private void readNextBlock() throws IOException
1607 readNextBlock(this.realInputStream.readByte());
1610 private void readNextBlock(byte marker) throws IOException
1612 if (marker == TC_BLOCKDATA)
1614 if(dump) dumpElement("BLOCK DATA SIZE=");
1615 this.blockDataBytes = this.realInputStream.readUnsignedByte();
1616 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1618 else if (marker == TC_BLOCKDATALONG)
1620 if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1621 this.blockDataBytes = this.realInputStream.readInt();
1622 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1624 else
1626 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1629 if (this.blockData.length < this.blockDataBytes)
1630 this.blockData = new byte[this.blockDataBytes];
1632 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1633 this.blockDataPosition = 0;
1636 private void readArrayElements (Object array, Class clazz)
1637 throws ClassNotFoundException, IOException
1639 if (clazz.isPrimitive())
1641 if (clazz == Boolean.TYPE)
1643 boolean[] cast_array = (boolean[])array;
1644 for (int i=0; i < cast_array.length; i++)
1645 cast_array[i] = this.realInputStream.readBoolean();
1646 return;
1648 if (clazz == Byte.TYPE)
1650 byte[] cast_array = (byte[])array;
1651 for (int i=0; i < cast_array.length; i++)
1652 cast_array[i] = this.realInputStream.readByte();
1653 return;
1655 if (clazz == Character.TYPE)
1657 char[] cast_array = (char[])array;
1658 for (int i=0; i < cast_array.length; i++)
1659 cast_array[i] = this.realInputStream.readChar();
1660 return;
1662 if (clazz == Double.TYPE)
1664 double[] cast_array = (double[])array;
1665 for (int i=0; i < cast_array.length; i++)
1666 cast_array[i] = this.realInputStream.readDouble();
1667 return;
1669 if (clazz == Float.TYPE)
1671 float[] cast_array = (float[])array;
1672 for (int i=0; i < cast_array.length; i++)
1673 cast_array[i] = this.realInputStream.readFloat();
1674 return;
1676 if (clazz == Integer.TYPE)
1678 int[] cast_array = (int[])array;
1679 for (int i=0; i < cast_array.length; i++)
1680 cast_array[i] = this.realInputStream.readInt();
1681 return;
1683 if (clazz == Long.TYPE)
1685 long[] cast_array = (long[])array;
1686 for (int i=0; i < cast_array.length; i++)
1687 cast_array[i] = this.realInputStream.readLong();
1688 return;
1690 if (clazz == Short.TYPE)
1692 short[] cast_array = (short[])array;
1693 for (int i=0; i < cast_array.length; i++)
1694 cast_array[i] = this.realInputStream.readShort();
1695 return;
1698 else
1700 Object[] cast_array = (Object[])array;
1701 for (int i=0; i < cast_array.length; i++)
1702 cast_array[i] = readObject();
1706 private void readFields (Object obj, ObjectStreamClass stream_osc)
1707 throws ClassNotFoundException, IOException
1709 ObjectStreamField[] fields = stream_osc.fieldMapping;
1711 for (int i = 0; i < fields.length; i += 2)
1713 ObjectStreamField stream_field = fields[i];
1714 ObjectStreamField real_field = fields[i + 1];
1715 boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1716 boolean set_value = (real_field != null && real_field.isToSet());
1717 String field_name;
1718 char type;
1720 if (stream_field != null)
1722 field_name = stream_field.getName();
1723 type = stream_field.getTypeCode();
1725 else
1727 field_name = real_field.getName();
1728 type = real_field.getTypeCode();
1731 switch(type)
1733 case 'Z':
1735 boolean value =
1736 read_value ? this.realInputStream.readBoolean() : false;
1737 if (dump && read_value && set_value)
1738 dumpElementln(" " + field_name + ": " + value);
1739 if (set_value)
1740 real_field.setBooleanField(obj, value);
1741 break;
1743 case 'B':
1745 byte value =
1746 read_value ? this.realInputStream.readByte() : 0;
1747 if (dump && read_value && set_value)
1748 dumpElementln(" " + field_name + ": " + value);
1749 if (set_value)
1750 real_field.setByteField(obj, value);
1751 break;
1753 case 'C':
1755 char value =
1756 read_value ? this.realInputStream.readChar(): 0;
1757 if (dump && read_value && set_value)
1758 dumpElementln(" " + field_name + ": " + value);
1759 if (set_value)
1760 real_field.setCharField(obj, value);
1761 break;
1763 case 'D':
1765 double value =
1766 read_value ? this.realInputStream.readDouble() : 0;
1767 if (dump && read_value && set_value)
1768 dumpElementln(" " + field_name + ": " + value);
1769 if (set_value)
1770 real_field.setDoubleField(obj, value);
1771 break;
1773 case 'F':
1775 float value =
1776 read_value ? this.realInputStream.readFloat() : 0;
1777 if (dump && read_value && set_value)
1778 dumpElementln(" " + field_name + ": " + value);
1779 if (set_value)
1780 real_field.setFloatField(obj, value);
1781 break;
1783 case 'I':
1785 int value =
1786 read_value ? this.realInputStream.readInt() : 0;
1787 if (dump && read_value && set_value)
1788 dumpElementln(" " + field_name + ": " + value);
1789 if (set_value)
1790 real_field.setIntField(obj, value);
1791 break;
1793 case 'J':
1795 long value =
1796 read_value ? this.realInputStream.readLong() : 0;
1797 if (dump && read_value && set_value)
1798 dumpElementln(" " + field_name + ": " + value);
1799 if (set_value)
1800 real_field.setLongField(obj, value);
1801 break;
1803 case 'S':
1805 short value =
1806 read_value ? this.realInputStream.readShort() : 0;
1807 if (dump && read_value && set_value)
1808 dumpElementln(" " + field_name + ": " + value);
1809 if (set_value)
1810 real_field.setShortField(obj, value);
1811 break;
1813 case 'L':
1814 case '[':
1816 Object value =
1817 read_value ? readObject() : null;
1818 if (set_value)
1819 real_field.setObjectField(obj, value);
1820 break;
1822 default:
1823 throw new InternalError("Invalid type code: " + type);
1828 // Toggles writing primitive data to block-data buffer.
1829 private boolean setBlockDataMode (boolean on)
1831 boolean oldmode = this.readDataFromBlock;
1832 this.readDataFromBlock = on;
1834 if (on)
1835 this.dataInputStream = this.blockDataInput;
1836 else
1837 this.dataInputStream = this.realInputStream;
1838 return oldmode;
1841 // returns a new instance of REAL_CLASS that has been constructed
1842 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1843 private Object newObject (Class real_class, Constructor constructor)
1844 throws ClassNotFoundException, IOException
1846 if (constructor == null)
1847 throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
1850 return allocateObject(real_class, constructor.getDeclaringClass(), constructor);
1852 catch (InstantiationException e)
1854 throw new ClassNotFoundException
1855 ("Instance of " + real_class + " could not be created");
1859 // runs all registered ObjectInputValidations in prioritized order
1860 // on OBJ
1861 private void invokeValidators() throws InvalidObjectException
1863 Object[] validators = new Object[this.validators.size()];
1864 this.validators.copyInto (validators);
1865 Arrays.sort (validators);
1869 for (int i=0; i < validators.length; i++)
1870 ((ObjectInputValidation)validators[i]).validateObject();
1872 finally
1874 this.validators.removeAllElements();
1878 private void callReadMethod (Method readObject, Class klass, Object obj)
1879 throws ClassNotFoundException, IOException
1883 readObject.invoke(obj, new Object[] { this });
1885 catch (InvocationTargetException x)
1887 /* Rethrow if possible. */
1888 Throwable exception = x.getTargetException();
1889 if (exception instanceof RuntimeException)
1890 throw (RuntimeException) exception;
1891 if (exception instanceof IOException)
1892 throw (IOException) exception;
1893 if (exception instanceof ClassNotFoundException)
1894 throw (ClassNotFoundException) exception;
1896 throw new IOException("Exception thrown from readObject() on " +
1897 klass + ": " + exception.getClass().getName());
1899 catch (Exception x)
1901 throw new IOException("Failure invoking readObject() on " +
1902 klass + ": " + x.getClass().getName());
1905 // Invalidate fields which has been read through readFields.
1906 prereadFields = null;
1909 private native Object allocateObject(Class clazz, Class constr_clazz, Constructor constructor)
1910 throws InstantiationException;
1912 private static final int BUFFER_SIZE = 1024;
1914 private DataInputStream realInputStream;
1915 private DataInputStream dataInputStream;
1916 private DataInputStream blockDataInput;
1917 private int blockDataPosition;
1918 private int blockDataBytes;
1919 private byte[] blockData;
1920 private boolean useSubclassMethod;
1921 private int nextOID;
1922 private boolean resolveEnabled;
1923 private Hashtable objectLookupTable;
1924 private Object currentObject;
1925 private ObjectStreamClass currentObjectStreamClass;
1926 private boolean readDataFromBlock;
1927 private boolean isDeserializing;
1928 private boolean fieldsAlreadyRead;
1929 private Vector validators;
1930 private Hashtable classLookupTable;
1931 private GetField prereadFields;
1933 private ClassLoader callersClassLoader;
1934 private static boolean dump;
1936 // The nesting depth for debugging output
1937 private int depth = 0;
1939 private void dumpElement (String msg)
1941 System.out.print(msg);
1944 private void dumpElementln (String msg)
1946 System.out.println(msg);
1947 for (int i = 0; i < depth; i++)
1948 System.out.print (" ");
1949 System.out.print (Thread.currentThread() + ": ");
1952 static
1954 if (Configuration.INIT_LOAD_LIBRARY)
1956 System.loadLibrary ("javaio");
1960 // used to keep a prioritized list of object validators
1961 private static final class ValidatorAndPriority implements Comparable
1963 int priority;
1964 ObjectInputValidation validator;
1966 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1968 this.priority = priority;
1969 this.validator = validator;
1972 public int compareTo (Object o)
1974 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1975 return this.priority - vap.priority;