Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / java / io / ObjectInputStream.java
blob750c6989f25e1052edad2d6a1b282e1284b19613
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.java.io.ObjectIdentityWrapper;
44 import java.lang.reflect.Array;
45 import java.lang.reflect.Constructor;
46 import java.lang.reflect.Field;
47 import java.lang.reflect.InvocationTargetException;
48 import java.lang.reflect.Method;
49 import java.lang.reflect.Modifier;
50 import java.lang.reflect.Proxy;
51 import java.security.AccessController;
52 import java.security.PrivilegedAction;
53 import java.util.Hashtable;
54 import java.util.Iterator;
55 import java.util.TreeSet;
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 (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.blockDataPosition = 0;
95 this.blockDataBytes = 0;
96 this.blockData = new byte[BUFFER_SIZE];
97 this.blockDataInput = new DataInputStream(this);
98 this.realInputStream = new DataInputStream(in);
99 this.nextOID = baseWireHandle;
100 this.objectLookupTable = new Hashtable();
101 this.classLookupTable = new Hashtable();
102 setBlockDataMode(true);
103 readStreamHeader();
108 * Returns the next deserialized object read from the underlying stream.
110 * This method can be overriden by a class by implementing
111 * <code>private void readObject (ObjectInputStream)</code>.
113 * If an exception is thrown from this method, the stream is left in
114 * an undefined state. This method can also throw Errors and
115 * RuntimeExceptions if caused by existing readResolve() user code.
117 * @return The object read from the underlying stream.
119 * @exception ClassNotFoundException The class that an object being
120 * read in belongs to cannot be found.
122 * @exception IOException Exception from underlying
123 * <code>InputStream</code>.
125 public final Object readObject()
126 throws ClassNotFoundException, IOException
128 if (this.useSubclassMethod)
129 return readObjectOverride();
131 Object ret_val;
132 boolean old_mode = setBlockDataMode(false);
133 byte marker = this.realInputStream.readByte();
135 if (DEBUG)
136 depth += 2;
138 if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
142 ret_val = parseContent(marker);
144 finally
146 setBlockDataMode(old_mode);
147 if (DEBUG)
148 depth -= 2;
151 return ret_val;
155 * Handles a content block within the stream, which begins with a marker
156 * byte indicating its type.
158 * @param marker the byte marker.
159 * @return an object which represents the parsed content.
160 * @throws ClassNotFoundException if the class of an object being
161 * read in cannot be found.
162 * @throws IOException if invalid data occurs or one is thrown by the
163 * underlying <code>InputStream</code>.
165 private Object parseContent(byte marker)
166 throws ClassNotFoundException, IOException
168 Object ret_val;
169 boolean is_consumed = false;
171 switch (marker)
173 case TC_ENDBLOCKDATA:
175 ret_val = null;
176 is_consumed = true;
177 break;
180 case TC_BLOCKDATA:
181 case TC_BLOCKDATALONG:
183 if (marker == TC_BLOCKDATALONG)
184 { if(dump) dumpElementln("BLOCKDATALONG"); }
185 else
186 { if(dump) dumpElementln("BLOCKDATA"); }
187 readNextBlock(marker);
190 case TC_NULL:
192 if(dump) dumpElementln("NULL");
193 ret_val = null;
194 break;
197 case TC_REFERENCE:
199 if(dump) dumpElement("REFERENCE ");
200 Integer oid = new Integer(this.realInputStream.readInt());
201 if(dump) dumpElementln(Integer.toHexString(oid.intValue()));
202 ret_val = ((ObjectIdentityWrapper)
203 this.objectLookupTable.get(oid)).object;
204 break;
207 case TC_CLASS:
209 if(dump) dumpElementln("CLASS");
210 ObjectStreamClass osc = (ObjectStreamClass)readObject();
211 Class clazz = osc.forClass();
212 assignNewHandle(clazz);
213 ret_val = clazz;
214 break;
217 case TC_PROXYCLASSDESC:
219 if(dump) dumpElementln("PROXYCLASS");
220 int n_intf = this.realInputStream.readInt();
221 String[] intfs = new String[n_intf];
222 for (int i = 0; i < n_intf; i++)
224 intfs[i] = this.realInputStream.readUTF();
227 boolean oldmode = setBlockDataMode(true);
228 Class cl = resolveProxyClass(intfs);
229 setBlockDataMode(oldmode);
231 ObjectStreamClass osc = lookupClass(cl);
232 if (osc.firstNonSerializableParentConstructor == null)
234 osc.realClassIsSerializable = true;
235 osc.fields = osc.fieldMapping = new ObjectStreamField[0];
238 osc.firstNonSerializableParentConstructor =
239 Object.class.getConstructor(new Class[0]);
241 catch (NoSuchMethodException x)
243 throw (InternalError)
244 new InternalError("Object ctor missing").initCause(x);
247 assignNewHandle(osc);
249 if (!is_consumed)
251 byte b = this.realInputStream.readByte();
252 if (b != TC_ENDBLOCKDATA)
253 throw new IOException("Data annotated to class was not consumed." + b);
255 else
256 is_consumed = false;
257 ObjectStreamClass superosc = (ObjectStreamClass)readObject();
258 osc.setSuperclass(superosc);
259 ret_val = osc;
260 break;
263 case TC_CLASSDESC:
265 ObjectStreamClass osc = readClassDescriptor();
267 if (!is_consumed)
269 byte b = this.realInputStream.readByte();
270 if (b != TC_ENDBLOCKDATA)
271 throw new IOException("Data annotated to class was not consumed." + b);
273 else
274 is_consumed = false;
276 osc.setSuperclass ((ObjectStreamClass)readObject());
277 ret_val = osc;
278 break;
281 case TC_STRING:
282 case TC_LONGSTRING:
284 if(dump) dumpElement("STRING=");
285 String s = this.realInputStream.readUTF();
286 if(dump) dumpElementln(s);
287 ret_val = processResolution(null, s, assignNewHandle(s));
288 break;
291 case TC_ARRAY:
293 if(dump) dumpElementln("ARRAY");
294 ObjectStreamClass osc = (ObjectStreamClass)readObject();
295 Class componentType = osc.forClass().getComponentType();
296 if(dump) dumpElement("ARRAY LENGTH=");
297 int length = this.realInputStream.readInt();
298 if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
299 Object array = Array.newInstance(componentType, length);
300 int handle = assignNewHandle(array);
301 readArrayElements(array, componentType);
302 if(dump)
303 for (int i = 0, len = Array.getLength(array); i < len; i++)
304 dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i));
305 ret_val = processResolution(null, array, handle);
306 break;
309 case TC_OBJECT:
311 if(dump) dumpElementln("OBJECT");
312 ObjectStreamClass osc = (ObjectStreamClass)readObject();
313 Class clazz = osc.forClass();
315 if (!osc.realClassIsSerializable)
316 throw new NotSerializableException
317 (clazz + " is not Serializable, and thus cannot be deserialized.");
319 if (osc.realClassIsExternalizable)
321 Externalizable obj = osc.newInstance();
323 int handle = assignNewHandle(obj);
325 boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
327 boolean oldmode = this.readDataFromBlock;
328 if (read_from_blocks)
329 setBlockDataMode(true);
331 obj.readExternal(this);
333 if (read_from_blocks)
335 setBlockDataMode(oldmode);
336 if (!oldmode)
337 if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
338 throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
341 ret_val = processResolution(osc, obj, handle);
342 break;
344 } // end if (osc.realClassIsExternalizable)
346 Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
348 int handle = assignNewHandle(obj);
349 Object prevObject = this.currentObject;
350 ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
351 TreeSet prevObjectValidators = this.currentObjectValidators;
353 this.currentObject = obj;
354 this.currentObjectValidators = null;
355 ObjectStreamClass[] hierarchy =
356 inputGetObjectStreamClasses(clazz);
358 for (int i = 0; i < hierarchy.length; i++)
360 this.currentObjectStreamClass = hierarchy[i];
361 if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
363 // XXX: should initialize fields in classes in the hierarchy
364 // that aren't in the stream
365 // should skip over classes in the stream that aren't in the
366 // real classes hierarchy
368 Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
369 if (readObjectMethod != null)
371 fieldsAlreadyRead = false;
372 boolean oldmode = setBlockDataMode(true);
373 callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
374 setBlockDataMode(oldmode);
376 else
378 readFields(obj, currentObjectStreamClass);
381 if (this.currentObjectStreamClass.hasWriteMethod())
383 if(dump) dumpElement("ENDBLOCKDATA? ");
386 /* Read blocks until an end marker */
387 byte writeMarker = this.realInputStream.readByte();
388 while (writeMarker != TC_ENDBLOCKDATA)
390 parseContent(writeMarker);
391 writeMarker = this.realInputStream.readByte();
393 if(dump) dumpElementln("yes");
395 catch (EOFException e)
397 throw (IOException) new IOException
398 ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
403 this.currentObject = prevObject;
404 this.currentObjectStreamClass = prevObjectStreamClass;
405 ret_val = processResolution(osc, obj, handle);
406 if (currentObjectValidators != null)
407 invokeValidators();
408 this.currentObjectValidators = prevObjectValidators;
410 break;
413 case TC_RESET:
414 if(dump) dumpElementln("RESET");
415 clearHandles();
416 ret_val = readObject();
417 break;
419 case TC_EXCEPTION:
421 if(dump) dumpElement("EXCEPTION=");
422 Exception e = (Exception)readObject();
423 if(dump) dumpElementln(e.toString());
424 clearHandles();
425 throw new WriteAbortedException("Exception thrown during writing of stream", e);
428 default:
429 throw new IOException("Unknown marker on stream: " + marker);
431 return ret_val;
435 * This method makes a partial check of types for the fields
436 * contained given in arguments. It checks primitive types of
437 * fields1 against non primitive types of fields2. This method
438 * assumes the two lists has already been sorted according to
439 * the Java specification.
441 * @param name Name of the class owning the given fields.
442 * @param fields1 First list to check.
443 * @param fields2 Second list to check.
444 * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
445 * in the non primitive part in fields2.
447 private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
448 throws InvalidClassException
450 int nonPrimitive = 0;
452 for (nonPrimitive = 0;
453 nonPrimitive < fields1.length
454 && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
458 if (nonPrimitive == fields1.length)
459 return;
461 int i = 0;
462 ObjectStreamField f1;
463 ObjectStreamField f2;
465 while (i < fields2.length
466 && nonPrimitive < fields1.length)
468 f1 = fields1[nonPrimitive];
469 f2 = fields2[i];
471 if (!f2.isPrimitive())
472 break;
474 int compVal = f1.getName().compareTo (f2.getName());
476 if (compVal < 0)
478 nonPrimitive++;
480 else if (compVal > 0)
482 i++;
484 else
486 throw new InvalidClassException
487 ("invalid field type for " + f2.getName() +
488 " in class " + name);
494 * This method reads a class descriptor from the real input stream
495 * and use these data to create a new instance of ObjectStreamClass.
496 * Fields are sorted and ordered for the real read which occurs for
497 * each instance of the described class. Be aware that if you call that
498 * method you must ensure that the stream is synchronized, in the other
499 * case it may be completely desynchronized.
501 * @return A new instance of ObjectStreamClass containing the freshly
502 * created descriptor.
503 * @throws ClassNotFoundException if the required class to build the
504 * descriptor has not been found in the system.
505 * @throws IOException An input/output error occured.
506 * @throws InvalidClassException If there was a compatibility problem
507 * between the class present in the system and the serialized class.
509 protected ObjectStreamClass readClassDescriptor()
510 throws ClassNotFoundException, IOException
512 if(dump) dumpElement("CLASSDESC NAME=");
513 String name = this.realInputStream.readUTF();
514 if(dump) dumpElement(name + "; UID=");
515 long uid = this.realInputStream.readLong ();
516 if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
517 byte flags = this.realInputStream.readByte ();
518 if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
519 short field_count = this.realInputStream.readShort();
520 if(dump) dumpElementln(Short.toString(field_count));
521 ObjectStreamField[] fields = new ObjectStreamField[field_count];
522 ObjectStreamClass osc = new ObjectStreamClass(name, uid,
523 flags, fields);
524 assignNewHandle(osc);
526 ClassLoader callersClassLoader = currentLoader();
528 for (int i = 0; i < field_count; i++)
530 if(dump) dumpElement(" TYPE CODE=");
531 char type_code = (char)this.realInputStream.readByte();
532 if(dump) dumpElement(type_code + "; FIELD NAME=");
533 String field_name = this.realInputStream.readUTF();
534 if(dump) dumpElementln(field_name);
535 String class_name;
537 // If the type code is an array or an object we must
538 // decode a String here. In the other case we convert
539 // the type code and pass it to ObjectStreamField.
540 // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
541 if (type_code == 'L' || type_code == '[')
542 class_name = (String)readObject();
543 else
544 class_name = String.valueOf(type_code);
546 fields[i] =
547 new ObjectStreamField(field_name, class_name, callersClassLoader);
550 /* Now that fields have been read we may resolve the class
551 * (and read annotation if needed). */
552 Class clazz = resolveClass(osc);
553 boolean oldmode = setBlockDataMode(true);
554 osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
555 classLookupTable.put(clazz, osc);
556 setBlockDataMode(oldmode);
558 // find the first non-serializable, non-abstract
559 // class in clazz's inheritance hierarchy
560 Class first_nonserial = clazz.getSuperclass();
561 // Maybe it is a primitive class, those don't have a super class,
562 // or Object itself. Otherwise we can keep getting the superclass
563 // till we hit the Object class, or some other non-serializable class.
565 if (first_nonserial == null)
566 first_nonserial = clazz;
567 else
568 while (Serializable.class.isAssignableFrom(first_nonserial)
569 || Modifier.isAbstract(first_nonserial.getModifiers()))
570 first_nonserial = first_nonserial.getSuperclass();
572 final Class local_constructor_class = first_nonserial;
574 osc.firstNonSerializableParentConstructor =
575 (Constructor)AccessController.doPrivileged(new PrivilegedAction()
577 public Object run()
581 Constructor c = local_constructor_class.
582 getDeclaredConstructor(new Class[0]);
583 if (Modifier.isPrivate(c.getModifiers()))
584 return null;
585 return c;
587 catch (NoSuchMethodException e)
589 // error will be reported later, in newObject()
590 return null;
595 osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
596 osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
598 ObjectStreamField[] stream_fields = osc.fields;
599 ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
600 ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
602 int stream_idx = 0;
603 int real_idx = 0;
604 int map_idx = 0;
607 * Check that there is no type inconsistencies between the lists.
608 * A special checking must be done for the two groups: primitive types and
609 * not primitive types.
611 checkTypeConsistency(name, real_fields, stream_fields);
612 checkTypeConsistency(name, stream_fields, real_fields);
615 while (stream_idx < stream_fields.length
616 || real_idx < real_fields.length)
618 ObjectStreamField stream_field = null;
619 ObjectStreamField real_field = null;
621 if (stream_idx == stream_fields.length)
623 real_field = real_fields[real_idx++];
625 else if (real_idx == real_fields.length)
627 stream_field = stream_fields[stream_idx++];
629 else
631 int comp_val =
632 real_fields[real_idx].compareTo (stream_fields[stream_idx]);
634 if (comp_val < 0)
636 real_field = real_fields[real_idx++];
638 else if (comp_val > 0)
640 stream_field = stream_fields[stream_idx++];
642 else
644 stream_field = stream_fields[stream_idx++];
645 real_field = real_fields[real_idx++];
646 if (stream_field.getType() != real_field.getType())
647 throw new InvalidClassException
648 ("invalid field type for " + real_field.getName() +
649 " in class " + name);
653 /* If some of stream_fields does not correspond to any of real_fields,
654 * or the opposite, then fieldmapping will go short.
656 if (map_idx == fieldmapping.length)
658 ObjectStreamField[] newfieldmapping =
659 new ObjectStreamField[fieldmapping.length + 2];
660 System.arraycopy(fieldmapping, 0,
661 newfieldmapping, 0, fieldmapping.length);
662 fieldmapping = newfieldmapping;
664 fieldmapping[map_idx++] = stream_field;
665 fieldmapping[map_idx++] = real_field;
667 osc.fieldMapping = fieldmapping;
669 return osc;
673 * Reads the current objects non-transient, non-static fields from
674 * the current class from the underlying output stream.
676 * This method is intended to be called from within a object's
677 * <code>private void readObject (ObjectInputStream)</code>
678 * method.
680 * @exception ClassNotFoundException The class that an object being
681 * read in belongs to cannot be found.
683 * @exception NotActiveException This method was called from a
684 * context other than from the current object's and current class's
685 * <code>private void readObject (ObjectInputStream)</code>
686 * method.
688 * @exception IOException Exception from underlying
689 * <code>OutputStream</code>.
691 public void defaultReadObject()
692 throws ClassNotFoundException, IOException, NotActiveException
694 if (this.currentObject == null || this.currentObjectStreamClass == null)
695 throw new NotActiveException("defaultReadObject called by non-active"
696 + " class and/or object");
698 if (fieldsAlreadyRead)
699 throw new NotActiveException("defaultReadObject called but fields "
700 + "already read from stream (by "
701 + "defaultReadObject or readFields)");
703 boolean oldmode = setBlockDataMode(false);
704 readFields(this.currentObject, this.currentObjectStreamClass);
705 setBlockDataMode(oldmode);
707 fieldsAlreadyRead = true;
712 * Registers a <code>ObjectInputValidation</code> to be carried out
713 * on the object graph currently being deserialized before it is
714 * returned to the original caller of <code>readObject ()</code>.
715 * The order of validation for multiple
716 * <code>ObjectInputValidation</code>s can be controled using
717 * <code>priority</code>. Validators with higher priorities are
718 * called first.
720 * @see java.io.ObjectInputValidation
722 * @exception InvalidObjectException <code>validator</code> is
723 * <code>null</code>
725 * @exception NotActiveException an attempt was made to add a
726 * validator outside of the <code>readObject</code> method of the
727 * object currently being deserialized
729 public void registerValidation(ObjectInputValidation validator,
730 int priority)
731 throws InvalidObjectException, NotActiveException
733 if (this.currentObject == null || this.currentObjectStreamClass == null)
734 throw new NotActiveException("registerValidation called by non-active "
735 + "class and/or object");
737 if (validator == null)
738 throw new InvalidObjectException("attempt to add a null "
739 + "ObjectInputValidation object");
741 if (currentObjectValidators == null)
742 currentObjectValidators = new TreeSet();
744 currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
749 * Called when a class is being deserialized. This is a hook to
750 * allow subclasses to read in information written by the
751 * <code>annotateClass (Class)</code> method of an
752 * <code>ObjectOutputStream</code>.
754 * This implementation looks up the active call stack for a
755 * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
756 * it is used to load the class associated with <code>osc</code>,
757 * otherwise, the default system <code>ClassLoader</code> is used.
759 * @exception IOException Exception from underlying
760 * <code>OutputStream</code>.
762 * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
764 protected Class resolveClass(ObjectStreamClass osc)
765 throws ClassNotFoundException, IOException
767 String name = osc.getName();
770 return Class.forName(name, true, currentLoader());
772 catch(ClassNotFoundException x)
774 if (name.equals("void"))
775 return Void.TYPE;
776 else if (name.equals("boolean"))
777 return Boolean.TYPE;
778 else if (name.equals("byte"))
779 return Byte.TYPE;
780 else if (name.equals("char"))
781 return Character.TYPE;
782 else if (name.equals("short"))
783 return Short.TYPE;
784 else if (name.equals("int"))
785 return Integer.TYPE;
786 else if (name.equals("long"))
787 return Long.TYPE;
788 else if (name.equals("float"))
789 return Float.TYPE;
790 else if (name.equals("double"))
791 return Double.TYPE;
792 else
793 throw x;
798 * Returns the most recent user defined ClassLoader on the execution stack
799 * or null if none is found.
801 private ClassLoader currentLoader()
803 return VMObjectInputStream.currentClassLoader();
807 * Lookup a class stored in the local hashtable. If it is not
808 * use the global lookup function in ObjectStreamClass to build
809 * the ObjectStreamClass. This method is requested according to
810 * the behaviour detected in the JDK by Kaffe's team.
812 * @param clazz Class to lookup in the hash table or for which
813 * we must build a descriptor.
814 * @return A valid instance of ObjectStreamClass corresponding
815 * to the specified class.
817 private ObjectStreamClass lookupClass(Class clazz)
819 if (clazz == null)
820 return null;
822 ObjectStreamClass oclazz;
823 oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
824 if (oclazz == null)
825 return ObjectStreamClass.lookup(clazz);
826 else
827 return oclazz;
831 * Reconstruct class hierarchy the same way
832 * {@link java.io.ObjectStreamClass#getObjectStreamClasses(Class)} does
833 * but using lookupClass instead of ObjectStreamClass.lookup. This
834 * dup is necessary localize the lookup table. Hopefully some future
835 * rewritings will be able to prevent this.
837 * @param clazz This is the class for which we want the hierarchy.
839 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
840 * represent the class hierarchy for clazz.
842 private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
844 ObjectStreamClass osc = lookupClass(clazz);
846 if (osc == null)
847 return new ObjectStreamClass[0];
848 else
850 Vector oscs = new Vector();
852 while (osc != null)
854 oscs.addElement(osc);
855 osc = osc.getSuper();
858 int count = oscs.size();
859 ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
861 for (int i = count - 1; i >= 0; i--)
862 sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
864 return sorted_oscs;
869 * Allows subclasses to resolve objects that are read from the
870 * stream with other objects to be returned in their place. This
871 * method is called the first time each object is encountered.
873 * This method must be enabled before it will be called in the
874 * serialization process.
876 * @exception IOException Exception from underlying
877 * <code>OutputStream</code>.
879 * @see #enableResolveObject(boolean)
881 protected Object resolveObject(Object obj) throws IOException
883 return obj;
887 protected Class resolveProxyClass(String[] intfs)
888 throws IOException, ClassNotFoundException
890 ClassLoader cl = currentLoader();
892 Class[] clss = new Class[intfs.length];
893 if(cl == null)
895 for (int i = 0; i < intfs.length; i++)
896 clss[i] = Class.forName(intfs[i]);
897 cl = ClassLoader.getSystemClassLoader();
899 else
900 for (int i = 0; i < intfs.length; i++)
901 clss[i] = Class.forName(intfs[i], false, cl);
902 try
904 return Proxy.getProxyClass(cl, clss);
906 catch (IllegalArgumentException e)
908 throw new ClassNotFoundException(null, e);
913 * If <code>enable</code> is <code>true</code> and this object is
914 * trusted, then <code>resolveObject (Object)</code> will be called
915 * in subsequent calls to <code>readObject (Object)</code>.
916 * Otherwise, <code>resolveObject (Object)</code> will not be called.
918 * @exception SecurityException This class is not trusted.
920 protected boolean enableResolveObject (boolean enable)
921 throws SecurityException
923 if (enable)
925 SecurityManager sm = System.getSecurityManager();
926 if (sm != null)
927 sm.checkPermission(new SerializablePermission("enableSubstitution"));
930 boolean old_val = this.resolveEnabled;
931 this.resolveEnabled = enable;
932 return old_val;
936 * Reads stream magic and stream version information from the
937 * underlying stream.
939 * @exception IOException Exception from underlying stream.
941 * @exception StreamCorruptedException An invalid stream magic
942 * number or stream version was read from the stream.
944 protected void readStreamHeader()
945 throws IOException, StreamCorruptedException
947 if(dump) dumpElement("STREAM MAGIC ");
948 if (this.realInputStream.readShort() != STREAM_MAGIC)
949 throw new StreamCorruptedException("Invalid stream magic number");
951 if(dump) dumpElementln("STREAM VERSION ");
952 if (this.realInputStream.readShort() != STREAM_VERSION)
953 throw new StreamCorruptedException("Invalid stream version number");
956 public int read() throws IOException
958 if (this.readDataFromBlock)
960 if (this.blockDataPosition >= this.blockDataBytes)
961 readNextBlock();
962 return (this.blockData[this.blockDataPosition++] & 0xff);
964 else
965 return this.realInputStream.read();
968 public int read(byte[] data, int offset, int length) throws IOException
970 if (this.readDataFromBlock)
972 int remain = this.blockDataBytes - this.blockDataPosition;
973 if (remain == 0)
975 readNextBlock();
976 remain = this.blockDataBytes - this.blockDataPosition;
978 length = Math.min(length, remain);
979 System.arraycopy(this.blockData, this.blockDataPosition,
980 data, offset, length);
981 this.blockDataPosition += length;
983 return length;
985 else
986 return this.realInputStream.read(data, offset, length);
989 public int available() throws IOException
991 if (this.readDataFromBlock)
993 if (this.blockDataPosition >= this.blockDataBytes)
994 readNextBlock ();
996 return this.blockDataBytes - this.blockDataPosition;
998 else
999 return this.realInputStream.available();
1002 public void close() throws IOException
1004 this.realInputStream.close();
1007 public boolean readBoolean() throws IOException
1009 boolean switchmode = true;
1010 boolean oldmode = this.readDataFromBlock;
1011 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1012 switchmode = false;
1013 if (switchmode)
1014 oldmode = setBlockDataMode (true);
1015 boolean value = this.dataInputStream.readBoolean ();
1016 if (switchmode)
1017 setBlockDataMode (oldmode);
1018 return value;
1021 public byte readByte() throws IOException
1023 boolean switchmode = true;
1024 boolean oldmode = this.readDataFromBlock;
1025 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1026 switchmode = false;
1027 if (switchmode)
1028 oldmode = setBlockDataMode(true);
1029 byte value = this.dataInputStream.readByte();
1030 if (switchmode)
1031 setBlockDataMode(oldmode);
1032 return value;
1035 public int readUnsignedByte() throws IOException
1037 boolean switchmode = true;
1038 boolean oldmode = this.readDataFromBlock;
1039 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1040 switchmode = false;
1041 if (switchmode)
1042 oldmode = setBlockDataMode(true);
1043 int value = this.dataInputStream.readUnsignedByte();
1044 if (switchmode)
1045 setBlockDataMode(oldmode);
1046 return value;
1049 public short readShort() throws IOException
1051 boolean switchmode = true;
1052 boolean oldmode = this.readDataFromBlock;
1053 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1054 switchmode = false;
1055 if (switchmode)
1056 oldmode = setBlockDataMode(true);
1057 short value = this.dataInputStream.readShort();
1058 if (switchmode)
1059 setBlockDataMode(oldmode);
1060 return value;
1063 public int readUnsignedShort() throws IOException
1065 boolean switchmode = true;
1066 boolean oldmode = this.readDataFromBlock;
1067 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1068 switchmode = false;
1069 if (switchmode)
1070 oldmode = setBlockDataMode(true);
1071 int value = this.dataInputStream.readUnsignedShort();
1072 if (switchmode)
1073 setBlockDataMode(oldmode);
1074 return value;
1077 public char readChar() throws IOException
1079 boolean switchmode = true;
1080 boolean oldmode = this.readDataFromBlock;
1081 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1082 switchmode = false;
1083 if (switchmode)
1084 oldmode = setBlockDataMode(true);
1085 char value = this.dataInputStream.readChar();
1086 if (switchmode)
1087 setBlockDataMode(oldmode);
1088 return value;
1091 public int readInt() throws IOException
1093 boolean switchmode = true;
1094 boolean oldmode = this.readDataFromBlock;
1095 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1096 switchmode = false;
1097 if (switchmode)
1098 oldmode = setBlockDataMode(true);
1099 int value = this.dataInputStream.readInt();
1100 if (switchmode)
1101 setBlockDataMode(oldmode);
1102 return value;
1105 public long readLong() throws IOException
1107 boolean switchmode = true;
1108 boolean oldmode = this.readDataFromBlock;
1109 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1110 switchmode = false;
1111 if (switchmode)
1112 oldmode = setBlockDataMode(true);
1113 long value = this.dataInputStream.readLong();
1114 if (switchmode)
1115 setBlockDataMode(oldmode);
1116 return value;
1119 public float readFloat() throws IOException
1121 boolean switchmode = true;
1122 boolean oldmode = this.readDataFromBlock;
1123 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1124 switchmode = false;
1125 if (switchmode)
1126 oldmode = setBlockDataMode(true);
1127 float value = this.dataInputStream.readFloat();
1128 if (switchmode)
1129 setBlockDataMode(oldmode);
1130 return value;
1133 public double readDouble() throws IOException
1135 boolean switchmode = true;
1136 boolean oldmode = this.readDataFromBlock;
1137 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1138 switchmode = false;
1139 if (switchmode)
1140 oldmode = setBlockDataMode(true);
1141 double value = this.dataInputStream.readDouble();
1142 if (switchmode)
1143 setBlockDataMode(oldmode);
1144 return value;
1147 public void readFully(byte data[]) throws IOException
1149 this.dataInputStream.readFully(data);
1152 public void readFully(byte data[], int offset, int size)
1153 throws IOException
1155 this.dataInputStream.readFully(data, offset, size);
1158 public int skipBytes(int len) throws IOException
1160 return this.dataInputStream.skipBytes(len);
1164 * @deprecated
1165 * @see java.io.DataInputStream#readLine ()
1167 public String readLine() throws IOException
1169 return this.dataInputStream.readLine();
1172 public String readUTF() throws IOException
1174 return this.dataInputStream.readUTF();
1178 * This class allows a class to specify exactly which fields should
1179 * be read, and what values should be read for these fields.
1181 * XXX: finish up comments
1183 public abstract static class GetField
1185 public abstract ObjectStreamClass getObjectStreamClass();
1187 public abstract boolean defaulted(String name)
1188 throws IOException, IllegalArgumentException;
1190 public abstract boolean get(String name, boolean defvalue)
1191 throws IOException, IllegalArgumentException;
1193 public abstract char get(String name, char defvalue)
1194 throws IOException, IllegalArgumentException;
1196 public abstract byte get(String name, byte defvalue)
1197 throws IOException, IllegalArgumentException;
1199 public abstract short get(String name, short defvalue)
1200 throws IOException, IllegalArgumentException;
1202 public abstract int get(String name, int defvalue)
1203 throws IOException, IllegalArgumentException;
1205 public abstract long get(String name, long defvalue)
1206 throws IOException, IllegalArgumentException;
1208 public abstract float get(String name, float defvalue)
1209 throws IOException, IllegalArgumentException;
1211 public abstract double get(String name, double defvalue)
1212 throws IOException, IllegalArgumentException;
1214 public abstract Object get(String name, Object defvalue)
1215 throws IOException, IllegalArgumentException;
1219 * This method should be called by a method called 'readObject' in the
1220 * deserializing class (if present). It cannot (and should not)be called
1221 * outside of it. Its goal is to read all fields in the real input stream
1222 * and keep them accessible through the {@link GetField} class. Calling
1223 * this method will not alter the deserializing object.
1225 * @return A valid freshly created 'GetField' instance to get access to
1226 * the deserialized stream.
1227 * @throws IOException An input/output exception occured.
1228 * @throws ClassNotFoundException
1229 * @throws NotActiveException
1231 public GetField readFields()
1232 throws IOException, ClassNotFoundException, NotActiveException
1234 if (this.currentObject == null || this.currentObjectStreamClass == null)
1235 throw new NotActiveException("readFields called by non-active class and/or object");
1237 if (prereadFields != null)
1238 return prereadFields;
1240 if (fieldsAlreadyRead)
1241 throw new NotActiveException("readFields called but fields already read from"
1242 + " stream (by defaultReadObject or readFields)");
1244 final ObjectStreamClass clazz = this.currentObjectStreamClass;
1245 final byte[] prim_field_data = new byte[clazz.primFieldSize];
1246 final Object[] objs = new Object[clazz.objectFieldCount];
1248 // Apparently Block data is not used with GetField as per
1249 // empirical evidence against JDK 1.2. Also see Mauve test
1250 // java.io.ObjectInputOutput.Test.GetPutField.
1251 boolean oldmode = setBlockDataMode(false);
1252 readFully(prim_field_data);
1253 for (int i = 0; i < objs.length; ++ i)
1254 objs[i] = readObject();
1255 setBlockDataMode(oldmode);
1257 prereadFields = new GetField()
1259 public ObjectStreamClass getObjectStreamClass()
1261 return clazz;
1264 public boolean defaulted(String name)
1265 throws IOException, IllegalArgumentException
1267 ObjectStreamField f = clazz.getField(name);
1269 /* First if we have a serialized field use the descriptor */
1270 if (f != null)
1272 /* It is in serialPersistentFields but setClass tells us
1273 * it should not be set. This value is defaulted.
1275 if (f.isPersistent() && !f.isToSet())
1276 return true;
1278 return false;
1281 /* This is not a serialized field. There should be
1282 * a default value only if the field really exists.
1286 return (clazz.forClass().getDeclaredField (name) != null);
1288 catch (NoSuchFieldException e)
1290 throw new IllegalArgumentException(e);
1294 public boolean get(String name, boolean defvalue)
1295 throws IOException, IllegalArgumentException
1297 ObjectStreamField field = getField(name, Boolean.TYPE);
1299 if (field == null)
1300 return defvalue;
1302 return prim_field_data[field.getOffset()] == 0 ? false : true;
1305 public char get(String name, char defvalue)
1306 throws IOException, IllegalArgumentException
1308 ObjectStreamField field = getField(name, Character.TYPE);
1310 if (field == null)
1311 return defvalue;
1313 int off = field.getOffset();
1315 return (char)(((prim_field_data[off++] & 0xFF) << 8)
1316 | (prim_field_data[off] & 0xFF));
1319 public byte get(String name, byte defvalue)
1320 throws IOException, IllegalArgumentException
1322 ObjectStreamField field = getField(name, Byte.TYPE);
1324 if (field == null)
1325 return defvalue;
1327 return prim_field_data[field.getOffset()];
1330 public short get(String name, short defvalue)
1331 throws IOException, IllegalArgumentException
1333 ObjectStreamField field = getField(name, Short.TYPE);
1335 if (field == null)
1336 return defvalue;
1338 int off = field.getOffset();
1340 return (short)(((prim_field_data[off++] & 0xFF) << 8)
1341 | (prim_field_data[off] & 0xFF));
1344 public int get(String name, int defvalue)
1345 throws IOException, IllegalArgumentException
1347 ObjectStreamField field = getField(name, Integer.TYPE);
1349 if (field == null)
1350 return defvalue;
1352 int off = field.getOffset();
1354 return ((prim_field_data[off++] & 0xFF) << 24)
1355 | ((prim_field_data[off++] & 0xFF) << 16)
1356 | ((prim_field_data[off++] & 0xFF) << 8)
1357 | (prim_field_data[off] & 0xFF);
1360 public long get(String name, long defvalue)
1361 throws IOException, IllegalArgumentException
1363 ObjectStreamField field = getField(name, Long.TYPE);
1365 if (field == null)
1366 return defvalue;
1368 int off = field.getOffset();
1370 return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1371 | ((prim_field_data[off++] & 0xFFL) << 48)
1372 | ((prim_field_data[off++] & 0xFFL) << 40)
1373 | ((prim_field_data[off++] & 0xFFL) << 32)
1374 | ((prim_field_data[off++] & 0xFF) << 24)
1375 | ((prim_field_data[off++] & 0xFF) << 16)
1376 | ((prim_field_data[off++] & 0xFF) << 8)
1377 | (prim_field_data[off] & 0xFF));
1380 public float get(String name, float defvalue)
1381 throws IOException, IllegalArgumentException
1383 ObjectStreamField field = getField(name, Float.TYPE);
1385 if (field == null)
1386 return defvalue;
1388 int off = field.getOffset();
1390 return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1391 | ((prim_field_data[off++] & 0xFF) << 16)
1392 | ((prim_field_data[off++] & 0xFF) << 8)
1393 | (prim_field_data[off] & 0xFF));
1396 public double get(String name, double defvalue)
1397 throws IOException, IllegalArgumentException
1399 ObjectStreamField field = getField(name, Double.TYPE);
1401 if (field == null)
1402 return defvalue;
1404 int off = field.getOffset();
1406 return Double.longBitsToDouble
1407 ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1408 | ((prim_field_data[off++] & 0xFFL) << 48)
1409 | ((prim_field_data[off++] & 0xFFL) << 40)
1410 | ((prim_field_data[off++] & 0xFFL) << 32)
1411 | ((prim_field_data[off++] & 0xFF) << 24)
1412 | ((prim_field_data[off++] & 0xFF) << 16)
1413 | ((prim_field_data[off++] & 0xFF) << 8)
1414 | (prim_field_data[off] & 0xFF)));
1417 public Object get(String name, Object defvalue)
1418 throws IOException, IllegalArgumentException
1420 ObjectStreamField field =
1421 getField(name, defvalue == null ? null : defvalue.getClass ());
1423 if (field == null)
1424 return defvalue;
1426 return objs[field.getOffset()];
1429 private ObjectStreamField getField(String name, Class type)
1430 throws IllegalArgumentException
1432 ObjectStreamField field = clazz.getField(name);
1433 boolean illegal = false;
1435 // XXX This code is horrible and needs to be rewritten!
1440 Class field_type = field.getType();
1442 if (type == field_type ||
1443 (type == null && !field_type.isPrimitive()))
1445 /* See defaulted */
1446 return field;
1449 illegal = true;
1450 throw new IllegalArgumentException
1451 ("Field requested is of type "
1452 + field_type.getName()
1453 + ", but requested type was "
1454 + (type == null ? "Object" : type.getName()));
1456 catch (NullPointerException _)
1458 /* Here we catch NullPointerException, because it may
1459 only come from the call 'field.getType()'. If field
1460 is null, we have to return null and classpath ethic
1461 say we must try to avoid 'if (xxx == null)'.
1464 catch (IllegalArgumentException e)
1466 throw e;
1469 return null;
1471 finally
1473 /* If this is an unassigned field we should return
1474 * the default value.
1476 if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1477 return null;
1479 /* We do not want to modify transient fields. They should
1480 * be left to 0.
1484 Field f = clazz.forClass().getDeclaredField(name);
1485 if (Modifier.isTransient(f.getModifiers()))
1486 throw new IllegalArgumentException
1487 ("no such field (non transient) " + name);
1488 if (field == null && f.getType() != type)
1489 throw new IllegalArgumentException
1490 ("Invalid requested type for field " + name);
1492 catch (NoSuchFieldException e)
1494 if (field == null)
1495 throw new IllegalArgumentException(e);
1502 fieldsAlreadyRead = true;
1503 return prereadFields;
1507 * Protected constructor that allows subclasses to override
1508 * deserialization. This constructor should be called by subclasses
1509 * that wish to override <code>readObject (Object)</code>. This
1510 * method does a security check <i>NOTE: currently not
1511 * implemented</i>, then sets a flag that informs
1512 * <code>readObject (Object)</code> to call the subclasses
1513 * <code>readObjectOverride (Object)</code> method.
1515 * @see #readObjectOverride()
1517 protected ObjectInputStream()
1518 throws IOException, SecurityException
1520 SecurityManager sec_man = System.getSecurityManager();
1521 if (sec_man != null)
1522 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1523 this.useSubclassMethod = true;
1527 * This method allows subclasses to override the default
1528 * de serialization mechanism provided by
1529 * <code>ObjectInputStream</code>. To make this method be used for
1530 * writing objects, subclasses must invoke the 0-argument
1531 * constructor on this class from their constructor.
1533 * @see #ObjectInputStream()
1535 protected Object readObjectOverride()
1536 throws ClassNotFoundException, IOException, OptionalDataException
1538 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1542 * Assigns the next available handle to <code>obj</code>.
1544 * @param obj The object for which we want a new handle.
1545 * @return A valid handle for the specified object.
1547 private int assignNewHandle(Object obj)
1549 this.objectLookupTable.put(new Integer(this.nextOID),
1550 new ObjectIdentityWrapper(obj));
1551 return this.nextOID++;
1554 private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
1555 throws IOException
1557 if (osc != null && obj instanceof Serializable)
1561 Method m = osc.readResolveMethod;
1562 if(m != null)
1564 obj = m.invoke(obj, new Object[] {});
1567 catch (IllegalAccessException ignore)
1570 catch (InvocationTargetException exception)
1572 Throwable cause = exception.getCause();
1573 if (cause instanceof ObjectStreamException)
1574 throw (ObjectStreamException) cause;
1575 else if (cause instanceof RuntimeException)
1576 throw (RuntimeException) cause;
1577 else if (cause instanceof Error)
1578 throw (Error) cause;
1582 if (this.resolveEnabled)
1583 obj = resolveObject(obj);
1585 this.objectLookupTable.put(new Integer(handle),
1586 new ObjectIdentityWrapper(obj));
1588 return obj;
1591 private void clearHandles()
1593 this.objectLookupTable.clear();
1594 this.nextOID = baseWireHandle;
1597 private void readNextBlock() throws IOException
1599 readNextBlock(this.realInputStream.readByte());
1602 private void readNextBlock(byte marker) throws IOException
1604 if (marker == TC_BLOCKDATA)
1606 if(dump) dumpElement("BLOCK DATA SIZE=");
1607 this.blockDataBytes = this.realInputStream.readUnsignedByte();
1608 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1610 else if (marker == TC_BLOCKDATALONG)
1612 if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1613 this.blockDataBytes = this.realInputStream.readInt();
1614 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1616 else
1618 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1621 if (this.blockData.length < this.blockDataBytes)
1622 this.blockData = new byte[this.blockDataBytes];
1624 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1625 this.blockDataPosition = 0;
1628 private void readArrayElements (Object array, Class clazz)
1629 throws ClassNotFoundException, IOException
1631 if (clazz.isPrimitive())
1633 if (clazz == Boolean.TYPE)
1635 boolean[] cast_array = (boolean[])array;
1636 for (int i=0; i < cast_array.length; i++)
1637 cast_array[i] = this.realInputStream.readBoolean();
1638 return;
1640 if (clazz == Byte.TYPE)
1642 byte[] cast_array = (byte[])array;
1643 for (int i=0; i < cast_array.length; i++)
1644 cast_array[i] = this.realInputStream.readByte();
1645 return;
1647 if (clazz == Character.TYPE)
1649 char[] cast_array = (char[])array;
1650 for (int i=0; i < cast_array.length; i++)
1651 cast_array[i] = this.realInputStream.readChar();
1652 return;
1654 if (clazz == Double.TYPE)
1656 double[] cast_array = (double[])array;
1657 for (int i=0; i < cast_array.length; i++)
1658 cast_array[i] = this.realInputStream.readDouble();
1659 return;
1661 if (clazz == Float.TYPE)
1663 float[] cast_array = (float[])array;
1664 for (int i=0; i < cast_array.length; i++)
1665 cast_array[i] = this.realInputStream.readFloat();
1666 return;
1668 if (clazz == Integer.TYPE)
1670 int[] cast_array = (int[])array;
1671 for (int i=0; i < cast_array.length; i++)
1672 cast_array[i] = this.realInputStream.readInt();
1673 return;
1675 if (clazz == Long.TYPE)
1677 long[] cast_array = (long[])array;
1678 for (int i=0; i < cast_array.length; i++)
1679 cast_array[i] = this.realInputStream.readLong();
1680 return;
1682 if (clazz == Short.TYPE)
1684 short[] cast_array = (short[])array;
1685 for (int i=0; i < cast_array.length; i++)
1686 cast_array[i] = this.realInputStream.readShort();
1687 return;
1690 else
1692 Object[] cast_array = (Object[])array;
1693 for (int i=0; i < cast_array.length; i++)
1694 cast_array[i] = readObject();
1698 private void readFields (Object obj, ObjectStreamClass stream_osc)
1699 throws ClassNotFoundException, IOException
1701 ObjectStreamField[] fields = stream_osc.fieldMapping;
1703 for (int i = 0; i < fields.length; i += 2)
1705 ObjectStreamField stream_field = fields[i];
1706 ObjectStreamField real_field = fields[i + 1];
1707 boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1708 boolean set_value = (real_field != null && real_field.isToSet());
1709 String field_name;
1710 char type;
1712 if (stream_field != null)
1714 field_name = stream_field.getName();
1715 type = stream_field.getTypeCode();
1717 else
1719 field_name = real_field.getName();
1720 type = real_field.getTypeCode();
1723 switch(type)
1725 case 'Z':
1727 boolean value =
1728 read_value ? this.realInputStream.readBoolean() : false;
1729 if (dump && read_value && set_value)
1730 dumpElementln(" " + field_name + ": " + value);
1731 if (set_value)
1732 real_field.setBooleanField(obj, value);
1733 break;
1735 case 'B':
1737 byte value =
1738 read_value ? this.realInputStream.readByte() : 0;
1739 if (dump && read_value && set_value)
1740 dumpElementln(" " + field_name + ": " + value);
1741 if (set_value)
1742 real_field.setByteField(obj, value);
1743 break;
1745 case 'C':
1747 char value =
1748 read_value ? this.realInputStream.readChar(): 0;
1749 if (dump && read_value && set_value)
1750 dumpElementln(" " + field_name + ": " + value);
1751 if (set_value)
1752 real_field.setCharField(obj, value);
1753 break;
1755 case 'D':
1757 double value =
1758 read_value ? this.realInputStream.readDouble() : 0;
1759 if (dump && read_value && set_value)
1760 dumpElementln(" " + field_name + ": " + value);
1761 if (set_value)
1762 real_field.setDoubleField(obj, value);
1763 break;
1765 case 'F':
1767 float value =
1768 read_value ? this.realInputStream.readFloat() : 0;
1769 if (dump && read_value && set_value)
1770 dumpElementln(" " + field_name + ": " + value);
1771 if (set_value)
1772 real_field.setFloatField(obj, value);
1773 break;
1775 case 'I':
1777 int value =
1778 read_value ? this.realInputStream.readInt() : 0;
1779 if (dump && read_value && set_value)
1780 dumpElementln(" " + field_name + ": " + value);
1781 if (set_value)
1782 real_field.setIntField(obj, value);
1783 break;
1785 case 'J':
1787 long value =
1788 read_value ? this.realInputStream.readLong() : 0;
1789 if (dump && read_value && set_value)
1790 dumpElementln(" " + field_name + ": " + value);
1791 if (set_value)
1792 real_field.setLongField(obj, value);
1793 break;
1795 case 'S':
1797 short value =
1798 read_value ? this.realInputStream.readShort() : 0;
1799 if (dump && read_value && set_value)
1800 dumpElementln(" " + field_name + ": " + value);
1801 if (set_value)
1802 real_field.setShortField(obj, value);
1803 break;
1805 case 'L':
1806 case '[':
1808 Object value =
1809 read_value ? readObject() : null;
1810 if (set_value)
1811 real_field.setObjectField(obj, value);
1812 break;
1814 default:
1815 throw new InternalError("Invalid type code: " + type);
1820 // Toggles writing primitive data to block-data buffer.
1821 private boolean setBlockDataMode (boolean on)
1823 boolean oldmode = this.readDataFromBlock;
1824 this.readDataFromBlock = on;
1826 if (on)
1827 this.dataInputStream = this.blockDataInput;
1828 else
1829 this.dataInputStream = this.realInputStream;
1830 return oldmode;
1833 // returns a new instance of REAL_CLASS that has been constructed
1834 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1835 private Object newObject (Class real_class, Constructor constructor)
1836 throws ClassNotFoundException, IOException
1838 if (constructor == null)
1839 throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
1842 return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
1844 catch (InstantiationException e)
1846 throw (ClassNotFoundException) new ClassNotFoundException
1847 ("Instance of " + real_class + " could not be created").initCause(e);
1851 // runs all registered ObjectInputValidations in prioritized order
1852 // on OBJ
1853 private void invokeValidators() throws InvalidObjectException
1857 Iterator it = currentObjectValidators.iterator();
1858 while(it.hasNext())
1860 ValidatorAndPriority vap = (ValidatorAndPriority) it.next();
1861 ObjectInputValidation validator = vap.validator;
1862 validator.validateObject();
1865 finally
1867 currentObjectValidators = null;
1871 private void callReadMethod (Method readObject, Class klass, Object obj)
1872 throws ClassNotFoundException, IOException
1876 readObject.invoke(obj, new Object[] { this });
1878 catch (InvocationTargetException x)
1880 /* Rethrow if possible. */
1881 Throwable exception = x.getTargetException();
1882 if (exception instanceof RuntimeException)
1883 throw (RuntimeException) exception;
1884 if (exception instanceof IOException)
1885 throw (IOException) exception;
1886 if (exception instanceof ClassNotFoundException)
1887 throw (ClassNotFoundException) exception;
1889 throw (IOException) new IOException(
1890 "Exception thrown from readObject() on " + klass).initCause(x);
1892 catch (Exception x)
1894 throw (IOException) new IOException(
1895 "Failure invoking readObject() on " + klass).initCause(x);
1898 // Invalidate fields which has been read through readFields.
1899 prereadFields = null;
1902 private static final int BUFFER_SIZE = 1024;
1904 private DataInputStream realInputStream;
1905 private DataInputStream dataInputStream;
1906 private DataInputStream blockDataInput;
1907 private int blockDataPosition;
1908 private int blockDataBytes;
1909 private byte[] blockData;
1910 private boolean useSubclassMethod;
1911 private int nextOID;
1912 private boolean resolveEnabled;
1913 private Hashtable objectLookupTable;
1914 private Object currentObject;
1915 private ObjectStreamClass currentObjectStreamClass;
1916 private TreeSet currentObjectValidators;
1917 private boolean readDataFromBlock;
1918 private boolean fieldsAlreadyRead;
1919 private Hashtable classLookupTable;
1920 private GetField prereadFields;
1922 private static boolean dump;
1924 // The nesting depth for debugging output
1925 private int depth = 0;
1927 private static final boolean DEBUG = false;
1929 private void dumpElement (String msg)
1931 System.out.print(msg);
1934 private void dumpElementln (String msg)
1936 System.out.println(msg);
1937 for (int i = 0; i < depth; i++)
1938 System.out.print (" ");
1939 System.out.print (Thread.currentThread() + ": ");
1942 // used to keep a prioritized list of object validators
1943 private static final class ValidatorAndPriority implements Comparable
1945 int priority;
1946 ObjectInputValidation validator;
1948 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1950 this.priority = priority;
1951 this.validator = validator;
1954 public int compareTo (Object o)
1956 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1957 return this.priority - vap.priority;