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)
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.Configuration;
43 import gnu.java.io.ObjectIdentityWrapper;
45 import java.lang.reflect.Array;
46 import java.lang.reflect.Constructor;
47 import java.lang.reflect.Field;
48 import java.lang.reflect.InvocationTargetException;
49 import java.lang.reflect.Method;
50 import java.lang.reflect.Modifier;
51 import java.lang.reflect.Proxy;
52 import java.security.AccessController;
53 import java.security.PrivilegedAction;
54 import java.util.Arrays;
55 import java.util.Hashtable;
56 import java.util.Vector;
58 public class ObjectInputStream extends InputStream
59 implements ObjectInput, ObjectStreamConstants
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
80 String val = System.getProperty("gcj.dumpobjects");
81 if (dump == false && val != null && !val.equals(""))
84 System.out.println ("Serialization debugging enabled");
86 else if (dump == true && (val == null || val.equals("")))
89 System.out.println ("Serialization debugging disabled");
93 this.resolveEnabled = false;
94 this.isDeserializing = false;
95 this.blockDataPosition = 0;
96 this.blockDataBytes = 0;
97 this.blockData = new byte[BUFFER_SIZE];
98 this.blockDataInput = new DataInputStream(this);
99 this.realInputStream = new DataInputStream(in);
100 this.nextOID = baseWireHandle;
101 this.objectLookupTable = new Hashtable();
102 this.validators = new Vector();
103 this.classLookupTable = new Hashtable();
104 setBlockDataMode(true);
110 * Returns the next deserialized object read from the underlying stream.
112 * This method can be overriden by a class by implementing
113 * <code>private void readObject (ObjectInputStream)</code>.
115 * If an exception is thrown from this method, the stream is left in
116 * an undefined state.
118 * @exception ClassNotFoundException The class that an object being
119 * read in belongs to cannot be found.
121 * @exception IOException Exception from underlying
122 * <code>InputStream</code>.
124 public final Object readObject() throws ClassNotFoundException, IOException
126 if (this.useSubclassMethod)
127 return readObjectOverride();
129 boolean was_deserializing;
132 was_deserializing = this.isDeserializing;
134 boolean is_consumed = false;
135 boolean old_mode = setBlockDataMode(false);
137 this.isDeserializing = true;
139 byte marker = this.realInputStream.readByte();
143 if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
149 case TC_ENDBLOCKDATA:
157 case TC_BLOCKDATALONG:
159 if (marker == TC_BLOCKDATALONG)
160 { if(dump) dumpElementln("BLOCKDATALONG"); }
162 { if(dump) dumpElementln("BLOCKDATA"); }
163 readNextBlock(marker);
164 throw new StreamCorruptedException("Unexpected blockData");
169 if(dump) dumpElementln("NULL");
176 if(dump) dumpElement("REFERENCE ");
177 Integer oid = new Integer(this.realInputStream.readInt());
178 if(dump) dumpElementln(Integer.toHexString(oid.intValue()));
179 ret_val = ((ObjectIdentityWrapper)
180 this.objectLookupTable.get(oid)).object;
186 if(dump) dumpElementln("CLASS");
187 ObjectStreamClass osc = (ObjectStreamClass)readObject();
188 Class clazz = osc.forClass();
189 assignNewHandle(clazz);
194 case TC_PROXYCLASSDESC:
196 if(dump) dumpElementln("PROXYCLASS");
197 int n_intf = this.realInputStream.readInt();
198 String[] intfs = new String[n_intf];
199 for (int i = 0; i < n_intf; i++)
201 intfs[i] = this.realInputStream.readUTF();
202 System.out.println(intfs[i]);
205 boolean oldmode = setBlockDataMode(true);
206 Class cl = resolveProxyClass(intfs);
207 setBlockDataMode(oldmode);
209 ObjectStreamClass osc = lookupClass(cl);
210 assignNewHandle(osc);
214 byte b = this.realInputStream.readByte();
215 if (b != TC_ENDBLOCKDATA)
216 throw new IOException("Data annotated to class was not consumed." + b);
220 ObjectStreamClass superosc = (ObjectStreamClass)readObject();
221 osc.setSuperclass(superosc);
228 ObjectStreamClass osc = readClassDescriptor();
232 byte b = this.realInputStream.readByte();
233 if (b != TC_ENDBLOCKDATA)
234 throw new IOException("Data annotated to class was not consumed." + b);
239 osc.setSuperclass ((ObjectStreamClass)readObject());
247 if(dump) dumpElement("STRING=");
248 String s = this.realInputStream.readUTF();
249 if(dump) dumpElementln(s);
250 ret_val = processResolution(null, s, assignNewHandle(s));
256 if(dump) dumpElementln("ARRAY");
257 ObjectStreamClass osc = (ObjectStreamClass)readObject();
258 Class componentType = osc.forClass().getComponentType();
259 if(dump) dumpElement("ARRAY LENGTH=");
260 int length = this.realInputStream.readInt();
261 if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
262 Object array = Array.newInstance(componentType, length);
263 int handle = assignNewHandle(array);
264 readArrayElements(array, componentType);
266 for (int i = 0, len = Array.getLength(array); i < len; i++)
267 dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i));
268 ret_val = processResolution(null, array, handle);
274 if(dump) dumpElementln("OBJECT");
275 ObjectStreamClass osc = (ObjectStreamClass)readObject();
276 Class clazz = osc.forClass();
278 if (!osc.realClassIsSerializable)
279 throw new NotSerializableException
280 (clazz + " is not Serializable, and thus cannot be deserialized.");
282 if (osc.realClassIsExternalizable)
284 Externalizable obj = osc.newInstance();
286 int handle = assignNewHandle(obj);
288 boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
290 boolean oldmode = this.readDataFromBlock;
291 if (read_from_blocks)
292 setBlockDataMode(true);
294 obj.readExternal(this);
296 if (read_from_blocks)
298 setBlockDataMode(oldmode);
300 if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
301 throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
304 ret_val = processResolution(osc, obj, handle);
306 } // end if (osc.realClassIsExternalizable)
308 Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
310 int handle = assignNewHandle(obj);
311 Object prevObject = this.currentObject;
312 ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
314 this.currentObject = obj;
315 ObjectStreamClass[] hierarchy =
316 inputGetObjectStreamClasses(clazz);
318 for (int i = 0; i < hierarchy.length; i++)
320 this.currentObjectStreamClass = hierarchy[i];
322 if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
324 // XXX: should initialize fields in classes in the hierarchy
325 // that aren't in the stream
326 // should skip over classes in the stream that aren't in the
327 // real classes hierarchy
329 Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
330 if (readObjectMethod != null)
332 fieldsAlreadyRead = false;
333 boolean oldmode = setBlockDataMode(true);
334 callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
335 setBlockDataMode(oldmode);
339 readFields(obj, currentObjectStreamClass);
342 if (this.currentObjectStreamClass.hasWriteMethod())
344 if(dump) dumpElement("ENDBLOCKDATA? ");
347 // FIXME: XXX: This try block is to
348 // catch EOF which is thrown for some
349 // objects. That indicates a bug in
352 if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
353 throw new IOException
354 ("No end of block data seen for class with readObject (ObjectInputStream) method.");
355 if(dump) dumpElementln("yes");
357 // catch (EOFException e)
359 // if(dump) dumpElementln("no, got EOFException");
361 catch (IOException e)
363 if(dump) dumpElementln("no, got IOException");
368 this.currentObject = prevObject;
369 this.currentObjectStreamClass = prevObjectStreamClass;
370 ret_val = processResolution(osc, obj, handle);
376 if(dump) dumpElementln("RESET");
378 ret_val = readObject();
383 if(dump) dumpElement("EXCEPTION=");
384 Exception e = (Exception)readObject();
385 if(dump) dumpElementln(e.toString());
387 throw new WriteAbortedException("Exception thrown during writing of stream", e);
391 throw new IOException("Unknown marker on stream: " + marker);
396 setBlockDataMode(old_mode);
398 this.isDeserializing = was_deserializing;
402 if (! was_deserializing)
404 if (validators.size() > 0)
413 * This method makes a partial check of types for the fields
414 * contained given in arguments. It checks primitive types of
415 * fields1 against non primitive types of fields2. This method
416 * assumes the two lists has already been sorted according to
417 * the Java specification.
419 * @param name Name of the class owning the given fields.
420 * @param fields1 First list to check.
421 * @param fields2 Second list to check.
422 * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
423 * in the non primitive part in fields2.
425 private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
426 throws InvalidClassException
428 int nonPrimitive = 0;
430 for (nonPrimitive = 0;
431 nonPrimitive < fields1.length
432 && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
436 if (nonPrimitive == fields1.length)
440 ObjectStreamField f1;
441 ObjectStreamField f2;
443 while (i < fields2.length
444 && nonPrimitive < fields1.length)
446 f1 = fields1[nonPrimitive];
449 if (!f2.isPrimitive())
452 int compVal = f1.getName().compareTo (f2.getName());
458 else if (compVal > 0)
464 throw new InvalidClassException
465 ("invalid field type for " + f2.getName() +
466 " in class " + name);
472 * This method reads a class descriptor from the real input stream
473 * and use these data to create a new instance of ObjectStreamClass.
474 * Fields are sorted and ordered for the real read which occurs for
475 * each instance of the described class. Be aware that if you call that
476 * method you must ensure that the stream is synchronized, in the other
477 * case it may be completely desynchronized.
479 * @return A new instance of ObjectStreamClass containing the freshly
480 * created descriptor.
481 * @throws ClassNotFoundException if the required class to build the
482 * descriptor has not been found in the system.
483 * @throws IOException An input/output error occured.
484 * @throws InvalidClassException If there was a compatibility problem
485 * between the class present in the system and the serialized class.
487 protected ObjectStreamClass readClassDescriptor()
488 throws ClassNotFoundException, IOException
490 if(dump) dumpElement("CLASSDESC NAME=");
491 String name = this.realInputStream.readUTF();
492 if(dump) dumpElement(name + "; UID=");
493 long uid = this.realInputStream.readLong ();
494 if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
495 byte flags = this.realInputStream.readByte ();
496 if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
497 short field_count = this.realInputStream.readShort();
498 if(dump) dumpElementln(Short.toString(field_count));
499 ObjectStreamField[] fields = new ObjectStreamField[field_count];
500 ObjectStreamClass osc = new ObjectStreamClass(name, uid,
502 assignNewHandle(osc);
504 if (callersClassLoader == null)
505 callersClassLoader = currentLoader();
507 for (int i = 0; i < field_count; i++)
509 if(dump) dumpElement(" TYPE CODE=");
510 char type_code = (char)this.realInputStream.readByte();
511 if(dump) dumpElement(type_code + "; FIELD NAME=");
512 String field_name = this.realInputStream.readUTF();
513 if(dump) dumpElementln(field_name);
516 // If the type code is an array or an object we must
517 // decode a String here. In the other case we convert
518 // the type code and pass it to ObjectStreamField.
519 // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
520 if (type_code == 'L' || type_code == '[')
521 class_name = (String)readObject();
523 class_name = String.valueOf(type_code);
526 new ObjectStreamField(field_name, class_name, callersClassLoader);
529 /* Now that fields have been read we may resolve the class
530 * (and read annotation if needed). */
534 clazz = resolveClass(osc);
536 catch (ClassNotFoundException cnfe)
538 // Maybe it was an primitive class?
539 if (name.equals("void"))
541 else if (name.equals("boolean"))
542 clazz = Boolean.TYPE;
543 else if (name.equals("byte"))
545 else if (name.equals("short"))
547 else if (name.equals("char"))
548 clazz = Character.TYPE;
549 else if (name.equals("int"))
550 clazz = Integer.TYPE;
551 else if (name.equals("long"))
553 else if (name.equals("float"))
555 else if (name.equals("double"))
561 boolean oldmode = setBlockDataMode(true);
562 osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
563 classLookupTable.put(clazz, osc);
564 setBlockDataMode(oldmode);
566 // find the first non-serializable, non-abstract
567 // class in clazz's inheritance hierarchy
568 Class first_nonserial = clazz.getSuperclass();
569 // Maybe it is a primitive class, those don't have a super class,
570 // or Object itself. Otherwise we can keep getting the superclass
571 // till we hit the Object class, or some other non-serializable class.
573 if (first_nonserial == null)
574 first_nonserial = clazz;
576 while (Serializable.class.isAssignableFrom(first_nonserial)
577 || Modifier.isAbstract(first_nonserial.getModifiers()))
578 first_nonserial = first_nonserial.getSuperclass();
580 final Class local_constructor_class = first_nonserial;
582 osc.firstNonSerializableParentConstructor =
583 (Constructor)AccessController.doPrivileged(new PrivilegedAction()
589 Constructor c = local_constructor_class.
590 getDeclaredConstructor(new Class[0]);
591 if (Modifier.isPrivate(c.getModifiers()))
595 catch (NoSuchMethodException e)
597 // error will be reported later, in newObject()
603 osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
604 osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
606 ObjectStreamField[] stream_fields = osc.fields;
607 ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
608 ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
615 * Check that there is no type inconsistencies between the lists.
616 * A special checking must be done for the two groups: primitive types and
617 * not primitive types.
619 checkTypeConsistency(name, real_fields, stream_fields);
620 checkTypeConsistency(name, stream_fields, real_fields);
623 while (stream_idx < stream_fields.length
624 || real_idx < real_fields.length)
626 ObjectStreamField stream_field = null;
627 ObjectStreamField real_field = null;
629 if (stream_idx == stream_fields.length)
631 real_field = real_fields[real_idx++];
633 else if (real_idx == real_fields.length)
635 stream_field = stream_fields[stream_idx++];
640 real_fields[real_idx].compareTo (stream_fields[stream_idx]);
644 real_field = real_fields[real_idx++];
646 else if (comp_val > 0)
648 stream_field = stream_fields[stream_idx++];
652 stream_field = stream_fields[stream_idx++];
653 real_field = real_fields[real_idx++];
654 if (stream_field.getType() != real_field.getType())
655 throw new InvalidClassException
656 ("invalid field type for " + real_field.getName() +
657 " in class " + name);
661 /* If some of stream_fields does not correspond to any of real_fields,
662 * or the opposite, then fieldmapping will go short.
664 if (map_idx == fieldmapping.length)
666 ObjectStreamField[] newfieldmapping =
667 new ObjectStreamField[fieldmapping.length + 2];
668 System.arraycopy(fieldmapping, 0,
669 newfieldmapping, 0, fieldmapping.length);
670 fieldmapping = newfieldmapping;
672 fieldmapping[map_idx++] = stream_field;
673 fieldmapping[map_idx++] = real_field;
675 osc.fieldMapping = fieldmapping;
681 * Reads the current objects non-transient, non-static fields from
682 * the current class from the underlying output stream.
684 * This method is intended to be called from within a object's
685 * <code>private void readObject (ObjectInputStream)</code>
688 * @exception ClassNotFoundException The class that an object being
689 * read in belongs to cannot be found.
691 * @exception NotActiveException This method was called from a
692 * context other than from the current object's and current class's
693 * <code>private void readObject (ObjectInputStream)</code>
696 * @exception IOException Exception from underlying
697 * <code>OutputStream</code>.
699 public void defaultReadObject()
700 throws ClassNotFoundException, IOException, NotActiveException
702 if (this.currentObject == null || this.currentObjectStreamClass == null)
703 throw new NotActiveException("defaultReadObject called by non-active"
704 + " class and/or object");
706 if (fieldsAlreadyRead)
707 throw new NotActiveException("defaultReadObject called but fields "
708 + "already read from stream (by "
709 + "defaultReadObject or readFields)");
711 boolean oldmode = setBlockDataMode(false);
712 readFields(this.currentObject, this.currentObjectStreamClass);
713 setBlockDataMode(oldmode);
715 fieldsAlreadyRead = true;
720 * Registers a <code>ObjectInputValidation</code> to be carried out
721 * on the object graph currently being deserialized before it is
722 * returned to the original caller of <code>readObject ()</code>.
723 * The order of validation for multiple
724 * <code>ObjectInputValidation</code>s can be controled using
725 * <code>priority</code>. Validators with higher priorities are
728 * @see java.io.ObjectInputValidation
730 * @exception InvalidObjectException <code>validator</code> is
733 * @exception NotActiveException an attempt was made to add a
734 * validator outside of the <code>readObject</code> method of the
735 * object currently being deserialized
737 public void registerValidation(ObjectInputValidation validator,
739 throws InvalidObjectException, NotActiveException
741 if (this.currentObject == null || this.currentObjectStreamClass == null)
742 throw new NotActiveException("registerValidation called by non-active "
743 + "class and/or object");
745 if (validator == null)
746 throw new InvalidObjectException("attempt to add a null "
747 + "ObjectInputValidation object");
749 this.validators.addElement(new ValidatorAndPriority (validator,
755 * Called when a class is being deserialized. This is a hook to
756 * allow subclasses to read in information written by the
757 * <code>annotateClass (Class)</code> method of an
758 * <code>ObjectOutputStream</code>.
760 * This implementation looks up the active call stack for a
761 * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
762 * it is used to load the class associated with <code>osc</code>,
763 * otherwise, the default system <code>ClassLoader</code> is used.
765 * @exception IOException Exception from underlying
766 * <code>OutputStream</code>.
768 * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
770 protected Class resolveClass(ObjectStreamClass osc)
771 throws ClassNotFoundException, IOException
773 if (callersClassLoader == null)
775 callersClassLoader = currentLoader ();
778 dumpElementln ("CallersClassLoader = " + callersClassLoader);
782 return Class.forName(osc.getName(), true, callersClassLoader);
786 * Returns the most recent user defined ClassLoader on the execution stack
787 * or null if none is found.
789 private ClassLoader currentLoader()
791 return VMObjectInputStream.currentClassLoader();
795 * Lookup a class stored in the local hashtable. If it is not
796 * use the global lookup function in ObjectStreamClass to build
797 * the ObjectStreamClass. This method is requested according to
798 * the behaviour detected in the JDK by Kaffe's team.
800 * @param clazz Class to lookup in the hash table or for which
801 * we must build a descriptor.
802 * @return A valid instance of ObjectStreamClass corresponding
803 * to the specified class.
805 private ObjectStreamClass lookupClass(Class clazz)
810 ObjectStreamClass oclazz;
811 oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
813 return ObjectStreamClass.lookup(clazz);
819 * Reconstruct class hierarchy the same way
820 * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
821 * but using lookupClass instead of ObjectStreamClass.lookup. This
822 * dup is necessary localize the lookup table. Hopefully some future
823 * rewritings will be able to prevent this.
825 * @param clazz This is the class for which we want the hierarchy.
827 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
828 * represent the class hierarchy for clazz.
830 private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
832 ObjectStreamClass osc = lookupClass(clazz);
835 return new ObjectStreamClass[0];
838 Vector oscs = new Vector();
842 oscs.addElement(osc);
843 osc = osc.getSuper();
846 int count = oscs.size();
847 ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
849 for (int i = count - 1; i >= 0; i--)
850 sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
857 * Allows subclasses to resolve objects that are read from the
858 * stream with other objects to be returned in their place. This
859 * method is called the first time each object is encountered.
861 * This method must be enabled before it will be called in the
862 * serialization process.
864 * @exception IOException Exception from underlying
865 * <code>OutputStream</code>.
867 * @see #enableResolveObject(boolean)
869 protected Object resolveObject(Object obj) throws IOException
875 protected Class resolveProxyClass(String[] intfs)
876 throws IOException, ClassNotFoundException
878 ClassLoader cl = currentLoader();
880 Class[] clss = new Class[intfs.length];
883 for (int i = 0; i < intfs.length; i++)
884 clss[i] = Class.forName(intfs[i]);
885 cl = ClassLoader.getSystemClassLoader();
888 for (int i = 0; i < intfs.length; i++)
889 clss[i] = cl.loadClass(intfs[i]);
892 return Proxy.getProxyClass(cl, clss);
894 catch (IllegalArgumentException e)
896 throw new ClassNotFoundException(null, e);
901 * If <code>enable</code> is <code>true</code> and this object is
902 * trusted, then <code>resolveObject (Object)</code> will be called
903 * in subsequent calls to <code>readObject (Object)</code>.
904 * Otherwise, <code>resolveObject (Object)</code> will not be called.
906 * @exception SecurityException This class is not trusted.
908 protected boolean enableResolveObject (boolean enable)
909 throws SecurityException
913 SecurityManager sm = System.getSecurityManager();
915 sm.checkPermission(new SerializablePermission("enableSubstitution"));
918 boolean old_val = this.resolveEnabled;
919 this.resolveEnabled = enable;
924 * Reads stream magic and stream version information from the
927 * @exception IOException Exception from underlying stream.
929 * @exception StreamCorruptedException An invalid stream magic
930 * number or stream version was read from the stream.
932 protected void readStreamHeader()
933 throws IOException, StreamCorruptedException
935 if(dump) dumpElement("STREAM MAGIC ");
936 if (this.realInputStream.readShort() != STREAM_MAGIC)
937 throw new StreamCorruptedException("Invalid stream magic number");
939 if(dump) dumpElementln("STREAM VERSION ");
940 if (this.realInputStream.readShort() != STREAM_VERSION)
941 throw new StreamCorruptedException("Invalid stream version number");
944 public int read() throws IOException
946 if (this.readDataFromBlock)
948 if (this.blockDataPosition >= this.blockDataBytes)
950 return (this.blockData[this.blockDataPosition++] & 0xff);
953 return this.realInputStream.read();
956 public int read(byte[] data, int offset, int length) throws IOException
958 if (this.readDataFromBlock)
960 if (this.blockDataPosition + length > this.blockDataBytes)
962 int remain = this.blockDataBytes - this.blockDataPosition;
965 System.arraycopy(this.blockData, this.blockDataPosition,
966 data, offset, remain);
973 System.arraycopy(this.blockData, this.blockDataPosition,
974 data, offset, length);
975 this.blockDataPosition += length;
980 return this.realInputStream.read(data, offset, length);
983 public int available() throws IOException
985 if (this.readDataFromBlock)
987 if (this.blockDataPosition >= this.blockDataBytes)
990 return this.blockDataBytes - this.blockDataPosition;
993 return this.realInputStream.available();
996 public void close() throws IOException
998 this.realInputStream.close();
1001 public boolean readBoolean() throws IOException
1003 boolean switchmode = true;
1004 boolean oldmode = this.readDataFromBlock;
1005 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1008 oldmode = setBlockDataMode (true);
1009 boolean value = this.dataInputStream.readBoolean ();
1011 setBlockDataMode (oldmode);
1015 public byte readByte() throws IOException
1017 boolean switchmode = true;
1018 boolean oldmode = this.readDataFromBlock;
1019 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1022 oldmode = setBlockDataMode(true);
1023 byte value = this.dataInputStream.readByte();
1025 setBlockDataMode(oldmode);
1029 public int readUnsignedByte() throws IOException
1031 boolean switchmode = true;
1032 boolean oldmode = this.readDataFromBlock;
1033 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1036 oldmode = setBlockDataMode(true);
1037 int value = this.dataInputStream.readUnsignedByte();
1039 setBlockDataMode(oldmode);
1043 public short readShort() throws IOException
1045 boolean switchmode = true;
1046 boolean oldmode = this.readDataFromBlock;
1047 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1050 oldmode = setBlockDataMode(true);
1051 short value = this.dataInputStream.readShort();
1053 setBlockDataMode(oldmode);
1057 public int readUnsignedShort() throws IOException
1059 boolean switchmode = true;
1060 boolean oldmode = this.readDataFromBlock;
1061 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1064 oldmode = setBlockDataMode(true);
1065 int value = this.dataInputStream.readUnsignedShort();
1067 setBlockDataMode(oldmode);
1071 public char readChar() throws IOException
1073 boolean switchmode = true;
1074 boolean oldmode = this.readDataFromBlock;
1075 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1078 oldmode = setBlockDataMode(true);
1079 char value = this.dataInputStream.readChar();
1081 setBlockDataMode(oldmode);
1085 public int readInt() throws IOException
1087 boolean switchmode = true;
1088 boolean oldmode = this.readDataFromBlock;
1089 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1092 oldmode = setBlockDataMode(true);
1093 int value = this.dataInputStream.readInt();
1095 setBlockDataMode(oldmode);
1099 public long readLong() throws IOException
1101 boolean switchmode = true;
1102 boolean oldmode = this.readDataFromBlock;
1103 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1106 oldmode = setBlockDataMode(true);
1107 long value = this.dataInputStream.readLong();
1109 setBlockDataMode(oldmode);
1113 public float readFloat() throws IOException
1115 boolean switchmode = true;
1116 boolean oldmode = this.readDataFromBlock;
1117 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1120 oldmode = setBlockDataMode(true);
1121 float value = this.dataInputStream.readFloat();
1123 setBlockDataMode(oldmode);
1127 public double readDouble() throws IOException
1129 boolean switchmode = true;
1130 boolean oldmode = this.readDataFromBlock;
1131 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1134 oldmode = setBlockDataMode(true);
1135 double value = this.dataInputStream.readDouble();
1137 setBlockDataMode(oldmode);
1141 public void readFully(byte data[]) throws IOException
1143 this.dataInputStream.readFully(data);
1146 public void readFully(byte data[], int offset, int size)
1149 this.dataInputStream.readFully(data, offset, size);
1152 public int skipBytes(int len) throws IOException
1154 return this.dataInputStream.skipBytes(len);
1159 * @see java.io.DataInputStream#readLine ()
1161 public String readLine() throws IOException
1163 return this.dataInputStream.readLine();
1166 public String readUTF() throws IOException
1168 return this.dataInputStream.readUTF();
1172 * This class allows a class to specify exactly which fields should
1173 * be read, and what values should be read for these fields.
1175 * XXX: finish up comments
1177 public abstract static class GetField
1179 public abstract ObjectStreamClass getObjectStreamClass();
1181 public abstract boolean defaulted(String name)
1182 throws IOException, IllegalArgumentException;
1184 public abstract boolean get(String name, boolean defvalue)
1185 throws IOException, IllegalArgumentException;
1187 public abstract char get(String name, char defvalue)
1188 throws IOException, IllegalArgumentException;
1190 public abstract byte get(String name, byte defvalue)
1191 throws IOException, IllegalArgumentException;
1193 public abstract short get(String name, short defvalue)
1194 throws IOException, IllegalArgumentException;
1196 public abstract int get(String name, int defvalue)
1197 throws IOException, IllegalArgumentException;
1199 public abstract long get(String name, long defvalue)
1200 throws IOException, IllegalArgumentException;
1202 public abstract float get(String name, float defvalue)
1203 throws IOException, IllegalArgumentException;
1205 public abstract double get(String name, double defvalue)
1206 throws IOException, IllegalArgumentException;
1208 public abstract Object get(String name, Object defvalue)
1209 throws IOException, IllegalArgumentException;
1213 * This method should be called by a method called 'readObject' in the
1214 * deserializing class (if present). It cannot (and should not)be called
1215 * outside of it. Its goal is to read all fields in the real input stream
1216 * and keep them accessible through the {@link #GetField} class. Calling
1217 * this method will not alter the deserializing object.
1219 * @return A valid freshly created 'GetField' instance to get access to
1220 * the deserialized stream.
1221 * @throws IOException An input/output exception occured.
1222 * @throws ClassNotFoundException
1223 * @throws NotActiveException
1225 public GetField readFields()
1226 throws IOException, ClassNotFoundException, NotActiveException
1228 if (this.currentObject == null || this.currentObjectStreamClass == null)
1229 throw new NotActiveException("readFields called by non-active class and/or object");
1231 if (prereadFields != null)
1232 return prereadFields;
1234 if (fieldsAlreadyRead)
1235 throw new NotActiveException("readFields called but fields already read from"
1236 + " stream (by defaultReadObject or readFields)");
1238 final ObjectStreamClass clazz = this.currentObjectStreamClass;
1239 final byte[] prim_field_data = new byte[clazz.primFieldSize];
1240 final Object[] objs = new Object[clazz.objectFieldCount];
1242 // Apparently Block data is not used with GetField as per
1243 // empirical evidence against JDK 1.2. Also see Mauve test
1244 // java.io.ObjectInputOutput.Test.GetPutField.
1245 boolean oldmode = setBlockDataMode(false);
1246 readFully(prim_field_data);
1247 for (int i = 0; i < objs.length; ++ i)
1248 objs[i] = readObject();
1249 setBlockDataMode(oldmode);
1251 prereadFields = new GetField()
1253 public ObjectStreamClass getObjectStreamClass()
1258 public boolean defaulted(String name)
1259 throws IOException, IllegalArgumentException
1261 ObjectStreamField f = clazz.getField(name);
1263 /* First if we have a serialized field use the descriptor */
1266 /* It is in serialPersistentFields but setClass tells us
1267 * it should not be set. This value is defaulted.
1269 if (f.isPersistent() && !f.isToSet())
1275 /* This is not a serialized field. There should be
1276 * a default value only if the field really exists.
1280 return (clazz.forClass().getDeclaredField (name) != null);
1282 catch (NoSuchFieldException e)
1284 throw new IllegalArgumentException(e.getMessage());
1288 public boolean get(String name, boolean defvalue)
1289 throws IOException, IllegalArgumentException
1291 ObjectStreamField field = getField(name, Boolean.TYPE);
1296 return prim_field_data[field.getOffset()] == 0 ? false : true;
1299 public char get(String name, char defvalue)
1300 throws IOException, IllegalArgumentException
1302 ObjectStreamField field = getField(name, Character.TYPE);
1307 int off = field.getOffset();
1309 return (char)(((prim_field_data[off++] & 0xFF) << 8)
1310 | (prim_field_data[off] & 0xFF));
1313 public byte get(String name, byte defvalue)
1314 throws IOException, IllegalArgumentException
1316 ObjectStreamField field = getField(name, Byte.TYPE);
1321 return prim_field_data[field.getOffset()];
1324 public short get(String name, short defvalue)
1325 throws IOException, IllegalArgumentException
1327 ObjectStreamField field = getField(name, Short.TYPE);
1332 int off = field.getOffset();
1334 return (short)(((prim_field_data[off++] & 0xFF) << 8)
1335 | (prim_field_data[off] & 0xFF));
1338 public int get(String name, int defvalue)
1339 throws IOException, IllegalArgumentException
1341 ObjectStreamField field = getField(name, Integer.TYPE);
1346 int off = field.getOffset();
1348 return ((prim_field_data[off++] & 0xFF) << 24)
1349 | ((prim_field_data[off++] & 0xFF) << 16)
1350 | ((prim_field_data[off++] & 0xFF) << 8)
1351 | (prim_field_data[off] & 0xFF);
1354 public long get(String name, long defvalue)
1355 throws IOException, IllegalArgumentException
1357 ObjectStreamField field = getField(name, Long.TYPE);
1362 int off = field.getOffset();
1364 return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1365 | ((prim_field_data[off++] & 0xFFL) << 48)
1366 | ((prim_field_data[off++] & 0xFFL) << 40)
1367 | ((prim_field_data[off++] & 0xFFL) << 32)
1368 | ((prim_field_data[off++] & 0xFF) << 24)
1369 | ((prim_field_data[off++] & 0xFF) << 16)
1370 | ((prim_field_data[off++] & 0xFF) << 8)
1371 | (prim_field_data[off] & 0xFF));
1374 public float get(String name, float defvalue)
1375 throws IOException, IllegalArgumentException
1377 ObjectStreamField field = getField(name, Float.TYPE);
1382 int off = field.getOffset();
1384 return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1385 | ((prim_field_data[off++] & 0xFF) << 16)
1386 | ((prim_field_data[off++] & 0xFF) << 8)
1387 | (prim_field_data[off] & 0xFF));
1390 public double get(String name, double defvalue)
1391 throws IOException, IllegalArgumentException
1393 ObjectStreamField field = getField(name, Double.TYPE);
1398 int off = field.getOffset();
1400 return Double.longBitsToDouble
1401 ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1402 | ((prim_field_data[off++] & 0xFFL) << 48)
1403 | ((prim_field_data[off++] & 0xFFL) << 40)
1404 | ((prim_field_data[off++] & 0xFFL) << 32)
1405 | ((prim_field_data[off++] & 0xFF) << 24)
1406 | ((prim_field_data[off++] & 0xFF) << 16)
1407 | ((prim_field_data[off++] & 0xFF) << 8)
1408 | (prim_field_data[off] & 0xFF)));
1411 public Object get(String name, Object defvalue)
1412 throws IOException, IllegalArgumentException
1414 ObjectStreamField field =
1415 getField(name, defvalue == null ? null : defvalue.getClass ());
1420 return objs[field.getOffset()];
1423 private ObjectStreamField getField(String name, Class type)
1424 throws IllegalArgumentException
1426 ObjectStreamField field = clazz.getField(name);
1427 boolean illegal = false;
1433 Class field_type = field.getType();
1435 if (type == field_type ||
1436 (type == null && !field_type.isPrimitive()))
1443 throw new IllegalArgumentException
1444 ("Field requested is of type "
1445 + field_type.getName()
1446 + ", but requested type was "
1447 + (type == null ? "Object" : type.getName()));
1449 catch (NullPointerException _)
1451 /* Here we catch NullPointerException, because it may
1452 only come from the call 'field.getType()'. If field
1453 is null, we have to return null and classpath ethic
1454 say we must try to avoid 'if (xxx == null)'.
1457 catch (IllegalArgumentException e)
1466 /* If this is an unassigned field we should return
1467 * the default value.
1469 if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1472 /* We do not want to modify transient fields. They should
1477 Field f = clazz.forClass().getDeclaredField(name);
1478 if (Modifier.isTransient(f.getModifiers()))
1479 throw new IllegalArgumentException
1480 ("no such field (non transient) " + name);
1481 if (field == null && f.getType() != type)
1482 throw new IllegalArgumentException
1483 ("Invalid requested type for field " + name);
1485 catch (NoSuchFieldException e)
1488 throw new IllegalArgumentException(e.getMessage());
1495 fieldsAlreadyRead = true;
1496 return prereadFields;
1500 * Protected constructor that allows subclasses to override
1501 * deserialization. This constructor should be called by subclasses
1502 * that wish to override <code>readObject (Object)</code>. This
1503 * method does a security check <i>NOTE: currently not
1504 * implemented</i>, then sets a flag that informs
1505 * <code>readObject (Object)</code> to call the subclasses
1506 * <code>readObjectOverride (Object)</code> method.
1508 * @see #readObjectOverride()
1510 protected ObjectInputStream()
1511 throws IOException, SecurityException
1513 SecurityManager sec_man = System.getSecurityManager();
1514 if (sec_man != null)
1515 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1516 this.useSubclassMethod = true;
1520 * This method allows subclasses to override the default
1521 * de serialization mechanism provided by
1522 * <code>ObjectInputStream</code>. To make this method be used for
1523 * writing objects, subclasses must invoke the 0-argument
1524 * constructor on this class from their constructor.
1526 * @see #ObjectInputStream()
1528 protected Object readObjectOverride()
1529 throws ClassNotFoundException, IOException, OptionalDataException
1531 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1535 * Assigns the next available handle to <code>obj</code>.
1537 * @param obj The object for which we want a new handle.
1538 * @return A valid handle for the specified object.
1540 private int assignNewHandle(Object obj)
1542 this.objectLookupTable.put(new Integer(this.nextOID),
1543 new ObjectIdentityWrapper(obj));
1544 return this.nextOID++;
1547 private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
1550 if (osc != null && obj instanceof Serializable)
1554 Method m = osc.readResolveMethod;
1557 obj = m.invoke(obj, new Object[] {});
1560 catch (IllegalAccessException ignore)
1563 catch (InvocationTargetException ignore)
1568 if (this.resolveEnabled)
1569 obj = resolveObject(obj);
1571 this.objectLookupTable.put(new Integer(handle),
1572 new ObjectIdentityWrapper(obj));
1577 private void clearHandles()
1579 this.objectLookupTable.clear();
1580 this.nextOID = baseWireHandle;
1583 private void readNextBlock() throws IOException
1585 readNextBlock(this.realInputStream.readByte());
1588 private void readNextBlock(byte marker) throws IOException
1590 if (marker == TC_BLOCKDATA)
1592 if(dump) dumpElement("BLOCK DATA SIZE=");
1593 this.blockDataBytes = this.realInputStream.readUnsignedByte();
1594 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1596 else if (marker == TC_BLOCKDATALONG)
1598 if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1599 this.blockDataBytes = this.realInputStream.readInt();
1600 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1604 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1607 if (this.blockData.length < this.blockDataBytes)
1608 this.blockData = new byte[this.blockDataBytes];
1610 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1611 this.blockDataPosition = 0;
1614 private void readArrayElements (Object array, Class clazz)
1615 throws ClassNotFoundException, IOException
1617 if (clazz.isPrimitive())
1619 if (clazz == Boolean.TYPE)
1621 boolean[] cast_array = (boolean[])array;
1622 for (int i=0; i < cast_array.length; i++)
1623 cast_array[i] = this.realInputStream.readBoolean();
1626 if (clazz == Byte.TYPE)
1628 byte[] cast_array = (byte[])array;
1629 for (int i=0; i < cast_array.length; i++)
1630 cast_array[i] = this.realInputStream.readByte();
1633 if (clazz == Character.TYPE)
1635 char[] cast_array = (char[])array;
1636 for (int i=0; i < cast_array.length; i++)
1637 cast_array[i] = this.realInputStream.readChar();
1640 if (clazz == Double.TYPE)
1642 double[] cast_array = (double[])array;
1643 for (int i=0; i < cast_array.length; i++)
1644 cast_array[i] = this.realInputStream.readDouble();
1647 if (clazz == Float.TYPE)
1649 float[] cast_array = (float[])array;
1650 for (int i=0; i < cast_array.length; i++)
1651 cast_array[i] = this.realInputStream.readFloat();
1654 if (clazz == Integer.TYPE)
1656 int[] cast_array = (int[])array;
1657 for (int i=0; i < cast_array.length; i++)
1658 cast_array[i] = this.realInputStream.readInt();
1661 if (clazz == Long.TYPE)
1663 long[] cast_array = (long[])array;
1664 for (int i=0; i < cast_array.length; i++)
1665 cast_array[i] = this.realInputStream.readLong();
1668 if (clazz == Short.TYPE)
1670 short[] cast_array = (short[])array;
1671 for (int i=0; i < cast_array.length; i++)
1672 cast_array[i] = this.realInputStream.readShort();
1678 Object[] cast_array = (Object[])array;
1679 for (int i=0; i < cast_array.length; i++)
1680 cast_array[i] = readObject();
1684 private void readFields (Object obj, ObjectStreamClass stream_osc)
1685 throws ClassNotFoundException, IOException
1687 ObjectStreamField[] fields = stream_osc.fieldMapping;
1689 for (int i = 0; i < fields.length; i += 2)
1691 ObjectStreamField stream_field = fields[i];
1692 ObjectStreamField real_field = fields[i + 1];
1693 boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1694 boolean set_value = (real_field != null && real_field.isToSet());
1698 if (stream_field != null)
1700 field_name = stream_field.getName();
1701 type = stream_field.getTypeCode();
1705 field_name = real_field.getName();
1706 type = real_field.getTypeCode();
1714 read_value ? this.realInputStream.readBoolean() : false;
1715 if (dump && read_value && set_value)
1716 dumpElementln(" " + field_name + ": " + value);
1718 real_field.setBooleanField(obj, value);
1724 read_value ? this.realInputStream.readByte() : 0;
1725 if (dump && read_value && set_value)
1726 dumpElementln(" " + field_name + ": " + value);
1728 real_field.setByteField(obj, value);
1734 read_value ? this.realInputStream.readChar(): 0;
1735 if (dump && read_value && set_value)
1736 dumpElementln(" " + field_name + ": " + value);
1738 real_field.setCharField(obj, value);
1744 read_value ? this.realInputStream.readDouble() : 0;
1745 if (dump && read_value && set_value)
1746 dumpElementln(" " + field_name + ": " + value);
1748 real_field.setDoubleField(obj, value);
1754 read_value ? this.realInputStream.readFloat() : 0;
1755 if (dump && read_value && set_value)
1756 dumpElementln(" " + field_name + ": " + value);
1758 real_field.setFloatField(obj, value);
1764 read_value ? this.realInputStream.readInt() : 0;
1765 if (dump && read_value && set_value)
1766 dumpElementln(" " + field_name + ": " + value);
1768 real_field.setIntField(obj, value);
1774 read_value ? this.realInputStream.readLong() : 0;
1775 if (dump && read_value && set_value)
1776 dumpElementln(" " + field_name + ": " + value);
1778 real_field.setLongField(obj, value);
1784 read_value ? this.realInputStream.readShort() : 0;
1785 if (dump && read_value && set_value)
1786 dumpElementln(" " + field_name + ": " + value);
1788 real_field.setShortField(obj, value);
1795 read_value ? readObject() : null;
1797 real_field.setObjectField(obj, value);
1801 throw new InternalError("Invalid type code: " + type);
1806 // Toggles writing primitive data to block-data buffer.
1807 private boolean setBlockDataMode (boolean on)
1809 boolean oldmode = this.readDataFromBlock;
1810 this.readDataFromBlock = on;
1813 this.dataInputStream = this.blockDataInput;
1815 this.dataInputStream = this.realInputStream;
1819 // returns a new instance of REAL_CLASS that has been constructed
1820 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1821 private Object newObject (Class real_class, Constructor constructor)
1822 throws ClassNotFoundException, IOException
1824 if (constructor == null)
1825 throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
1828 return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
1830 catch (InstantiationException e)
1832 throw new ClassNotFoundException
1833 ("Instance of " + real_class + " could not be created");
1837 // runs all registered ObjectInputValidations in prioritized order
1839 private void invokeValidators() throws InvalidObjectException
1841 Object[] validators = new Object[this.validators.size()];
1842 this.validators.copyInto (validators);
1843 Arrays.sort (validators);
1847 for (int i=0; i < validators.length; i++)
1848 ((ObjectInputValidation)validators[i]).validateObject();
1852 this.validators.removeAllElements();
1856 private void callReadMethod (Method readObject, Class klass, Object obj)
1857 throws ClassNotFoundException, IOException
1861 readObject.invoke(obj, new Object[] { this });
1863 catch (InvocationTargetException x)
1865 /* Rethrow if possible. */
1866 Throwable exception = x.getTargetException();
1867 if (exception instanceof RuntimeException)
1868 throw (RuntimeException) exception;
1869 if (exception instanceof IOException)
1870 throw (IOException) exception;
1871 if (exception instanceof ClassNotFoundException)
1872 throw (ClassNotFoundException) exception;
1874 throw new IOException("Exception thrown from readObject() on " +
1875 klass + ": " + exception.getClass().getName());
1879 throw new IOException("Failure invoking readObject() on " +
1880 klass + ": " + x.getClass().getName());
1883 // Invalidate fields which has been read through readFields.
1884 prereadFields = null;
1887 private static final int BUFFER_SIZE = 1024;
1889 private DataInputStream realInputStream;
1890 private DataInputStream dataInputStream;
1891 private DataInputStream blockDataInput;
1892 private int blockDataPosition;
1893 private int blockDataBytes;
1894 private byte[] blockData;
1895 private boolean useSubclassMethod;
1896 private int nextOID;
1897 private boolean resolveEnabled;
1898 private Hashtable objectLookupTable;
1899 private Object currentObject;
1900 private ObjectStreamClass currentObjectStreamClass;
1901 private boolean readDataFromBlock;
1902 private boolean isDeserializing;
1903 private boolean fieldsAlreadyRead;
1904 private Vector validators;
1905 private Hashtable classLookupTable;
1906 private GetField prereadFields;
1908 private ClassLoader callersClassLoader;
1909 private static boolean dump;
1911 // The nesting depth for debugging output
1912 private int depth = 0;
1914 private static final boolean DEBUG = false;
1916 private void dumpElement (String msg)
1918 System.out.print(msg);
1921 private void dumpElementln (String msg)
1923 System.out.println(msg);
1924 for (int i = 0; i < depth; i++)
1925 System.out.print (" ");
1926 System.out.print (Thread.currentThread() + ": ");
1931 if (Configuration.INIT_LOAD_LIBRARY)
1933 System.loadLibrary ("javaio");
1937 // used to keep a prioritized list of object validators
1938 private static final class ValidatorAndPriority implements Comparable
1941 ObjectInputValidation validator;
1943 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1945 this.priority = priority;
1946 this.validator = validator;
1949 public int compareTo (Object o)
1951 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1952 return this.priority - vap.priority;