1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008
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)
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
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
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. */
42 import gnu.classpath.Pair;
43 import gnu.classpath.VMStackWalker;
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.HashMap;
55 import java.util.Hashtable;
56 import java.util.Iterator;
58 import java.util.TreeSet;
61 * @author Tom Tromey (tromey@redhat.com)
62 * @author Jeroen Frijters (jeroen@frijters.net)
63 * @author Guilhem Lavaux (guilhem@kaffe.org)
64 * @author Michael Koch (konqueror@gmx.de)
65 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
67 public class ObjectInputStream extends InputStream
68 implements ObjectInput, ObjectStreamConstants
71 * Creates a new <code>ObjectInputStream</code> that will do all of
72 * its reading from <code>in</code>. This method also checks
73 * the stream by reading the header information (stream magic number
74 * and stream version).
76 * @exception IOException Reading stream header from underlying
77 * stream cannot be completed.
79 * @exception StreamCorruptedException An invalid stream magic
80 * number or stream version was read from the stream.
82 * @see #readStreamHeader()
84 public ObjectInputStream(InputStream in)
85 throws IOException, StreamCorruptedException
89 String val = System.getProperty("gcj.dumpobjects");
90 if (dump == false && val != null && !val.equals(""))
93 System.out.println ("Serialization debugging enabled");
95 else if (dump == true && (val == null || val.equals("")))
98 System.out.println ("Serialization debugging disabled");
102 this.resolveEnabled = false;
103 this.blockDataPosition = 0;
104 this.blockDataBytes = 0;
105 this.blockData = new byte[BUFFER_SIZE];
106 this.blockDataInput = new DataInputStream(this);
107 this.realInputStream = new DataInputStream(in);
108 this.nextOID = baseWireHandle;
109 handles = new HashMap<Integer,Pair<Boolean,Object>>();
110 this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
111 setBlockDataMode(true);
117 * Returns the next deserialized object read from the underlying stream.
119 * This method can be overriden by a class by implementing
120 * <code>private void readObject (ObjectInputStream)</code>.
122 * If an exception is thrown from this method, the stream is left in
123 * an undefined state. This method can also throw Errors and
124 * RuntimeExceptions if caused by existing readResolve() user code.
126 * @return The object read from the underlying stream.
128 * @exception ClassNotFoundException The class that an object being
129 * read in belongs to cannot be found.
131 * @exception IOException Exception from underlying
132 * <code>InputStream</code>.
134 public final Object readObject()
135 throws ClassNotFoundException, IOException
137 return readObject(true);
142 * Returns the next deserialized object read from the
143 * underlying stream in an unshared manner. Any object
144 * returned by this method will not be returned by
145 * subsequent calls to either this method or {@link #readObject()}.
148 * This behaviour is achieved by:
151 * <li>Marking the handles created by successful calls to this
152 * method, so that future calls to {@link #readObject()} or
153 * {@link #readUnshared()} will throw an {@link ObjectStreamException}
154 * rather than returning the same object reference.</li>
155 * <li>Throwing an {@link ObjectStreamException} if the next
156 * element in the stream is a reference to an earlier object.</li>
159 * @return a reference to the deserialized object.
160 * @throws ClassNotFoundException if the class of the object being
161 * deserialized can not be found.
162 * @throws StreamCorruptedException if information in the stream
164 * @throws ObjectStreamException if the next object has already been
165 * returned by an earlier call to this
166 * method or {@link #readObject()}.
167 * @throws OptionalDataException if primitive data occurs next in the stream.
168 * @throws IOException if an I/O error occurs from the stream.
172 public Object readUnshared()
173 throws IOException, ClassNotFoundException
175 return readObject(false);
179 * Returns the next deserialized object read from the underlying stream.
181 * This method can be overriden by a class by implementing
182 * <code>private void readObject (ObjectInputStream)</code>.
184 * If an exception is thrown from this method, the stream is left in
185 * an undefined state. This method can also throw Errors and
186 * RuntimeExceptions if caused by existing readResolve() user code.
188 * @param shared true if handles created by this call should be shared
190 * @return The object read from the underlying stream.
192 * @exception ClassNotFoundException The class that an object being
193 * read in belongs to cannot be found.
195 * @exception IOException Exception from underlying
196 * <code>InputStream</code>.
198 private final Object readObject(boolean shared)
199 throws ClassNotFoundException, IOException
201 if (this.useSubclassMethod)
202 return readObjectOverride();
205 boolean old_mode = setBlockDataMode(false);
206 byte marker = this.realInputStream.readByte();
211 if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
215 ret_val = parseContent(marker, shared);
219 setBlockDataMode(old_mode);
228 * Handles a content block within the stream, which begins with a marker
229 * byte indicating its type.
231 * @param marker the byte marker.
232 * @param shared true if handles created by this call should be shared
234 * @return an object which represents the parsed content.
235 * @throws ClassNotFoundException if the class of an object being
236 * read in cannot be found.
237 * @throws IOException if invalid data occurs or one is thrown by the
238 * underlying <code>InputStream</code>.
240 private Object parseContent(byte marker, boolean shared)
241 throws ClassNotFoundException, IOException
244 boolean is_consumed = false;
248 case TC_ENDBLOCKDATA:
256 case TC_BLOCKDATALONG:
258 if (marker == TC_BLOCKDATALONG)
259 { if(dump) dumpElementln("BLOCKDATALONG"); }
261 { if(dump) dumpElementln("BLOCKDATA"); }
262 readNextBlock(marker);
267 if(dump) dumpElementln("NULL");
274 if(dump) dumpElement("REFERENCE ");
275 int oid = realInputStream.readInt();
276 if(dump) dumpElementln(Integer.toHexString(oid));
277 ret_val = lookupHandle(oid);
280 InvalidObjectException("References can not be read unshared.");
286 if(dump) dumpElementln("CLASS");
287 ObjectStreamClass osc = (ObjectStreamClass)readObject();
288 Class clazz = osc.forClass();
289 assignNewHandle(clazz,shared);
294 case TC_PROXYCLASSDESC:
296 if(dump) dumpElementln("PROXYCLASS");
299 // The grammar at this point is
300 // TC_PROXYCLASSDESC newHandle proxyClassDescInfo
301 // i.e. we have to assign the handle immediately after
302 // reading the marker.
303 int handle = assignNewHandle("Dummy proxy",shared);
306 int n_intf = this.realInputStream.readInt();
307 String[] intfs = new String[n_intf];
308 for (int i = 0; i < n_intf; i++)
310 intfs[i] = this.realInputStream.readUTF();
313 boolean oldmode = setBlockDataMode(true);
314 Class cl = resolveProxyClass(intfs);
315 setBlockDataMode(oldmode);
317 ObjectStreamClass osc = lookupClass(cl);
318 if (osc.firstNonSerializableParentConstructor == null)
320 osc.realClassIsSerializable = true;
321 osc.fields = osc.fieldMapping = new ObjectStreamField[0];
324 osc.firstNonSerializableParentConstructor =
325 Object.class.getConstructor(new Class[0]);
327 catch (NoSuchMethodException x)
329 throw (InternalError)
330 new InternalError("Object ctor missing").initCause(x);
334 rememberHandle(osc,shared,handle);
339 byte b = this.realInputStream.readByte();
340 if (b != TC_ENDBLOCKDATA)
341 throw new IOException("Data annotated to class was not consumed." + b);
345 ObjectStreamClass superosc = (ObjectStreamClass)readObject();
346 osc.setSuperclass(superosc);
353 ObjectStreamClass osc = readClassDescriptor();
357 byte b = this.realInputStream.readByte();
358 if (b != TC_ENDBLOCKDATA)
359 throw new IOException("Data annotated to class was not consumed." + b);
364 osc.setSuperclass ((ObjectStreamClass)readObject());
371 if(dump) dumpElement("STRING=");
372 String s = this.realInputStream.readUTF();
373 if(dump) dumpElementln(s);
374 ret_val = processResolution(null, s, assignNewHandle(s,shared),
381 if(dump) dumpElement("STRING=");
382 String s = this.realInputStream.readUTFLong();
383 if(dump) dumpElementln(s);
384 ret_val = processResolution(null, s, assignNewHandle(s,shared),
391 if(dump) dumpElementln("ARRAY");
392 ObjectStreamClass osc = (ObjectStreamClass)readObject();
393 Class componentType = osc.forClass().getComponentType();
394 if(dump) dumpElement("ARRAY LENGTH=");
395 int length = this.realInputStream.readInt();
396 if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
397 Object array = Array.newInstance(componentType, length);
398 int handle = assignNewHandle(array,shared);
399 readArrayElements(array, componentType);
401 for (int i = 0, len = Array.getLength(array); i < len; i++)
402 dumpElementln(" ELEMENT[" + i + "]=", Array.get(array, i));
403 ret_val = processResolution(null, array, handle, shared);
409 if(dump) dumpElementln("OBJECT");
410 ObjectStreamClass osc = (ObjectStreamClass)readObject();
411 Class clazz = osc.forClass();
413 if (!osc.realClassIsSerializable)
414 throw new NotSerializableException
415 (clazz + " is not Serializable, and thus cannot be deserialized.");
417 if (osc.realClassIsExternalizable)
419 Externalizable obj = osc.newInstance();
421 int handle = assignNewHandle(obj,shared);
423 boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
425 boolean oldmode = this.readDataFromBlock;
426 if (read_from_blocks)
427 setBlockDataMode(true);
429 obj.readExternal(this);
431 if (read_from_blocks)
433 setBlockDataMode(oldmode);
435 if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
436 throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
439 ret_val = processResolution(osc, obj, handle,shared);
442 } // end if (osc.realClassIsExternalizable)
444 Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
446 int handle = assignNewHandle(obj,shared);
447 Object prevObject = this.currentObject;
448 ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
449 TreeSet<ValidatorAndPriority> prevObjectValidators =
450 this.currentObjectValidators;
452 this.currentObject = obj;
453 this.currentObjectValidators = null;
454 ObjectStreamClass[] hierarchy = hierarchy(clazz);
456 for (int i = 0; i < hierarchy.length; i++)
458 this.currentObjectStreamClass = hierarchy[i];
459 if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
461 // XXX: should initialize fields in classes in the hierarchy
462 // that aren't in the stream
463 // should skip over classes in the stream that aren't in the
464 // real classes hierarchy
466 Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
467 if (readObjectMethod != null)
469 fieldsAlreadyRead = false;
470 boolean oldmode = setBlockDataMode(true);
471 callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
472 setBlockDataMode(oldmode);
476 readFields(obj, currentObjectStreamClass);
479 if (this.currentObjectStreamClass.hasWriteMethod())
481 if(dump) dumpElement("ENDBLOCKDATA? ");
484 /* Read blocks until an end marker */
485 byte writeMarker = this.realInputStream.readByte();
486 while (writeMarker != TC_ENDBLOCKDATA)
488 parseContent(writeMarker, shared);
489 writeMarker = this.realInputStream.readByte();
491 if(dump) dumpElementln("yes");
493 catch (EOFException e)
495 throw (IOException) new IOException
496 ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
501 this.currentObject = prevObject;
502 this.currentObjectStreamClass = prevObjectStreamClass;
503 ret_val = processResolution(osc, obj, handle, shared);
504 if (currentObjectValidators != null)
506 this.currentObjectValidators = prevObjectValidators;
512 if(dump) dumpElementln("RESET");
514 ret_val = readObject();
519 if(dump) dumpElement("EXCEPTION=");
520 Exception e = (Exception)readObject();
521 if(dump) dumpElementln(e.toString());
523 throw new WriteAbortedException("Exception thrown during writing of stream", e);
528 /* TC_ENUM classDesc newHandle enumConstantName */
530 dumpElementln("ENUM=");
531 ObjectStreamClass osc = (ObjectStreamClass) readObject();
532 int enumHandle = assignNewHandle(null, shared);
533 String constantName = (String) readObject();
535 dumpElementln("CONSTANT NAME = " + constantName);
536 Class clazz = osc.forClass();
537 Enum instance = Enum.valueOf(clazz, constantName);
538 rememberHandle(instance, shared, enumHandle);
544 throw new IOException("Unknown marker on stream: " + marker);
550 * This method makes a partial check of types for the fields
551 * contained given in arguments. It checks primitive types of
552 * fields1 against non primitive types of fields2. This method
553 * assumes the two lists has already been sorted according to
554 * the Java specification.
556 * @param name Name of the class owning the given fields.
557 * @param fields1 First list to check.
558 * @param fields2 Second list to check.
559 * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
560 * in the non primitive part in fields2.
562 private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
563 throws InvalidClassException
565 int nonPrimitive = 0;
567 for (nonPrimitive = 0;
568 nonPrimitive < fields1.length
569 && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
573 if (nonPrimitive == fields1.length)
577 ObjectStreamField f1;
578 ObjectStreamField f2;
580 while (i < fields2.length
581 && nonPrimitive < fields1.length)
583 f1 = fields1[nonPrimitive];
586 if (!f2.isPrimitive())
589 int compVal = f1.getName().compareTo (f2.getName());
595 else if (compVal > 0)
601 throw new InvalidClassException
602 ("invalid field type for " + f2.getName() +
603 " in class " + name);
609 * This method reads a class descriptor from the real input stream
610 * and use these data to create a new instance of ObjectStreamClass.
611 * Fields are sorted and ordered for the real read which occurs for
612 * each instance of the described class. Be aware that if you call that
613 * method you must ensure that the stream is synchronized, in the other
614 * case it may be completely desynchronized.
616 * @return A new instance of ObjectStreamClass containing the freshly
617 * created descriptor.
618 * @throws ClassNotFoundException if the required class to build the
619 * descriptor has not been found in the system.
620 * @throws IOException An input/output error occured.
621 * @throws InvalidClassException If there was a compatibility problem
622 * between the class present in the system and the serialized class.
624 protected ObjectStreamClass readClassDescriptor()
625 throws ClassNotFoundException, IOException
627 if(dump) dumpElement("CLASSDESC NAME=");
628 String name = this.realInputStream.readUTF();
629 if(dump) dumpElement(name + "; UID=");
630 long uid = this.realInputStream.readLong ();
631 if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
632 byte flags = this.realInputStream.readByte ();
633 if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
634 short field_count = this.realInputStream.readShort();
635 if(dump) dumpElementln(Short.toString(field_count));
636 ObjectStreamField[] fields = new ObjectStreamField[field_count];
637 ObjectStreamClass osc = new ObjectStreamClass(name, uid,
639 assignNewHandle(osc,true);
641 for (int i = 0; i < field_count; i++)
643 if(dump) dumpElement(" TYPE CODE=");
644 char type_code = (char)this.realInputStream.readByte();
645 if(dump) dumpElement(type_code + "; FIELD NAME=");
646 String field_name = this.realInputStream.readUTF();
647 if(dump) dumpElementln(field_name);
650 // If the type code is an array or an object we must
651 // decode a String here. In the other case we convert
652 // the type code and pass it to ObjectStreamField.
653 // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
654 if (type_code == 'L' || type_code == '[')
655 class_name = (String)readObject();
657 class_name = String.valueOf(type_code);
660 new ObjectStreamField(field_name, class_name);
663 /* Now that fields have been read we may resolve the class
664 * (and read annotation if needed). */
665 Class clazz = resolveClass(osc);
666 ClassLoader loader = clazz.getClassLoader();
667 for (int i = 0; i < field_count; i++)
669 fields[i].resolveType(loader);
671 boolean oldmode = setBlockDataMode(true);
672 osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
673 classLookupTable.put(clazz, osc);
674 setBlockDataMode(oldmode);
676 // find the first non-serializable class in clazz's inheritance hierarchy
677 Class first_nonserial = clazz.getSuperclass();
678 // Maybe it is a primitive class, those don't have a super class,
679 // or Object itself. Otherwise we can keep getting the superclass
680 // till we hit the Object class, or some other non-serializable class.
682 if (first_nonserial == null)
683 first_nonserial = clazz;
685 while (Serializable.class.isAssignableFrom(first_nonserial))
686 first_nonserial = first_nonserial.getSuperclass();
688 final Class local_constructor_class = first_nonserial;
690 osc.firstNonSerializableParentConstructor =
691 (Constructor)AccessController.doPrivileged(new PrivilegedAction()
697 Constructor c = local_constructor_class.
698 getDeclaredConstructor(new Class[0]);
699 if (Modifier.isPrivate(c.getModifiers()))
703 catch (NoSuchMethodException e)
705 // error will be reported later, in newObject()
711 osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
712 osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
714 ObjectStreamField[] stream_fields = osc.fields;
715 ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
716 ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
723 * Check that there is no type inconsistencies between the lists.
724 * A special checking must be done for the two groups: primitive types and
725 * not primitive types.
727 checkTypeConsistency(name, real_fields, stream_fields);
728 checkTypeConsistency(name, stream_fields, real_fields);
731 while (stream_idx < stream_fields.length
732 || real_idx < real_fields.length)
734 ObjectStreamField stream_field = null;
735 ObjectStreamField real_field = null;
737 if (stream_idx == stream_fields.length)
739 real_field = real_fields[real_idx++];
741 else if (real_idx == real_fields.length)
743 stream_field = stream_fields[stream_idx++];
748 real_fields[real_idx].compareTo (stream_fields[stream_idx]);
752 real_field = real_fields[real_idx++];
754 else if (comp_val > 0)
756 stream_field = stream_fields[stream_idx++];
760 stream_field = stream_fields[stream_idx++];
761 real_field = real_fields[real_idx++];
762 if (stream_field.getType() != real_field.getType())
763 throw new InvalidClassException
764 ("invalid field type for " + real_field.getName() +
765 " in class " + name);
769 /* If some of stream_fields does not correspond to any of real_fields,
770 * or the opposite, then fieldmapping will go short.
772 if (map_idx == fieldmapping.length)
774 ObjectStreamField[] newfieldmapping =
775 new ObjectStreamField[fieldmapping.length + 2];
776 System.arraycopy(fieldmapping, 0,
777 newfieldmapping, 0, fieldmapping.length);
778 fieldmapping = newfieldmapping;
780 fieldmapping[map_idx++] = stream_field;
781 fieldmapping[map_idx++] = real_field;
783 osc.fieldMapping = fieldmapping;
789 * Reads the current objects non-transient, non-static fields from
790 * the current class from the underlying output stream.
792 * This method is intended to be called from within a object's
793 * <code>private void readObject (ObjectInputStream)</code>
796 * @exception ClassNotFoundException The class that an object being
797 * read in belongs to cannot be found.
799 * @exception NotActiveException This method was called from a
800 * context other than from the current object's and current class's
801 * <code>private void readObject (ObjectInputStream)</code>
804 * @exception IOException Exception from underlying
805 * <code>OutputStream</code>.
807 public void defaultReadObject()
808 throws ClassNotFoundException, IOException, NotActiveException
810 if (this.currentObject == null || this.currentObjectStreamClass == null)
811 throw new NotActiveException("defaultReadObject called by non-active"
812 + " class and/or object");
814 if (fieldsAlreadyRead)
815 throw new NotActiveException("defaultReadObject called but fields "
816 + "already read from stream (by "
817 + "defaultReadObject or readFields)");
819 boolean oldmode = setBlockDataMode(false);
820 readFields(this.currentObject, this.currentObjectStreamClass);
821 setBlockDataMode(oldmode);
823 fieldsAlreadyRead = true;
828 * Registers a <code>ObjectInputValidation</code> to be carried out
829 * on the object graph currently being deserialized before it is
830 * returned to the original caller of <code>readObject ()</code>.
831 * The order of validation for multiple
832 * <code>ObjectInputValidation</code>s can be controled using
833 * <code>priority</code>. Validators with higher priorities are
836 * @see java.io.ObjectInputValidation
838 * @exception InvalidObjectException <code>validator</code> is
841 * @exception NotActiveException an attempt was made to add a
842 * validator outside of the <code>readObject</code> method of the
843 * object currently being deserialized
845 public void registerValidation(ObjectInputValidation validator,
847 throws InvalidObjectException, NotActiveException
849 if (this.currentObject == null || this.currentObjectStreamClass == null)
850 throw new NotActiveException("registerValidation called by non-active "
851 + "class and/or object");
853 if (validator == null)
854 throw new InvalidObjectException("attempt to add a null "
855 + "ObjectInputValidation object");
857 if (currentObjectValidators == null)
858 currentObjectValidators = new TreeSet<ValidatorAndPriority>();
860 currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
865 * Called when a class is being deserialized. This is a hook to
866 * allow subclasses to read in information written by the
867 * <code>annotateClass (Class)</code> method of an
868 * <code>ObjectOutputStream</code>.
870 * This implementation looks up the active call stack for a
871 * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
872 * it is used to load the class associated with <code>osc</code>,
873 * otherwise, the default system <code>ClassLoader</code> is used.
875 * @exception IOException Exception from underlying
876 * <code>OutputStream</code>.
878 * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
880 protected Class<?> resolveClass(ObjectStreamClass osc)
881 throws ClassNotFoundException, IOException
883 String name = osc.getName();
886 return Class.forName(name, true, currentLoader());
888 catch(ClassNotFoundException x)
890 if (name.equals("void"))
892 else if (name.equals("boolean"))
894 else if (name.equals("byte"))
896 else if (name.equals("char"))
897 return Character.TYPE;
898 else if (name.equals("short"))
900 else if (name.equals("int"))
902 else if (name.equals("long"))
904 else if (name.equals("float"))
906 else if (name.equals("double"))
914 * Returns the most recent user defined ClassLoader on the execution stack
915 * or null if none is found.
917 private ClassLoader currentLoader()
919 return VMStackWalker.firstNonNullClassLoader();
923 * Lookup a class stored in the local hashtable. If it is not
924 * use the global lookup function in ObjectStreamClass to build
925 * the ObjectStreamClass. This method is requested according to
926 * the behaviour detected in the JDK by Kaffe's team.
928 * @param clazz Class to lookup in the hash table or for which
929 * we must build a descriptor.
930 * @return A valid instance of ObjectStreamClass corresponding
931 * to the specified class.
933 private ObjectStreamClass lookupClass(Class clazz)
938 ObjectStreamClass oclazz;
939 oclazz = classLookupTable.get(clazz);
941 return ObjectStreamClass.lookup(clazz);
947 * Reconstruct class hierarchy the same way {@link
948 * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
949 * instead of ObjectStreamClass.lookup.
951 * @param clazz This is the class for which we want the hierarchy.
953 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
954 * represent the class hierarchy for clazz.
956 private ObjectStreamClass[] hierarchy(Class clazz)
958 ObjectStreamClass osc = lookupClass(clazz);
960 return osc == null ? new ObjectStreamClass[0] : osc.hierarchy();
964 * Allows subclasses to resolve objects that are read from the
965 * stream with other objects to be returned in their place. This
966 * method is called the first time each object is encountered.
968 * This method must be enabled before it will be called in the
969 * serialization process.
971 * @exception IOException Exception from underlying
972 * <code>OutputStream</code>.
974 * @see #enableResolveObject(boolean)
976 protected Object resolveObject(Object obj) throws IOException
982 protected Class<?> resolveProxyClass(String[] intfs)
983 throws IOException, ClassNotFoundException
985 ClassLoader cl = currentLoader();
987 Class<?>[] clss = new Class<?>[intfs.length];
990 for (int i = 0; i < intfs.length; i++)
991 clss[i] = Class.forName(intfs[i]);
992 cl = ClassLoader.getSystemClassLoader();
995 for (int i = 0; i < intfs.length; i++)
996 clss[i] = Class.forName(intfs[i], false, cl);
999 return Proxy.getProxyClass(cl, clss);
1001 catch (IllegalArgumentException e)
1003 throw new ClassNotFoundException(null, e);
1008 * If <code>enable</code> is <code>true</code> and this object is
1009 * trusted, then <code>resolveObject (Object)</code> will be called
1010 * in subsequent calls to <code>readObject (Object)</code>.
1011 * Otherwise, <code>resolveObject (Object)</code> will not be called.
1013 * @exception SecurityException This class is not trusted.
1015 protected boolean enableResolveObject (boolean enable)
1016 throws SecurityException
1020 SecurityManager sm = System.getSecurityManager();
1022 sm.checkPermission(new SerializablePermission("enableSubstitution"));
1025 boolean old_val = this.resolveEnabled;
1026 this.resolveEnabled = enable;
1031 * Reads stream magic and stream version information from the
1032 * underlying stream.
1034 * @exception IOException Exception from underlying stream.
1036 * @exception StreamCorruptedException An invalid stream magic
1037 * number or stream version was read from the stream.
1039 protected void readStreamHeader()
1040 throws IOException, StreamCorruptedException
1042 if(dump) dumpElement("STREAM MAGIC ");
1043 if (this.realInputStream.readShort() != STREAM_MAGIC)
1044 throw new StreamCorruptedException("Invalid stream magic number");
1046 if(dump) dumpElementln("STREAM VERSION ");
1047 if (this.realInputStream.readShort() != STREAM_VERSION)
1048 throw new StreamCorruptedException("Invalid stream version number");
1051 public int read() throws IOException
1053 if (this.readDataFromBlock)
1055 if (this.blockDataPosition >= this.blockDataBytes)
1057 return (this.blockData[this.blockDataPosition++] & 0xff);
1060 return this.realInputStream.read();
1063 public int read(byte[] data, int offset, int length) throws IOException
1065 if (this.readDataFromBlock)
1067 int remain = this.blockDataBytes - this.blockDataPosition;
1071 remain = this.blockDataBytes - this.blockDataPosition;
1073 length = Math.min(length, remain);
1074 System.arraycopy(this.blockData, this.blockDataPosition,
1075 data, offset, length);
1076 this.blockDataPosition += length;
1081 return this.realInputStream.read(data, offset, length);
1084 public int available() throws IOException
1086 if (this.readDataFromBlock)
1088 if (this.blockDataPosition >= this.blockDataBytes)
1091 return this.blockDataBytes - this.blockDataPosition;
1094 return this.realInputStream.available();
1097 public void close() throws IOException
1099 this.realInputStream.close();
1102 public boolean readBoolean() throws IOException
1104 boolean switchmode = true;
1105 boolean oldmode = this.readDataFromBlock;
1106 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1109 oldmode = setBlockDataMode (true);
1110 boolean value = this.dataInputStream.readBoolean ();
1112 setBlockDataMode (oldmode);
1116 public byte readByte() throws IOException
1118 boolean switchmode = true;
1119 boolean oldmode = this.readDataFromBlock;
1120 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1123 oldmode = setBlockDataMode(true);
1124 byte value = this.dataInputStream.readByte();
1126 setBlockDataMode(oldmode);
1130 public int readUnsignedByte() throws IOException
1132 boolean switchmode = true;
1133 boolean oldmode = this.readDataFromBlock;
1134 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1137 oldmode = setBlockDataMode(true);
1138 int value = this.dataInputStream.readUnsignedByte();
1140 setBlockDataMode(oldmode);
1144 public short readShort() throws IOException
1146 boolean switchmode = true;
1147 boolean oldmode = this.readDataFromBlock;
1148 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1151 oldmode = setBlockDataMode(true);
1152 short value = this.dataInputStream.readShort();
1154 setBlockDataMode(oldmode);
1158 public int readUnsignedShort() throws IOException
1160 boolean switchmode = true;
1161 boolean oldmode = this.readDataFromBlock;
1162 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1165 oldmode = setBlockDataMode(true);
1166 int value = this.dataInputStream.readUnsignedShort();
1168 setBlockDataMode(oldmode);
1172 public char readChar() throws IOException
1174 boolean switchmode = true;
1175 boolean oldmode = this.readDataFromBlock;
1176 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1179 oldmode = setBlockDataMode(true);
1180 char value = this.dataInputStream.readChar();
1182 setBlockDataMode(oldmode);
1186 public int readInt() throws IOException
1188 boolean switchmode = true;
1189 boolean oldmode = this.readDataFromBlock;
1190 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1193 oldmode = setBlockDataMode(true);
1194 int value = this.dataInputStream.readInt();
1196 setBlockDataMode(oldmode);
1200 public long readLong() throws IOException
1202 boolean switchmode = true;
1203 boolean oldmode = this.readDataFromBlock;
1204 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1207 oldmode = setBlockDataMode(true);
1208 long value = this.dataInputStream.readLong();
1210 setBlockDataMode(oldmode);
1214 public float readFloat() throws IOException
1216 boolean switchmode = true;
1217 boolean oldmode = this.readDataFromBlock;
1218 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1221 oldmode = setBlockDataMode(true);
1222 float value = this.dataInputStream.readFloat();
1224 setBlockDataMode(oldmode);
1228 public double readDouble() throws IOException
1230 boolean switchmode = true;
1231 boolean oldmode = this.readDataFromBlock;
1232 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1235 oldmode = setBlockDataMode(true);
1236 double value = this.dataInputStream.readDouble();
1238 setBlockDataMode(oldmode);
1242 public void readFully(byte data[]) throws IOException
1244 this.dataInputStream.readFully(data);
1247 public void readFully(byte data[], int offset, int size)
1250 this.dataInputStream.readFully(data, offset, size);
1253 public int skipBytes(int len) throws IOException
1255 return this.dataInputStream.skipBytes(len);
1260 * @see java.io.DataInputStream#readLine ()
1262 public String readLine() throws IOException
1264 return this.dataInputStream.readLine();
1267 public String readUTF() throws IOException
1269 return this.dataInputStream.readUTF();
1273 * This class allows a class to specify exactly which fields should
1274 * be read, and what values should be read for these fields.
1276 * XXX: finish up comments
1278 public abstract static class GetField
1280 public abstract ObjectStreamClass getObjectStreamClass();
1282 public abstract boolean defaulted(String name)
1283 throws IOException, IllegalArgumentException;
1285 public abstract boolean get(String name, boolean defvalue)
1286 throws IOException, IllegalArgumentException;
1288 public abstract char get(String name, char defvalue)
1289 throws IOException, IllegalArgumentException;
1291 public abstract byte get(String name, byte defvalue)
1292 throws IOException, IllegalArgumentException;
1294 public abstract short get(String name, short defvalue)
1295 throws IOException, IllegalArgumentException;
1297 public abstract int get(String name, int defvalue)
1298 throws IOException, IllegalArgumentException;
1300 public abstract long get(String name, long defvalue)
1301 throws IOException, IllegalArgumentException;
1303 public abstract float get(String name, float defvalue)
1304 throws IOException, IllegalArgumentException;
1306 public abstract double get(String name, double defvalue)
1307 throws IOException, IllegalArgumentException;
1309 public abstract Object get(String name, Object defvalue)
1310 throws IOException, IllegalArgumentException;
1314 * This method should be called by a method called 'readObject' in the
1315 * deserializing class (if present). It cannot (and should not)be called
1316 * outside of it. Its goal is to read all fields in the real input stream
1317 * and keep them accessible through the {@link GetField} class. Calling
1318 * this method will not alter the deserializing object.
1320 * @return A valid freshly created 'GetField' instance to get access to
1321 * the deserialized stream.
1322 * @throws IOException An input/output exception occured.
1323 * @throws ClassNotFoundException
1324 * @throws NotActiveException
1326 public GetField readFields()
1327 throws IOException, ClassNotFoundException, NotActiveException
1329 if (this.currentObject == null || this.currentObjectStreamClass == null)
1330 throw new NotActiveException("readFields called by non-active class and/or object");
1332 if (prereadFields != null)
1333 return prereadFields;
1335 if (fieldsAlreadyRead)
1336 throw new NotActiveException("readFields called but fields already read from"
1337 + " stream (by defaultReadObject or readFields)");
1339 final ObjectStreamClass clazz = this.currentObjectStreamClass;
1340 final byte[] prim_field_data = new byte[clazz.primFieldSize];
1341 final Object[] objs = new Object[clazz.objectFieldCount];
1343 // Apparently Block data is not used with GetField as per
1344 // empirical evidence against JDK 1.2. Also see Mauve test
1345 // java.io.ObjectInputOutput.Test.GetPutField.
1346 boolean oldmode = setBlockDataMode(false);
1347 readFully(prim_field_data);
1348 for (int i = 0; i < objs.length; ++ i)
1349 objs[i] = readObject();
1350 setBlockDataMode(oldmode);
1352 prereadFields = new GetField()
1354 public ObjectStreamClass getObjectStreamClass()
1359 public boolean defaulted(String name)
1360 throws IOException, IllegalArgumentException
1362 ObjectStreamField f = clazz.getField(name);
1364 /* First if we have a serialized field use the descriptor */
1367 /* It is in serialPersistentFields but setClass tells us
1368 * it should not be set. This value is defaulted.
1370 if (f.isPersistent() && !f.isToSet())
1376 /* This is not a serialized field. There should be
1377 * a default value only if the field really exists.
1381 return (clazz.forClass().getDeclaredField (name) != null);
1383 catch (NoSuchFieldException e)
1385 throw new IllegalArgumentException(e);
1389 public boolean get(String name, boolean defvalue)
1390 throws IOException, IllegalArgumentException
1392 ObjectStreamField field = getField(name, Boolean.TYPE);
1397 return prim_field_data[field.getOffset()] == 0 ? false : true;
1400 public char get(String name, char defvalue)
1401 throws IOException, IllegalArgumentException
1403 ObjectStreamField field = getField(name, Character.TYPE);
1408 int off = field.getOffset();
1410 return (char)(((prim_field_data[off++] & 0xFF) << 8)
1411 | (prim_field_data[off] & 0xFF));
1414 public byte get(String name, byte defvalue)
1415 throws IOException, IllegalArgumentException
1417 ObjectStreamField field = getField(name, Byte.TYPE);
1422 return prim_field_data[field.getOffset()];
1425 public short get(String name, short defvalue)
1426 throws IOException, IllegalArgumentException
1428 ObjectStreamField field = getField(name, Short.TYPE);
1433 int off = field.getOffset();
1435 return (short)(((prim_field_data[off++] & 0xFF) << 8)
1436 | (prim_field_data[off] & 0xFF));
1439 public int get(String name, int defvalue)
1440 throws IOException, IllegalArgumentException
1442 ObjectStreamField field = getField(name, Integer.TYPE);
1447 int off = field.getOffset();
1449 return ((prim_field_data[off++] & 0xFF) << 24)
1450 | ((prim_field_data[off++] & 0xFF) << 16)
1451 | ((prim_field_data[off++] & 0xFF) << 8)
1452 | (prim_field_data[off] & 0xFF);
1455 public long get(String name, long defvalue)
1456 throws IOException, IllegalArgumentException
1458 ObjectStreamField field = getField(name, Long.TYPE);
1463 int off = field.getOffset();
1465 return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1466 | ((prim_field_data[off++] & 0xFFL) << 48)
1467 | ((prim_field_data[off++] & 0xFFL) << 40)
1468 | ((prim_field_data[off++] & 0xFFL) << 32)
1469 | ((prim_field_data[off++] & 0xFF) << 24)
1470 | ((prim_field_data[off++] & 0xFF) << 16)
1471 | ((prim_field_data[off++] & 0xFF) << 8)
1472 | (prim_field_data[off] & 0xFF));
1475 public float get(String name, float defvalue)
1476 throws IOException, IllegalArgumentException
1478 ObjectStreamField field = getField(name, Float.TYPE);
1483 int off = field.getOffset();
1485 return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1486 | ((prim_field_data[off++] & 0xFF) << 16)
1487 | ((prim_field_data[off++] & 0xFF) << 8)
1488 | (prim_field_data[off] & 0xFF));
1491 public double get(String name, double defvalue)
1492 throws IOException, IllegalArgumentException
1494 ObjectStreamField field = getField(name, Double.TYPE);
1499 int off = field.getOffset();
1501 return Double.longBitsToDouble
1502 ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1503 | ((prim_field_data[off++] & 0xFFL) << 48)
1504 | ((prim_field_data[off++] & 0xFFL) << 40)
1505 | ((prim_field_data[off++] & 0xFFL) << 32)
1506 | ((prim_field_data[off++] & 0xFF) << 24)
1507 | ((prim_field_data[off++] & 0xFF) << 16)
1508 | ((prim_field_data[off++] & 0xFF) << 8)
1509 | (prim_field_data[off] & 0xFF)));
1512 public Object get(String name, Object defvalue)
1513 throws IOException, IllegalArgumentException
1515 ObjectStreamField field =
1516 getField(name, defvalue == null ? null : defvalue.getClass ());
1521 return objs[field.getOffset()];
1524 private ObjectStreamField getField(String name, Class type)
1525 throws IllegalArgumentException
1527 ObjectStreamField field = clazz.getField(name);
1528 boolean illegal = false;
1530 // XXX This code is horrible and needs to be rewritten!
1535 Class field_type = field.getType();
1537 if (type == field_type ||
1538 (type == null && !field_type.isPrimitive()))
1545 throw new IllegalArgumentException
1546 ("Field requested is of type "
1547 + field_type.getName()
1548 + ", but requested type was "
1549 + (type == null ? "Object" : type.getName()));
1551 catch (NullPointerException _)
1553 /* Here we catch NullPointerException, because it may
1554 only come from the call 'field.getType()'. If field
1555 is null, we have to return null and classpath ethic
1556 say we must try to avoid 'if (xxx == null)'.
1559 catch (IllegalArgumentException e)
1568 /* If this is an unassigned field we should return
1569 * the default value.
1571 if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1574 /* We do not want to modify transient fields. They should
1579 Field f = clazz.forClass().getDeclaredField(name);
1580 if (Modifier.isTransient(f.getModifiers()))
1581 throw new IllegalArgumentException
1582 ("no such field (non transient) " + name);
1583 if (field == null && f.getType() != type)
1584 throw new IllegalArgumentException
1585 ("Invalid requested type for field " + name);
1587 catch (NoSuchFieldException e)
1590 throw new IllegalArgumentException(e);
1597 fieldsAlreadyRead = true;
1598 return prereadFields;
1602 * Protected constructor that allows subclasses to override
1603 * deserialization. This constructor should be called by subclasses
1604 * that wish to override <code>readObject (Object)</code>. This
1605 * method does a security check <i>NOTE: currently not
1606 * implemented</i>, then sets a flag that informs
1607 * <code>readObject (Object)</code> to call the subclasses
1608 * <code>readObjectOverride (Object)</code> method.
1610 * @see #readObjectOverride()
1612 protected ObjectInputStream()
1613 throws IOException, SecurityException
1615 SecurityManager sec_man = System.getSecurityManager();
1616 if (sec_man != null)
1617 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1618 this.useSubclassMethod = true;
1622 * This method allows subclasses to override the default
1623 * de serialization mechanism provided by
1624 * <code>ObjectInputStream</code>. To make this method be used for
1625 * writing objects, subclasses must invoke the 0-argument
1626 * constructor on this class from their constructor.
1628 * @see #ObjectInputStream()
1630 protected Object readObjectOverride()
1631 throws ClassNotFoundException, IOException, OptionalDataException
1633 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1637 * Assigns the next available handle to <code>obj</code>.
1639 * @param obj The object for which we want a new handle.
1640 * @param shared True if the handle should be shared
1642 * @return A valid handle for the specified object.
1644 private int assignNewHandle(Object obj, boolean shared)
1646 int handle = this.nextOID;
1647 this.nextOID = handle + 1;
1648 rememberHandle(obj,shared,handle);
1653 * Remember the object associated with the given handle.
1655 * @param obj an object
1656 * @param shared true if the reference should be shared
1658 * @param handle a handle, must be >= baseWireHandle
1660 * @see #lookupHandle
1662 private void rememberHandle(Object obj, boolean shared,
1665 handles.put(handle, new Pair<Boolean,Object>(shared, obj));
1669 * Look up the object associated with a given handle.
1671 * @param handle a handle, must be >= baseWireHandle
1672 * @return the object remembered for handle or null if none.
1673 * @throws StreamCorruptedException if the handle is invalid.
1674 * @throws InvalidObjectException if the reference is not shared.
1675 * @see #rememberHandle
1677 private Object lookupHandle(int handle)
1678 throws ObjectStreamException
1680 Pair<Boolean,Object> result = handles.get(handle);
1682 throw new StreamCorruptedException("The handle, " +
1683 Integer.toHexString(handle) +
1685 if (!result.getLeft())
1686 throw new InvalidObjectException("The handle, " +
1687 Integer.toHexString(handle) +
1688 ", is not shared.");
1689 return result.getRight();
1692 private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
1696 if (osc != null && obj instanceof Serializable)
1700 Method m = osc.readResolveMethod;
1703 obj = m.invoke(obj, new Object[] {});
1706 catch (IllegalAccessException ignore)
1709 catch (InvocationTargetException exception)
1711 Throwable cause = exception.getCause();
1712 if (cause instanceof ObjectStreamException)
1713 throw (ObjectStreamException) cause;
1714 else if (cause instanceof RuntimeException)
1715 throw (RuntimeException) cause;
1716 else if (cause instanceof Error)
1717 throw (Error) cause;
1721 if (this.resolveEnabled)
1722 obj = resolveObject(obj);
1724 rememberHandle(obj, shared, handle);
1727 if (obj instanceof byte[])
1728 return ((byte[]) obj).clone();
1729 if (obj instanceof short[])
1730 return ((short[]) obj).clone();
1731 if (obj instanceof int[])
1732 return ((int[]) obj).clone();
1733 if (obj instanceof long[])
1734 return ((long[]) obj).clone();
1735 if (obj instanceof char[])
1736 return ((char[]) obj).clone();
1737 if (obj instanceof boolean[])
1738 return ((boolean[]) obj).clone();
1739 if (obj instanceof float[])
1740 return ((float[]) obj).clone();
1741 if (obj instanceof double[])
1742 return ((double[]) obj).clone();
1743 if (obj instanceof Object[])
1744 return ((Object[]) obj).clone();
1749 private void clearHandles()
1752 this.nextOID = baseWireHandle;
1755 private void readNextBlock() throws IOException
1757 byte marker = this.realInputStream.readByte();
1758 while (marker == TC_RESET)
1760 if(dump) dumpElementln("RESET");
1762 marker = this.realInputStream.readByte();
1764 readNextBlock(marker);
1767 private void readNextBlock(byte marker) throws IOException
1769 if (marker == TC_BLOCKDATA)
1771 if(dump) dumpElement("BLOCK DATA SIZE=");
1772 this.blockDataBytes = this.realInputStream.readUnsignedByte();
1773 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1775 else if (marker == TC_BLOCKDATALONG)
1777 if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1778 this.blockDataBytes = this.realInputStream.readInt();
1779 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1783 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1786 if (this.blockData.length < this.blockDataBytes)
1787 this.blockData = new byte[this.blockDataBytes];
1789 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1790 this.blockDataPosition = 0;
1793 private void readArrayElements (Object array, Class clazz)
1794 throws ClassNotFoundException, IOException
1796 if (clazz.isPrimitive())
1798 if (clazz == Boolean.TYPE)
1800 boolean[] cast_array = (boolean[])array;
1801 for (int i=0; i < cast_array.length; i++)
1802 cast_array[i] = this.realInputStream.readBoolean();
1805 if (clazz == Byte.TYPE)
1807 byte[] cast_array = (byte[])array;
1808 for (int i=0; i < cast_array.length; i++)
1809 cast_array[i] = this.realInputStream.readByte();
1812 if (clazz == Character.TYPE)
1814 char[] cast_array = (char[])array;
1815 for (int i=0; i < cast_array.length; i++)
1816 cast_array[i] = this.realInputStream.readChar();
1819 if (clazz == Double.TYPE)
1821 double[] cast_array = (double[])array;
1822 for (int i=0; i < cast_array.length; i++)
1823 cast_array[i] = this.realInputStream.readDouble();
1826 if (clazz == Float.TYPE)
1828 float[] cast_array = (float[])array;
1829 for (int i=0; i < cast_array.length; i++)
1830 cast_array[i] = this.realInputStream.readFloat();
1833 if (clazz == Integer.TYPE)
1835 int[] cast_array = (int[])array;
1836 for (int i=0; i < cast_array.length; i++)
1837 cast_array[i] = this.realInputStream.readInt();
1840 if (clazz == Long.TYPE)
1842 long[] cast_array = (long[])array;
1843 for (int i=0; i < cast_array.length; i++)
1844 cast_array[i] = this.realInputStream.readLong();
1847 if (clazz == Short.TYPE)
1849 short[] cast_array = (short[])array;
1850 for (int i=0; i < cast_array.length; i++)
1851 cast_array[i] = this.realInputStream.readShort();
1857 Object[] cast_array = (Object[])array;
1858 for (int i=0; i < cast_array.length; i++)
1859 cast_array[i] = readObject();
1863 private void readFields (Object obj, ObjectStreamClass stream_osc)
1864 throws ClassNotFoundException, IOException
1866 ObjectStreamField[] fields = stream_osc.fieldMapping;
1868 for (int i = 0; i < fields.length; i += 2)
1870 ObjectStreamField stream_field = fields[i];
1871 ObjectStreamField real_field = fields[i + 1];
1872 boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1873 boolean set_value = (real_field != null && real_field.isToSet());
1877 if (stream_field != null)
1879 field_name = stream_field.getName();
1880 type = stream_field.getTypeCode();
1884 field_name = real_field.getName();
1885 type = real_field.getTypeCode();
1893 read_value ? this.realInputStream.readBoolean() : false;
1894 if (dump && read_value && set_value)
1895 dumpElementln(" " + field_name + ": " + value);
1897 real_field.setBooleanField(obj, value);
1903 read_value ? this.realInputStream.readByte() : 0;
1904 if (dump && read_value && set_value)
1905 dumpElementln(" " + field_name + ": " + value);
1907 real_field.setByteField(obj, value);
1913 read_value ? this.realInputStream.readChar(): 0;
1914 if (dump && read_value && set_value)
1915 dumpElementln(" " + field_name + ": " + value);
1917 real_field.setCharField(obj, value);
1923 read_value ? this.realInputStream.readDouble() : 0;
1924 if (dump && read_value && set_value)
1925 dumpElementln(" " + field_name + ": " + value);
1927 real_field.setDoubleField(obj, value);
1933 read_value ? this.realInputStream.readFloat() : 0;
1934 if (dump && read_value && set_value)
1935 dumpElementln(" " + field_name + ": " + value);
1937 real_field.setFloatField(obj, value);
1943 read_value ? this.realInputStream.readInt() : 0;
1944 if (dump && read_value && set_value)
1945 dumpElementln(" " + field_name + ": " + value);
1947 real_field.setIntField(obj, value);
1953 read_value ? this.realInputStream.readLong() : 0;
1954 if (dump && read_value && set_value)
1955 dumpElementln(" " + field_name + ": " + value);
1957 real_field.setLongField(obj, value);
1963 read_value ? this.realInputStream.readShort() : 0;
1964 if (dump && read_value && set_value)
1965 dumpElementln(" " + field_name + ": " + value);
1967 real_field.setShortField(obj, value);
1974 read_value ? readObject() : null;
1976 real_field.setObjectField(obj, value);
1980 throw new InternalError("Invalid type code: " + type);
1985 // Toggles writing primitive data to block-data buffer.
1986 private boolean setBlockDataMode (boolean on)
1988 boolean oldmode = this.readDataFromBlock;
1989 this.readDataFromBlock = on;
1992 this.dataInputStream = this.blockDataInput;
1994 this.dataInputStream = this.realInputStream;
1998 // returns a new instance of REAL_CLASS that has been constructed
1999 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
2000 private Object newObject (Class real_class, Constructor constructor)
2001 throws ClassNotFoundException, IOException
2003 if (constructor == null)
2004 throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
2007 return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
2009 catch (InstantiationException e)
2011 throw (ClassNotFoundException) new ClassNotFoundException
2012 ("Instance of " + real_class + " could not be created").initCause(e);
2016 // runs all registered ObjectInputValidations in prioritized order
2018 private void invokeValidators() throws InvalidObjectException
2022 Iterator<ValidatorAndPriority> it = currentObjectValidators.iterator();
2025 ValidatorAndPriority vap = it.next();
2026 ObjectInputValidation validator = vap.validator;
2027 validator.validateObject();
2032 currentObjectValidators = null;
2036 private void callReadMethod (Method readObject, Class klass, Object obj)
2037 throws ClassNotFoundException, IOException
2041 readObject.invoke(obj, new Object[] { this });
2043 catch (InvocationTargetException x)
2045 /* Rethrow if possible. */
2046 Throwable exception = x.getTargetException();
2047 if (exception instanceof RuntimeException)
2048 throw (RuntimeException) exception;
2049 if (exception instanceof IOException)
2050 throw (IOException) exception;
2051 if (exception instanceof ClassNotFoundException)
2052 throw (ClassNotFoundException) exception;
2054 throw (IOException) new IOException(
2055 "Exception thrown from readObject() on " + klass).initCause(x);
2059 throw (IOException) new IOException(
2060 "Failure invoking readObject() on " + klass).initCause(x);
2063 // Invalidate fields which has been read through readFields.
2064 prereadFields = null;
2067 private static final int BUFFER_SIZE = 1024;
2069 private DataInputStream realInputStream;
2070 private DataInputStream dataInputStream;
2071 private DataInputStream blockDataInput;
2072 private int blockDataPosition;
2073 private int blockDataBytes;
2074 private byte[] blockData;
2075 private boolean useSubclassMethod;
2076 private int nextOID;
2077 private boolean resolveEnabled;
2078 private Map<Integer,Pair<Boolean,Object>> handles;
2079 private Object currentObject;
2080 private ObjectStreamClass currentObjectStreamClass;
2081 private TreeSet<ValidatorAndPriority> currentObjectValidators;
2082 private boolean readDataFromBlock;
2083 private boolean fieldsAlreadyRead;
2084 private Hashtable<Class,ObjectStreamClass> classLookupTable;
2085 private GetField prereadFields;
2087 private static boolean dump;
2089 // The nesting depth for debugging output
2090 private int depth = 0;
2092 private static final boolean DEBUG = false;
2094 private void dumpElement (String msg)
2096 System.out.print(msg);
2099 private void dumpElementln (String msg)
2101 System.out.println(msg);
2102 for (int i = 0; i < depth; i++)
2103 System.out.print (" ");
2104 System.out.print (Thread.currentThread() + ": ");
2107 private void dumpElementln (String msg, Object obj)
2111 System.out.print(msg);
2112 if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
2113 System.out.println(obj.getClass());
2115 System.out.println(obj);
2120 for (int i = 0; i < depth; i++)
2121 System.out.print (" ");
2122 System.out.print (Thread.currentThread() + ": ");
2125 // used to keep a prioritized list of object validators
2126 private static final class ValidatorAndPriority implements Comparable
2129 ObjectInputValidation validator;
2131 ValidatorAndPriority (ObjectInputValidation validator, int priority)
2133 this.priority = priority;
2134 this.validator = validator;
2137 public int compareTo (Object o)
2139 ValidatorAndPriority vap = (ValidatorAndPriority)o;
2140 return this.priority - vap.priority;