1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java.lang.reflect.Array;
42 import java.lang.reflect.Modifier;
43 import java.lang.reflect.Proxy;
44 import java.security.PrivilegedAction;
45 import java.security.AccessController;
46 import java.util.Arrays;
47 import java.util.Hashtable;
48 import java.util.Vector;
51 import gnu.java.io.ObjectIdentityWrapper;
52 import gnu.java.lang.reflect.TypeSignature;
53 import java.lang.reflect.Field;
54 import java.lang.reflect.Method;
55 import java.lang.reflect.InvocationTargetException;
57 import gnu.classpath.Configuration;
59 public class ObjectInputStream extends InputStream
60 implements ObjectInput, ObjectStreamConstants
63 * Creates a new <code>ObjectInputStream</code> that will do all of
64 * its reading from <code>in</code>. This method also checks
65 * the stream by reading the header information (stream magic number
66 * and stream version).
68 * @exception IOException Reading stream header from underlying
69 * stream cannot be completed.
71 * @exception StreamCorruptedException An invalid stream magic
72 * number or stream version was read from the stream.
74 * @see #readStreamHeader()
76 public ObjectInputStream(InputStream in)
77 throws IOException, StreamCorruptedException
79 if (Configuration.DEBUG)
81 String val = System.getProperty("gcj.dumpobjects");
82 if (dump == false && val != null && !val.equals(""))
85 System.out.println ("Serialization debugging enabled");
87 else if (dump == true && (val == null || val.equals("")))
90 System.out.println ("Serialization debugging disabled");
94 this.resolveEnabled = false;
95 this.isDeserializing = false;
96 this.blockDataPosition = 0;
97 this.blockDataBytes = 0;
98 this.blockData = new byte[BUFFER_SIZE];
99 this.blockDataInput = new DataInputStream(this);
100 this.realInputStream = new DataInputStream(in);
101 this.nextOID = baseWireHandle;
102 this.objectLookupTable = new Hashtable();
103 this.validators = new Vector();
104 this.classLookupTable = new Hashtable();
105 setBlockDataMode(true);
111 * Returns the next deserialized object read from the underlying stream.
113 * This method can be overriden by a class by implementing
114 * <code>private void readObject (ObjectInputStream)</code>.
116 * If an exception is thrown from this method, the stream is left in
117 * an undefined state.
119 * @exception ClassNotFoundException The class that an object being
120 * read in belongs to cannot be found.
122 * @exception IOException Exception from underlying
123 * <code>InputStream</code>.
125 public final Object readObject() throws ClassNotFoundException, IOException
127 if (callersClassLoader == null)
129 callersClassLoader = getCallersClassLoader ();
130 if (Configuration.DEBUG && dump)
132 dumpElementln ("CallersClassLoader = " + callersClassLoader);
136 if (this.useSubclassMethod)
137 return readObjectOverride();
139 boolean was_deserializing;
142 was_deserializing = this.isDeserializing;
144 boolean is_consumed = false;
145 boolean old_mode = setBlockDataMode(false);
147 this.isDeserializing = true;
149 byte marker = this.realInputStream.readByte();
153 if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
159 case TC_ENDBLOCKDATA:
167 case TC_BLOCKDATALONG:
169 if (marker == TC_BLOCKDATALONG)
170 { if(dump) dumpElementln("BLOCKDATALONG"); }
172 { if(dump) dumpElementln("BLOCKDATA"); }
173 readNextBlock(marker);
174 throw new StreamCorruptedException("Unexpected blockData");
179 if(dump) dumpElementln("NULL");
186 if(dump) dumpElement("REFERENCE ");
187 Integer oid = new Integer(this.realInputStream.readInt());
188 if(dump) dumpElementln(Integer.toHexString(oid.intValue()));
189 ret_val = ((ObjectIdentityWrapper)
190 this.objectLookupTable.get(oid)).object;
196 if(dump) dumpElementln("CLASS");
197 ObjectStreamClass osc = (ObjectStreamClass)readObject();
198 Class clazz = osc.forClass();
199 assignNewHandle(clazz);
204 case TC_PROXYCLASSDESC:
206 if(dump) dumpElementln("PROXYCLASS");
207 int n_intf = this.realInputStream.readInt();
208 String[] intfs = new String[n_intf];
209 for (int i = 0; i < n_intf; i++)
211 intfs[i] = this.realInputStream.readUTF();
212 System.out.println(intfs[i]);
215 boolean oldmode = setBlockDataMode(true);
216 Class cl = resolveProxyClass(intfs);
217 setBlockDataMode(oldmode);
219 ObjectStreamClass osc = lookupClass(cl);
220 assignNewHandle(osc);
224 byte b = this.realInputStream.readByte();
225 if (b != TC_ENDBLOCKDATA)
226 throw new IOException("Data annotated to class was not consumed." + b);
230 ObjectStreamClass superosc = (ObjectStreamClass)readObject();
231 osc.setSuperclass(superosc);
238 ObjectStreamClass osc = readClassDescriptor();
242 byte b = this.realInputStream.readByte();
243 if (b != TC_ENDBLOCKDATA)
244 throw new IOException("Data annotated to class was not consumed." + b);
249 osc.setSuperclass ((ObjectStreamClass)readObject());
257 if(dump) dumpElement("STRING=");
258 String s = this.realInputStream.readUTF();
259 if(dump) dumpElementln(s);
260 ret_val = processResolution(null, s, assignNewHandle(s));
266 if(dump) dumpElementln("ARRAY");
267 ObjectStreamClass osc = (ObjectStreamClass)readObject();
268 Class componentType = osc.forClass().getComponentType();
269 if(dump) dumpElement("ARRAY LENGTH=");
270 int length = this.realInputStream.readInt();
271 if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
272 Object array = Array.newInstance(componentType, length);
273 int handle = assignNewHandle(array);
274 readArrayElements(array, componentType);
276 for (int i = 0, len = Array.getLength(array); i < len; i++)
277 dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i));
278 ret_val = processResolution(null, array, handle);
284 if(dump) dumpElementln("OBJECT");
285 ObjectStreamClass osc = (ObjectStreamClass)readObject();
286 Class clazz = osc.forClass();
288 if (!osc.realClassIsSerializable)
289 throw new NotSerializableException
290 (clazz + " is not Serializable, and thus cannot be deserialized.");
292 if (osc.realClassIsExternalizable)
294 Externalizable obj = osc.newInstance();
296 int handle = assignNewHandle(obj);
298 boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
300 boolean oldmode = this.readDataFromBlock;
301 if (read_from_blocks)
302 setBlockDataMode(true);
304 obj.readExternal(this);
306 if (read_from_blocks)
307 setBlockDataMode(oldmode);
309 ret_val = processResolution(osc, obj, handle);
311 } // end if (osc.realClassIsExternalizable)
313 Object obj = newObject(clazz, osc.firstNonSerializableParent);
315 int handle = assignNewHandle(obj);
316 Object prevObject = this.currentObject;
317 ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
319 this.currentObject = obj;
320 ObjectStreamClass[] hierarchy =
321 inputGetObjectStreamClasses(clazz);
323 for (int i = 0; i < hierarchy.length; i++)
325 this.currentObjectStreamClass = hierarchy[i];
327 if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
329 // XXX: should initialize fields in classes in the hierarchy
330 // that aren't in the stream
331 // should skip over classes in the stream that aren't in the
332 // real classes hierarchy
334 Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
335 if (readObjectMethod != null)
337 fieldsAlreadyRead = false;
338 boolean oldmode = setBlockDataMode(true);
339 callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
340 setBlockDataMode(oldmode);
344 readFields(obj, currentObjectStreamClass);
347 if (this.currentObjectStreamClass.hasWriteMethod())
349 if(dump) dumpElement("ENDBLOCKDATA? ");
352 // FIXME: XXX: This try block is to
353 // catch EOF which is thrown for some
354 // objects. That indicates a bug in
357 if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
358 throw new IOException
359 ("No end of block data seen for class with readObject (ObjectInputStream) method.");
360 if(dump) dumpElementln("yes");
362 // catch (EOFException e)
364 // if(dump) dumpElementln("no, got EOFException");
366 catch (IOException e)
368 if(dump) dumpElementln("no, got IOException");
373 this.currentObject = prevObject;
374 this.currentObjectStreamClass = prevObjectStreamClass;
375 ret_val = processResolution(osc, obj, handle);
381 if(dump) dumpElementln("RESET");
383 ret_val = readObject();
388 if(dump) dumpElement("EXCEPTION=");
389 Exception e = (Exception)readObject();
390 if(dump) dumpElementln(e.toString());
392 throw new WriteAbortedException("Exception thrown during writing of stream", e);
396 throw new IOException("Unknown marker on stream: " + marker);
401 setBlockDataMode(old_mode);
403 this.isDeserializing = was_deserializing;
407 if (! was_deserializing)
409 if (validators.size() > 0)
418 * This method makes a partial check of types for the fields
419 * contained given in arguments. It checks primitive types of
420 * fields1 against non primitive types of fields2. This method
421 * assumes the two lists has already been sorted according to
422 * the Java specification.
424 * @param name Name of the class owning the given fields.
425 * @param fields1 First list to check.
426 * @param fields2 Second list to check.
427 * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
428 * in the non primitive part in fields2.
430 private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
431 throws InvalidClassException
433 int nonPrimitive = 0;
435 for (nonPrimitive = 0;
436 nonPrimitive < fields1.length
437 && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
441 if (nonPrimitive == fields1.length)
445 ObjectStreamField f1;
446 ObjectStreamField f2;
448 while (i < fields2.length
449 && nonPrimitive < fields1.length)
451 f1 = fields1[nonPrimitive];
454 if (!f2.isPrimitive())
457 int compVal = f1.getName().compareTo (f2.getName());
463 else if (compVal > 0)
469 throw new InvalidClassException
470 ("invalid field type for " + f2.getName() +
471 " in class " + name);
477 * This method reads a class descriptor from the real input stream
478 * and use these data to create a new instance of ObjectStreamClass.
479 * Fields are sorted and ordered for the real read which occurs for
480 * each instance of the described class. Be aware that if you call that
481 * method you must ensure that the stream is synchronized, in the other
482 * case it may be completely desynchronized.
484 * @return A new instance of ObjectStreamClass containing the freshly
485 * created descriptor.
486 * @throws ClassNotFoundException if the required class to build the
487 * descriptor has not been found in the system.
488 * @throws IOException An input/output error occured.
489 * @throws InvalidClassException If there was a compatibility problem
490 * between the class present in the system and the serialized class.
492 protected ObjectStreamClass readClassDescriptor()
493 throws ClassNotFoundException, IOException
495 if(dump) dumpElement("CLASSDESC NAME=");
496 String name = this.realInputStream.readUTF();
497 if(dump) dumpElement(name + "; UID=");
498 long uid = this.realInputStream.readLong ();
499 if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
500 byte flags = this.realInputStream.readByte ();
501 if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
502 short field_count = this.realInputStream.readShort();
503 if(dump) dumpElementln(Short.toString(field_count));
504 ObjectStreamField[] fields = new ObjectStreamField[field_count];
505 ObjectStreamClass osc = new ObjectStreamClass(name, uid,
507 assignNewHandle(osc);
509 ClassLoader currentLoader = currentLoader();
511 for (int i = 0; i < field_count; i++)
513 if(dump) dumpElement(" TYPE CODE=");
514 char type_code = (char)this.realInputStream.readByte();
515 if(dump) dumpElement(type_code + "; FIELD NAME=");
516 String field_name = this.realInputStream.readUTF();
517 if(dump) dumpElementln(field_name);
520 // If the type code is an array or an object we must
521 // decode a String here. In the other case we convert
522 // the type code and pass it to ObjectStreamField.
523 // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
524 if (type_code == 'L' || type_code == '[')
525 class_name = (String)readObject();
527 class_name = String.valueOf(type_code);
530 new ObjectStreamField(field_name, class_name, currentLoader);
533 /* Now that fields have been read we may resolve the class
534 * (and read annotation if needed). */
535 Class clazz = resolveClass(osc);
537 boolean oldmode = setBlockDataMode(true);
538 osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
539 classLookupTable.put(clazz, osc);
540 setBlockDataMode(oldmode);
542 // find the first non-serializable, non-abstract
543 // class in clazz's inheritance hierarchy
544 Class first_nonserial = clazz.getSuperclass();
545 while (Serializable.class.isAssignableFrom(first_nonserial)
546 || Modifier.isAbstract(first_nonserial.getModifiers()))
547 first_nonserial = first_nonserial.getSuperclass();
549 osc.firstNonSerializableParent = first_nonserial;
550 osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
551 osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
553 ObjectStreamField[] stream_fields = osc.fields;
554 ObjectStreamField[] real_fields = ObjectStreamClass.lookup(clazz).fields;
555 ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
562 * Check that there is no type inconsistencies between the lists.
563 * A special checking must be done for the two groups: primitive types and
564 * not primitive types.
566 checkTypeConsistency(name, real_fields, stream_fields);
567 checkTypeConsistency(name, stream_fields, real_fields);
570 while (stream_idx < stream_fields.length
571 || real_idx < real_fields.length)
573 ObjectStreamField stream_field = null;
574 ObjectStreamField real_field = null;
576 if (stream_idx == stream_fields.length)
578 real_field = real_fields[real_idx++];
580 else if (real_idx == real_fields.length)
582 stream_field = stream_fields[stream_idx++];
587 real_fields[real_idx].compareTo (stream_fields[stream_idx]);
591 real_field = real_fields[real_idx++];
593 else if (comp_val > 0)
595 stream_field = stream_fields[stream_idx++];
599 stream_field = stream_fields[stream_idx++];
600 real_field = real_fields[real_idx++];
601 if (stream_field.getType() != real_field.getType())
602 throw new InvalidClassException
603 ("invalid field type for " + real_field.getName() +
604 " in class " + name);
608 /* If some of stream_fields does not correspond to any of real_fields,
609 * or the opposite, then fieldmapping will go short.
611 if (map_idx == fieldmapping.length)
613 ObjectStreamField[] newfieldmapping =
614 new ObjectStreamField[fieldmapping.length + 2];
615 System.arraycopy(fieldmapping, 0,
616 newfieldmapping, 0, fieldmapping.length);
617 fieldmapping = newfieldmapping;
619 fieldmapping[map_idx++] = stream_field;
620 fieldmapping[map_idx++] = real_field;
622 osc.fieldMapping = fieldmapping;
628 * Reads the current objects non-transient, non-static fields from
629 * the current class from the underlying output stream.
631 * This method is intended to be called from within a object's
632 * <code>private void readObject (ObjectInputStream)</code>
635 * @exception ClassNotFoundException The class that an object being
636 * read in belongs to cannot be found.
638 * @exception NotActiveException This method was called from a
639 * context other than from the current object's and current class's
640 * <code>private void readObject (ObjectInputStream)</code>
643 * @exception IOException Exception from underlying
644 * <code>OutputStream</code>.
646 public void defaultReadObject()
647 throws ClassNotFoundException, IOException, NotActiveException
649 if (this.currentObject == null || this.currentObjectStreamClass == null)
650 throw new NotActiveException("defaultReadObject called by non-active"
651 + " class and/or object");
653 if (fieldsAlreadyRead)
654 throw new NotActiveException("defaultReadObject called but fields "
655 + "already read from stream (by "
656 + "defaultReadObject or readFields)");
658 boolean oldmode = setBlockDataMode(false);
659 readFields(this.currentObject, this.currentObjectStreamClass);
660 setBlockDataMode(oldmode);
662 fieldsAlreadyRead = true;
667 * Registers a <code>ObjectInputValidation</code> to be carried out
668 * on the object graph currently being deserialized before it is
669 * returned to the original caller of <code>readObject ()</code>.
670 * The order of validation for multiple
671 * <code>ObjectInputValidation</code>s can be controled using
672 * <code>priority</code>. Validators with higher priorities are
675 * @see java.io.ObjectInputValidation
677 * @exception InvalidObjectException <code>validator</code> is
680 * @exception NotActiveException an attempt was made to add a
681 * validator outside of the <code>readObject</code> method of the
682 * object currently being deserialized
684 public void registerValidation(ObjectInputValidation validator,
686 throws InvalidObjectException, NotActiveException
688 if (this.currentObject == null || this.currentObjectStreamClass == null)
689 throw new NotActiveException("registerValidation called by non-active "
690 + "class and/or object");
692 if (validator == null)
693 throw new InvalidObjectException("attempt to add a null "
694 + "ObjectInputValidation object");
696 this.validators.addElement(new ValidatorAndPriority (validator,
702 * Called when a class is being deserialized. This is a hook to
703 * allow subclasses to read in information written by the
704 * <code>annotateClass (Class)</code> method of an
705 * <code>ObjectOutputStream</code>.
707 * This implementation looks up the active call stack for a
708 * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
709 * it is used to load the class associated with <code>osc</code>,
710 * otherwise, the default system <code>ClassLoader</code> is used.
712 * @exception IOException Exception from underlying
713 * <code>OutputStream</code>.
715 * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
717 protected Class resolveClass(ObjectStreamClass osc)
718 throws ClassNotFoundException, IOException
720 return Class.forName(osc.getName(), true, callersClassLoader);
724 * This method invokes the method currentClassLoader for the
725 * current security manager (or build an empty one if it is not
728 * @return The most recent non-system ClassLoader on the execution stack.
729 * @see java.lang.SecurityManager#currentClassLoader()
731 private ClassLoader currentLoader()
733 SecurityManager sm = System.getSecurityManager();
735 sm = new SecurityManager () {};
737 return currentClassLoader(sm);
741 * Lookup a class stored in the local hashtable. If it is not
742 * use the global lookup function in ObjectStreamClass to build
743 * the ObjectStreamClass. This method is requested according to
744 * the behaviour detected in the JDK by Kaffe's team.
746 * @param clazz Class to lookup in the hash table or for which
747 * we must build a descriptor.
748 * @return A valid instance of ObjectStreamClass corresponding
749 * to the specified class.
751 private ObjectStreamClass lookupClass(Class clazz)
753 ObjectStreamClass oclazz;
755 oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
757 return ObjectStreamClass.lookup(clazz);
763 * Reconstruct class hierarchy the same way
764 * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
765 * but using lookupClass instead of ObjectStreamClass.lookup. This
766 * dup is necessary localize the lookup table. Hopefully some future
767 * rewritings will be able to prevent this.
769 * @param clazz This is the class for which we want the hierarchy.
771 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
772 * represent the class hierarchy for clazz.
774 private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
776 ObjectStreamClass osc = lookupClass(clazz);
779 return new ObjectStreamClass[0];
782 Vector oscs = new Vector();
786 oscs.addElement(osc);
787 osc = osc.getSuper();
790 int count = oscs.size();
791 ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
793 for (int i = count - 1; i >= 0; i--)
794 sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
801 * Allows subclasses to resolve objects that are read from the
802 * stream with other objects to be returned in their place. This
803 * method is called the first time each object is encountered.
805 * This method must be enabled before it will be called in the
806 * serialization process.
808 * @exception IOException Exception from underlying
809 * <code>OutputStream</code>.
811 * @see #enableResolveObject(boolean)
813 protected Object resolveObject(Object obj) throws IOException
819 protected Class resolveProxyClass(String[] intfs)
820 throws IOException, ClassNotFoundException
822 SecurityManager sm = System.getSecurityManager();
825 sm = new SecurityManager() {};
827 ClassLoader cl = currentClassLoader(sm);
829 Class[] clss = new Class[intfs.length];
832 for (int i = 0; i < intfs.length; i++)
833 clss[i] = Class.forName(intfs[i]);
834 cl = ClassLoader.getSystemClassLoader();
837 for (int i = 0; i < intfs.length; i++)
838 clss[i] = cl.loadClass(intfs[i]);
841 return Proxy.getProxyClass(cl, clss);
843 catch (IllegalArgumentException e)
845 throw new ClassNotFoundException(null, e);
850 * If <code>enable</code> is <code>true</code> and this object is
851 * trusted, then <code>resolveObject (Object)</code> will be called
852 * in subsequent calls to <code>readObject (Object)</code>.
853 * Otherwise, <code>resolveObject (Object)</code> will not be called.
855 * @exception SecurityException This class is not trusted.
857 protected boolean enableResolveObject (boolean enable)
858 throws SecurityException
862 SecurityManager sm = System.getSecurityManager();
864 sm.checkPermission(new SerializablePermission("enableSubstitution"));
867 boolean old_val = this.resolveEnabled;
868 this.resolveEnabled = enable;
873 * Reads stream magic and stream version information from the
876 * @exception IOException Exception from underlying stream.
878 * @exception StreamCorruptedException An invalid stream magic
879 * number or stream version was read from the stream.
881 protected void readStreamHeader()
882 throws IOException, StreamCorruptedException
884 if(dump) dumpElement("STREAM MAGIC ");
885 if (this.realInputStream.readShort() != STREAM_MAGIC)
886 throw new StreamCorruptedException("Invalid stream magic number");
888 if(dump) dumpElementln("STREAM VERSION ");
889 if (this.realInputStream.readShort() != STREAM_VERSION)
890 throw new StreamCorruptedException("Invalid stream version number");
893 public int read() throws IOException
895 if (this.readDataFromBlock)
897 if (this.blockDataPosition >= this.blockDataBytes)
899 return (this.blockData[this.blockDataPosition++] & 0xff);
902 return this.realInputStream.read();
905 public int read(byte[] data, int offset, int length) throws IOException
907 if (this.readDataFromBlock)
909 if (this.blockDataPosition + length > this.blockDataBytes)
911 int remain = this.blockDataBytes - this.blockDataPosition;
914 System.arraycopy(this.blockData, this.blockDataPosition,
915 data, offset, remain);
922 System.arraycopy(this.blockData, this.blockDataPosition,
923 data, offset, length);
924 this.blockDataPosition += length;
929 return this.realInputStream.read(data, offset, length);
932 public int available() throws IOException
934 if (this.readDataFromBlock)
936 if (this.blockDataPosition >= this.blockDataBytes)
939 return this.blockDataBytes - this.blockDataPosition;
942 return this.realInputStream.available();
945 public void close() throws IOException
947 this.realInputStream.close();
950 public boolean readBoolean() throws IOException
952 boolean switchmode = true;
953 boolean oldmode = this.readDataFromBlock;
954 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
957 oldmode = setBlockDataMode (true);
958 boolean value = this.dataInputStream.readBoolean ();
960 setBlockDataMode (oldmode);
964 public byte readByte() throws IOException
966 boolean switchmode = true;
967 boolean oldmode = this.readDataFromBlock;
968 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
971 oldmode = setBlockDataMode(true);
972 byte value = this.dataInputStream.readByte();
974 setBlockDataMode(oldmode);
978 public int readUnsignedByte() throws IOException
980 boolean switchmode = true;
981 boolean oldmode = this.readDataFromBlock;
982 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
985 oldmode = setBlockDataMode(true);
986 int value = this.dataInputStream.readUnsignedByte();
988 setBlockDataMode(oldmode);
992 public short readShort() throws IOException
994 boolean switchmode = true;
995 boolean oldmode = this.readDataFromBlock;
996 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
999 oldmode = setBlockDataMode(true);
1000 short value = this.dataInputStream.readShort();
1002 setBlockDataMode(oldmode);
1006 public int readUnsignedShort() throws IOException
1008 boolean switchmode = true;
1009 boolean oldmode = this.readDataFromBlock;
1010 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1013 oldmode = setBlockDataMode(true);
1014 int value = this.dataInputStream.readUnsignedShort();
1016 setBlockDataMode(oldmode);
1020 public char readChar() throws IOException
1022 boolean switchmode = true;
1023 boolean oldmode = this.readDataFromBlock;
1024 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1027 oldmode = setBlockDataMode(true);
1028 char value = this.dataInputStream.readChar();
1030 setBlockDataMode(oldmode);
1034 public int readInt() throws IOException
1036 boolean switchmode = true;
1037 boolean oldmode = this.readDataFromBlock;
1038 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1041 oldmode = setBlockDataMode(true);
1042 int value = this.dataInputStream.readInt();
1044 setBlockDataMode(oldmode);
1048 public long readLong() throws IOException
1050 boolean switchmode = true;
1051 boolean oldmode = this.readDataFromBlock;
1052 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1055 oldmode = setBlockDataMode(true);
1056 long value = this.dataInputStream.readLong();
1058 setBlockDataMode(oldmode);
1062 public float readFloat() throws IOException
1064 boolean switchmode = true;
1065 boolean oldmode = this.readDataFromBlock;
1066 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1069 oldmode = setBlockDataMode(true);
1070 float value = this.dataInputStream.readFloat();
1072 setBlockDataMode(oldmode);
1076 public double readDouble() throws IOException
1078 boolean switchmode = true;
1079 boolean oldmode = this.readDataFromBlock;
1080 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1083 oldmode = setBlockDataMode(true);
1084 double value = this.dataInputStream.readDouble();
1086 setBlockDataMode(oldmode);
1090 public void readFully(byte data[]) throws IOException
1092 this.dataInputStream.readFully(data);
1095 public void readFully(byte data[], int offset, int size)
1098 this.dataInputStream.readFully(data, offset, size);
1101 public int skipBytes(int len) throws IOException
1103 return this.dataInputStream.skipBytes(len);
1108 * @see java.io.DataInputStream#readLine ()
1110 public String readLine() throws IOException
1112 return this.dataInputStream.readLine();
1115 public String readUTF() throws IOException
1117 return this.dataInputStream.readUTF();
1121 * This class allows a class to specify exactly which fields should
1122 * be read, and what values should be read for these fields.
1124 * XXX: finish up comments
1126 public static abstract class GetField
1128 public abstract ObjectStreamClass getObjectStreamClass();
1130 public abstract boolean defaulted(String name)
1131 throws IOException, IllegalArgumentException;
1133 public abstract boolean get(String name, boolean defvalue)
1134 throws IOException, IllegalArgumentException;
1136 public abstract char get(String name, char defvalue)
1137 throws IOException, IllegalArgumentException;
1139 public abstract byte get(String name, byte defvalue)
1140 throws IOException, IllegalArgumentException;
1142 public abstract short get(String name, short defvalue)
1143 throws IOException, IllegalArgumentException;
1145 public abstract int get(String name, int defvalue)
1146 throws IOException, IllegalArgumentException;
1148 public abstract long get(String name, long defvalue)
1149 throws IOException, IllegalArgumentException;
1151 public abstract float get(String name, float defvalue)
1152 throws IOException, IllegalArgumentException;
1154 public abstract double get(String name, double defvalue)
1155 throws IOException, IllegalArgumentException;
1157 public abstract Object get(String name, Object defvalue)
1158 throws IOException, IllegalArgumentException;
1162 * This method should be called by a method called 'readObject' in the
1163 * deserializing class (if present). It cannot (and should not)be called
1164 * outside of it. Its goal is to read all fields in the real input stream
1165 * and keep them accessible through the {@link #GetField} class. Calling
1166 * this method will not alter the deserializing object.
1168 * @return A valid freshly created 'GetField' instance to get access to
1169 * the deserialized stream.
1170 * @throws IOException An input/output exception occured.
1171 * @throws ClassNotFoundException
1172 * @throws NotActiveException
1174 public GetField readFields()
1175 throws IOException, ClassNotFoundException, NotActiveException
1177 if (this.currentObject == null || this.currentObjectStreamClass == null)
1178 throw new NotActiveException("readFields called by non-active class and/or object");
1180 if (prereadFields != null)
1181 return prereadFields;
1183 if (fieldsAlreadyRead)
1184 throw new NotActiveException("readFields called but fields already read from"
1185 + " stream (by defaultReadObject or readFields)");
1187 final ObjectStreamClass clazz = this.currentObjectStreamClass;
1188 final byte[] prim_field_data = new byte[clazz.primFieldSize];
1189 final Object[] objs = new Object[clazz.objectFieldCount];
1191 // Apparently Block data is not used with GetField as per
1192 // empirical evidence against JDK 1.2. Also see Mauve test
1193 // java.io.ObjectInputOutput.Test.GetPutField.
1194 boolean oldmode = setBlockDataMode(false);
1195 readFully(prim_field_data);
1196 for (int i = 0; i < objs.length; ++ i)
1197 objs[i] = readObject();
1198 setBlockDataMode(oldmode);
1200 prereadFields = new GetField()
1202 public ObjectStreamClass getObjectStreamClass()
1207 public boolean defaulted(String name)
1208 throws IOException, IllegalArgumentException
1210 ObjectStreamField f = clazz.getField(name);
1212 /* First if we have a serialized field use the descriptor */
1215 /* It is in serialPersistentFields but setClass tells us
1216 * it should not be set. This value is defaulted.
1218 if (f.isPersistent() && !f.isToSet())
1224 /* This is not a serialized field. There should be
1225 * a default value only if the field really exists.
1229 return (clazz.forClass().getDeclaredField (name) != null);
1231 catch (NoSuchFieldException e)
1233 throw new IllegalArgumentException(e.getMessage());
1237 public boolean get(String name, boolean defvalue)
1238 throws IOException, IllegalArgumentException
1240 ObjectStreamField field = getField(name, Boolean.TYPE);
1245 return prim_field_data[field.getOffset()] == 0 ? false : true;
1248 public char get(String name, char defvalue)
1249 throws IOException, IllegalArgumentException
1251 ObjectStreamField field = getField(name, Character.TYPE);
1256 int off = field.getOffset();
1258 return (char)(((prim_field_data[off++] & 0xFF) << 8)
1259 | (prim_field_data[off] & 0xFF));
1262 public byte get(String name, byte defvalue)
1263 throws IOException, IllegalArgumentException
1265 ObjectStreamField field = getField(name, Byte.TYPE);
1270 return prim_field_data[field.getOffset()];
1273 public short get(String name, short defvalue)
1274 throws IOException, IllegalArgumentException
1276 ObjectStreamField field = getField(name, Short.TYPE);
1281 int off = field.getOffset();
1283 return (short)(((prim_field_data[off++] & 0xFF) << 8)
1284 | (prim_field_data[off] & 0xFF));
1287 public int get(String name, int defvalue)
1288 throws IOException, IllegalArgumentException
1290 ObjectStreamField field = getField(name, Integer.TYPE);
1295 int off = field.getOffset();
1297 return ((prim_field_data[off++] & 0xFF) << 24)
1298 | ((prim_field_data[off++] & 0xFF) << 16)
1299 | ((prim_field_data[off++] & 0xFF) << 8)
1300 | (prim_field_data[off] & 0xFF);
1303 public long get(String name, long defvalue)
1304 throws IOException, IllegalArgumentException
1306 ObjectStreamField field = getField(name, Long.TYPE);
1311 int off = field.getOffset();
1313 return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1314 | ((prim_field_data[off++] & 0xFFL) << 48)
1315 | ((prim_field_data[off++] & 0xFFL) << 40)
1316 | ((prim_field_data[off++] & 0xFFL) << 32)
1317 | ((prim_field_data[off++] & 0xFF) << 24)
1318 | ((prim_field_data[off++] & 0xFF) << 16)
1319 | ((prim_field_data[off++] & 0xFF) << 8)
1320 | (prim_field_data[off] & 0xFF));
1323 public float get(String name, float defvalue)
1324 throws IOException, IllegalArgumentException
1326 ObjectStreamField field = getField(name, Float.TYPE);
1331 int off = field.getOffset();
1333 return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1334 | ((prim_field_data[off++] & 0xFF) << 16)
1335 | ((prim_field_data[off++] & 0xFF) << 8)
1336 | (prim_field_data[off] & 0xFF));
1339 public double get(String name, double defvalue)
1340 throws IOException, IllegalArgumentException
1342 ObjectStreamField field = getField(name, Double.TYPE);
1347 int off = field.getOffset();
1349 return Double.longBitsToDouble
1350 ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1351 | ((prim_field_data[off++] & 0xFFL) << 48)
1352 | ((prim_field_data[off++] & 0xFFL) << 40)
1353 | ((prim_field_data[off++] & 0xFFL) << 32)
1354 | ((prim_field_data[off++] & 0xFF) << 24)
1355 | ((prim_field_data[off++] & 0xFF) << 16)
1356 | ((prim_field_data[off++] & 0xFF) << 8)
1357 | (prim_field_data[off] & 0xFF)));
1360 public Object get(String name, Object defvalue)
1361 throws IOException, IllegalArgumentException
1363 ObjectStreamField field =
1364 getField(name, defvalue == null ? null : defvalue.getClass ());
1369 return objs[field.getOffset()];
1372 private ObjectStreamField getField(String name, Class type)
1373 throws IllegalArgumentException
1375 ObjectStreamField field = clazz.getField(name);
1376 boolean illegal = false;
1382 Class field_type = field.getType();
1384 if (type == field_type ||
1385 (type == null && !field_type.isPrimitive()))
1392 throw new IllegalArgumentException
1393 ("Field requested is of type "
1394 + field_type.getName()
1395 + ", but requested type was "
1396 + (type == null ? "Object" : type.getName()));
1398 catch (NullPointerException _)
1400 /* Here we catch NullPointerException, because it may
1401 only come from the call 'field.getType()'. If field
1402 is null, we have to return null and classpath ethic
1403 say we must try to avoid 'if (xxx == null)'.
1406 catch (IllegalArgumentException e)
1415 /* If this is an unassigned field we should return
1416 * the default value.
1418 if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1421 /* We do not want to modify transient fields. They should
1426 Field f = clazz.forClass().getDeclaredField(name);
1427 if (Modifier.isTransient(f.getModifiers()))
1428 throw new IllegalArgumentException
1429 ("no such field (non transient) " + name);
1430 if (field == null && f.getType() != type)
1431 throw new IllegalArgumentException
1432 ("Invalid requested type for field " + name);
1434 catch (NoSuchFieldException e)
1437 throw new IllegalArgumentException(e.getMessage());
1444 fieldsAlreadyRead = true;
1445 return prereadFields;
1449 * Protected constructor that allows subclasses to override
1450 * deserialization. This constructor should be called by subclasses
1451 * that wish to override <code>readObject (Object)</code>. This
1452 * method does a security check <i>NOTE: currently not
1453 * implemented</i>, then sets a flag that informs
1454 * <code>readObject (Object)</code> to call the subclasses
1455 * <code>readObjectOverride (Object)</code> method.
1457 * @see #readObjectOverride()
1459 protected ObjectInputStream()
1460 throws IOException, SecurityException
1462 SecurityManager sec_man = System.getSecurityManager();
1463 if (sec_man != null)
1464 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1465 this.useSubclassMethod = true;
1469 * This method allows subclasses to override the default
1470 * de serialization mechanism provided by
1471 * <code>ObjectInputStream</code>. To make this method be used for
1472 * writing objects, subclasses must invoke the 0-argument
1473 * constructor on this class from their constructor.
1475 * @see #ObjectInputStream()
1477 protected Object readObjectOverride()
1478 throws ClassNotFoundException, IOException, OptionalDataException
1480 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1484 * Assigns the next available handle to <code>obj</code>.
1486 * @param obj The object for which we want a new handle.
1487 * @return A valid handle for the specified object.
1489 private int assignNewHandle(Object obj)
1491 this.objectLookupTable.put(new Integer(this.nextOID),
1492 new ObjectIdentityWrapper(obj));
1493 return this.nextOID++;
1496 private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
1499 if (osc != null && obj instanceof Serializable)
1503 Method m = osc.readResolveMethod;
1506 obj = m.invoke(obj, new Object[] {});
1509 catch (IllegalAccessException ignore)
1512 catch (InvocationTargetException ignore)
1517 if (this.resolveEnabled)
1518 obj = resolveObject(obj);
1520 this.objectLookupTable.put(new Integer(handle),
1521 new ObjectIdentityWrapper(obj));
1526 private void clearHandles()
1528 this.objectLookupTable.clear();
1529 this.nextOID = baseWireHandle;
1532 private void readNextBlock() throws IOException
1534 readNextBlock(this.realInputStream.readByte());
1537 private void readNextBlock(byte marker) throws IOException
1539 if (marker == TC_BLOCKDATA)
1541 if(dump) dumpElement("BLOCK DATA SIZE=");
1542 this.blockDataBytes = this.realInputStream.readUnsignedByte();
1543 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1545 else if (marker == TC_BLOCKDATALONG)
1547 if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1548 this.blockDataBytes = this.realInputStream.readInt();
1549 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1553 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1556 if (this.blockData.length < this.blockDataBytes)
1557 this.blockData = new byte[this.blockDataBytes];
1559 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1560 this.blockDataPosition = 0;
1563 private void readArrayElements (Object array, Class clazz)
1564 throws ClassNotFoundException, IOException
1566 if (clazz.isPrimitive())
1568 if (clazz == Boolean.TYPE)
1570 boolean[] cast_array = (boolean[])array;
1571 for (int i=0; i < cast_array.length; i++)
1572 cast_array[i] = this.realInputStream.readBoolean();
1575 if (clazz == Byte.TYPE)
1577 byte[] cast_array = (byte[])array;
1578 for (int i=0; i < cast_array.length; i++)
1579 cast_array[i] = this.realInputStream.readByte();
1582 if (clazz == Character.TYPE)
1584 char[] cast_array = (char[])array;
1585 for (int i=0; i < cast_array.length; i++)
1586 cast_array[i] = this.realInputStream.readChar();
1589 if (clazz == Double.TYPE)
1591 double[] cast_array = (double[])array;
1592 for (int i=0; i < cast_array.length; i++)
1593 cast_array[i] = this.realInputStream.readDouble();
1596 if (clazz == Float.TYPE)
1598 float[] cast_array = (float[])array;
1599 for (int i=0; i < cast_array.length; i++)
1600 cast_array[i] = this.realInputStream.readFloat();
1603 if (clazz == Integer.TYPE)
1605 int[] cast_array = (int[])array;
1606 for (int i=0; i < cast_array.length; i++)
1607 cast_array[i] = this.realInputStream.readInt();
1610 if (clazz == Long.TYPE)
1612 long[] cast_array = (long[])array;
1613 for (int i=0; i < cast_array.length; i++)
1614 cast_array[i] = this.realInputStream.readLong();
1617 if (clazz == Short.TYPE)
1619 short[] cast_array = (short[])array;
1620 for (int i=0; i < cast_array.length; i++)
1621 cast_array[i] = this.realInputStream.readShort();
1627 Object[] cast_array = (Object[])array;
1628 for (int i=0; i < cast_array.length; i++)
1629 cast_array[i] = readObject();
1633 private void readFields (Object obj, ObjectStreamClass stream_osc)
1634 throws ClassNotFoundException, IOException
1636 ObjectStreamField[] fields = stream_osc.fieldMapping;
1638 for (int i = 0; i < fields.length; i += 2)
1640 ObjectStreamField stream_field = fields[i];
1641 ObjectStreamField real_field = fields[i + 1];
1642 boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1643 boolean set_value = (real_field != null && real_field.isToSet());
1647 if (stream_field != null)
1649 field_name = stream_field.getName();
1650 type = stream_field.getTypeCode();
1654 field_name = real_field.getName();
1655 type = real_field.getTypeCode();
1663 read_value ? this.realInputStream.readBoolean() : false;
1664 if (dump && read_value && set_value)
1665 dumpElementln(" " + field_name + ": " + value);
1667 real_field.setBooleanField(obj, value);
1673 read_value ? this.realInputStream.readByte() : 0;
1674 if (dump && read_value && set_value)
1675 dumpElementln(" " + field_name + ": " + value);
1677 real_field.setByteField(obj, value);
1683 read_value ? this.realInputStream.readChar(): 0;
1684 if (dump && read_value && set_value)
1685 dumpElementln(" " + field_name + ": " + value);
1687 real_field.setCharField(obj, value);
1693 read_value ? this.realInputStream.readDouble() : 0;
1694 if (dump && read_value && set_value)
1695 dumpElementln(" " + field_name + ": " + value);
1697 real_field.setDoubleField(obj, value);
1703 read_value ? this.realInputStream.readFloat() : 0;
1704 if (dump && read_value && set_value)
1705 dumpElementln(" " + field_name + ": " + value);
1707 real_field.setFloatField(obj, value);
1713 read_value ? this.realInputStream.readInt() : 0;
1714 if (dump && read_value && set_value)
1715 dumpElementln(" " + field_name + ": " + value);
1717 real_field.setIntField(obj, value);
1723 read_value ? this.realInputStream.readLong() : 0;
1724 if (dump && read_value && set_value)
1725 dumpElementln(" " + field_name + ": " + value);
1727 real_field.setLongField(obj, value);
1733 read_value ? this.realInputStream.readShort() : 0;
1734 if (dump && read_value && set_value)
1735 dumpElementln(" " + field_name + ": " + value);
1737 real_field.setShortField(obj, value);
1744 read_value ? readObject() : null;
1746 real_field.setObjectField(obj, value);
1750 throw new InternalError("Invalid type code: " + type);
1755 // Toggles writing primitive data to block-data buffer.
1756 private boolean setBlockDataMode (boolean on)
1758 boolean oldmode = this.readDataFromBlock;
1759 this.readDataFromBlock = on;
1762 this.dataInputStream = this.blockDataInput;
1764 this.dataInputStream = this.realInputStream;
1768 // returns a new instance of REAL_CLASS that has been constructed
1769 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1770 private Object newObject (Class real_class, Class constructor_class)
1771 throws ClassNotFoundException
1775 Object obj = allocateObject (real_class);
1776 callConstructor (constructor_class, obj);
1779 catch (InstantiationException e)
1781 throw new ClassNotFoundException
1782 ("Instance of " + real_class + " could not be created");
1786 // runs all registered ObjectInputValidations in prioritized order
1788 private void invokeValidators() throws InvalidObjectException
1790 Object[] validators = new Object[this.validators.size()];
1791 this.validators.copyInto (validators);
1792 Arrays.sort (validators);
1796 for (int i=0; i < validators.length; i++)
1797 ((ObjectInputValidation)validators[i]).validateObject();
1801 this.validators.removeAllElements();
1806 * This native method is used to get access to the protected method
1807 * of the same name in SecurityManger.
1809 * @param sm SecurityManager instance which should be called.
1810 * @return The current class loader in the calling stack.
1812 private static native ClassLoader currentClassLoader (SecurityManager sm);
1814 private native ClassLoader getCallersClassLoader();
1816 private void callReadMethod (Method readObject, Class klass, Object obj)
1817 throws ClassNotFoundException, IOException
1821 readObject.invoke(obj, new Object[] { this });
1823 catch (InvocationTargetException x)
1825 /* Rethrow if possible. */
1826 Throwable exception = x.getTargetException();
1827 if (exception instanceof RuntimeException)
1828 throw (RuntimeException) exception;
1829 if (exception instanceof IOException)
1830 throw (IOException) exception;
1831 if (exception instanceof ClassNotFoundException)
1832 throw (ClassNotFoundException) exception;
1834 throw new IOException("Exception thrown from readObject() on " +
1835 klass + ": " + exception.getClass().getName());
1839 throw new IOException("Failure invoking readObject() on " +
1840 klass + ": " + x.getClass().getName());
1843 // Invalidate fields which has been read through readFields.
1844 prereadFields = null;
1847 private native Object allocateObject (Class clazz)
1848 throws InstantiationException;
1850 private native void callConstructor (Class clazz, Object obj);
1852 private static final int BUFFER_SIZE = 1024;
1854 private DataInputStream realInputStream;
1855 private DataInputStream dataInputStream;
1856 private DataInputStream blockDataInput;
1857 private int blockDataPosition;
1858 private int blockDataBytes;
1859 private byte[] blockData;
1860 private boolean useSubclassMethod;
1861 private int nextOID;
1862 private boolean resolveEnabled;
1863 private Hashtable objectLookupTable;
1864 private Object currentObject;
1865 private ObjectStreamClass currentObjectStreamClass;
1866 private boolean readDataFromBlock;
1867 private boolean isDeserializing;
1868 private boolean fieldsAlreadyRead;
1869 private Vector validators;
1870 private Hashtable classLookupTable;
1871 private GetField prereadFields;
1873 private static boolean dump = false && Configuration.DEBUG;
1875 private ClassLoader callersClassLoader;
1877 // The nesting depth for debugging output
1878 private int depth = 0;
1880 private void dumpElement (String msg)
1882 System.out.print(msg);
1885 private void dumpElementln (String msg)
1887 System.out.println(msg);
1888 for (int i = 0; i < depth; i++)
1889 System.out.print (" ");
1890 System.out.print (Thread.currentThread() + ": ");
1895 if (Configuration.INIT_LOAD_LIBRARY)
1897 System.loadLibrary ("javaio");
1903 // used to keep a prioritized list of object validators
1904 class ValidatorAndPriority implements Comparable
1907 ObjectInputValidation validator;
1909 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1911 this.priority = priority;
1912 this.validator = validator;
1915 public int compareTo (Object o)
1917 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1918 return this.priority - vap.priority;