* Merge from mainline (tree-profiling-merge-20050603)
[official-gcc.git] / libjava / java / io / ObjectInputStream.java
blob3bcfd05f58161c23801b83972f89214fa419ab29
1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.io;
42 import gnu.classpath.Configuration;
43 import gnu.java.io.ObjectIdentityWrapper;
45 import java.lang.reflect.Array;
46 import java.lang.reflect.Constructor;
47 import java.lang.reflect.Field;
48 import java.lang.reflect.InvocationTargetException;
49 import java.lang.reflect.Method;
50 import java.lang.reflect.Modifier;
51 import java.lang.reflect.Proxy;
52 import java.security.AccessController;
53 import java.security.PrivilegedAction;
54 import java.util.Arrays;
55 import java.util.Hashtable;
56 import java.util.Vector;
58 public class ObjectInputStream extends InputStream
59 implements ObjectInput, ObjectStreamConstants
61 /**
62 * Creates a new <code>ObjectInputStream</code> that will do all of
63 * its reading from <code>in</code>. This method also checks
64 * the stream by reading the header information (stream magic number
65 * and stream version).
67 * @exception IOException Reading stream header from underlying
68 * stream cannot be completed.
70 * @exception StreamCorruptedException An invalid stream magic
71 * number or stream version was read from the stream.
73 * @see #readStreamHeader()
75 public ObjectInputStream(InputStream in)
76 throws IOException, StreamCorruptedException
78 if (Configuration.DEBUG)
80 String val = System.getProperty("gcj.dumpobjects");
81 if (dump == false && val != null && !val.equals(""))
83 dump = true;
84 System.out.println ("Serialization debugging enabled");
86 else if (dump == true && (val == null || val.equals("")))
88 dump = false;
89 System.out.println ("Serialization debugging disabled");
93 this.resolveEnabled = false;
94 this.isDeserializing = false;
95 this.blockDataPosition = 0;
96 this.blockDataBytes = 0;
97 this.blockData = new byte[BUFFER_SIZE];
98 this.blockDataInput = new DataInputStream(this);
99 this.realInputStream = new DataInputStream(in);
100 this.nextOID = baseWireHandle;
101 this.objectLookupTable = new Hashtable();
102 this.validators = new Vector();
103 this.classLookupTable = new Hashtable();
104 setBlockDataMode(true);
105 readStreamHeader();
110 * Returns the next deserialized object read from the underlying stream.
112 * This method can be overriden by a class by implementing
113 * <code>private void readObject (ObjectInputStream)</code>.
115 * If an exception is thrown from this method, the stream is left in
116 * an undefined state.
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;
131 Object ret_val;
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();
141 depth += 2;
143 if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
147 switch (marker)
149 case TC_ENDBLOCKDATA:
151 ret_val = null;
152 is_consumed = true;
153 break;
156 case TC_BLOCKDATA:
157 case TC_BLOCKDATALONG:
159 if (marker == TC_BLOCKDATALONG)
160 { if(dump) dumpElementln("BLOCKDATALONG"); }
161 else
162 { if(dump) dumpElementln("BLOCKDATA"); }
163 readNextBlock(marker);
164 throw new StreamCorruptedException("Unexpected blockData");
167 case TC_NULL:
169 if(dump) dumpElementln("NULL");
170 ret_val = null;
171 break;
174 case TC_REFERENCE:
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;
181 break;
184 case TC_CLASS:
186 if(dump) dumpElementln("CLASS");
187 ObjectStreamClass osc = (ObjectStreamClass)readObject();
188 Class clazz = osc.forClass();
189 assignNewHandle(clazz);
190 ret_val = clazz;
191 break;
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);
212 if (!is_consumed)
214 byte b = this.realInputStream.readByte();
215 if (b != TC_ENDBLOCKDATA)
216 throw new IOException("Data annotated to class was not consumed." + b);
218 else
219 is_consumed = false;
220 ObjectStreamClass superosc = (ObjectStreamClass)readObject();
221 osc.setSuperclass(superosc);
222 ret_val = osc;
223 break;
226 case TC_CLASSDESC:
228 ObjectStreamClass osc = readClassDescriptor();
230 if (!is_consumed)
232 byte b = this.realInputStream.readByte();
233 if (b != TC_ENDBLOCKDATA)
234 throw new IOException("Data annotated to class was not consumed." + b);
236 else
237 is_consumed = false;
239 osc.setSuperclass ((ObjectStreamClass)readObject());
240 ret_val = osc;
241 break;
244 case TC_STRING:
245 case TC_LONGSTRING:
247 if(dump) dumpElement("STRING=");
248 String s = this.realInputStream.readUTF();
249 if(dump) dumpElementln(s);
250 ret_val = processResolution(null, s, assignNewHandle(s));
251 break;
254 case TC_ARRAY:
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);
265 if(dump)
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);
269 break;
272 case TC_OBJECT:
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);
299 if (!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);
305 break;
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);
337 else
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
350 // the logic.
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)
358 // {
359 // if(dump) dumpElementln("no, got EOFException");
360 // }
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);
372 break;
375 case TC_RESET:
376 if(dump) dumpElementln("RESET");
377 clearHandles();
378 ret_val = readObject();
379 break;
381 case TC_EXCEPTION:
383 if(dump) dumpElement("EXCEPTION=");
384 Exception e = (Exception)readObject();
385 if(dump) dumpElementln(e.toString());
386 clearHandles();
387 throw new WriteAbortedException("Exception thrown during writing of stream", e);
390 default:
391 throw new IOException("Unknown marker on stream: " + marker);
394 finally
396 setBlockDataMode(old_mode);
398 this.isDeserializing = was_deserializing;
400 depth -= 2;
402 if (! was_deserializing)
404 if (validators.size() > 0)
405 invokeValidators();
409 return ret_val;
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)
437 return;
439 int i = 0;
440 ObjectStreamField f1;
441 ObjectStreamField f2;
443 while (i < fields2.length
444 && nonPrimitive < fields1.length)
446 f1 = fields1[nonPrimitive];
447 f2 = fields2[i];
449 if (!f2.isPrimitive())
450 break;
452 int compVal = f1.getName().compareTo (f2.getName());
454 if (compVal < 0)
456 nonPrimitive++;
458 else if (compVal > 0)
460 i++;
462 else
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,
501 flags, fields);
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);
514 String class_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();
522 else
523 class_name = String.valueOf(type_code);
525 fields[i] =
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). */
531 Class clazz;
534 clazz = resolveClass(osc);
536 catch (ClassNotFoundException cnfe)
538 // Maybe it was an primitive class?
539 if (name.equals("void"))
540 clazz = Void.TYPE;
541 else if (name.equals("boolean"))
542 clazz = Boolean.TYPE;
543 else if (name.equals("byte"))
544 clazz = Byte.TYPE;
545 else if (name.equals("short"))
546 clazz = Short.TYPE;
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"))
552 clazz = Long.TYPE;
553 else if (name.equals("float"))
554 clazz = Float.TYPE;
555 else if (name.equals("double"))
556 clazz = Double.TYPE;
557 else
558 throw cnfe;
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;
575 else
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()
585 public Object run()
589 Constructor c = local_constructor_class.
590 getDeclaredConstructor(new Class[0]);
591 if (Modifier.isPrivate(c.getModifiers()))
592 return null;
593 return c;
595 catch (NoSuchMethodException e)
597 // error will be reported later, in newObject()
598 return null;
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)];
610 int stream_idx = 0;
611 int real_idx = 0;
612 int map_idx = 0;
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++];
637 else
639 int comp_val =
640 real_fields[real_idx].compareTo (stream_fields[stream_idx]);
642 if (comp_val < 0)
644 real_field = real_fields[real_idx++];
646 else if (comp_val > 0)
648 stream_field = stream_fields[stream_idx++];
650 else
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;
677 return osc;
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>
686 * method.
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>
694 * method.
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
726 * called first.
728 * @see java.io.ObjectInputValidation
730 * @exception InvalidObjectException <code>validator</code> is
731 * <code>null</code>
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,
738 int priority)
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,
750 priority));
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 ();
776 if (Configuration.DEBUG && dump)
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 // GCJ LOCAL: native method.
790 private native ClassLoader currentLoader();
793 * Lookup a class stored in the local hashtable. If it is not
794 * use the global lookup function in ObjectStreamClass to build
795 * the ObjectStreamClass. This method is requested according to
796 * the behaviour detected in the JDK by Kaffe's team.
798 * @param clazz Class to lookup in the hash table or for which
799 * we must build a descriptor.
800 * @return A valid instance of ObjectStreamClass corresponding
801 * to the specified class.
803 private ObjectStreamClass lookupClass(Class clazz)
805 if (clazz == null)
806 return null;
808 ObjectStreamClass oclazz;
809 oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
810 if (oclazz == null)
811 return ObjectStreamClass.lookup(clazz);
812 else
813 return oclazz;
817 * Reconstruct class hierarchy the same way
818 * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
819 * but using lookupClass instead of ObjectStreamClass.lookup. This
820 * dup is necessary localize the lookup table. Hopefully some future
821 * rewritings will be able to prevent this.
823 * @param clazz This is the class for which we want the hierarchy.
825 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
826 * represent the class hierarchy for clazz.
828 private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
830 ObjectStreamClass osc = lookupClass(clazz);
832 if (osc == null)
833 return new ObjectStreamClass[0];
834 else
836 Vector oscs = new Vector();
838 while (osc != null)
840 oscs.addElement(osc);
841 osc = osc.getSuper();
844 int count = oscs.size();
845 ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
847 for (int i = count - 1; i >= 0; i--)
848 sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
850 return sorted_oscs;
855 * Allows subclasses to resolve objects that are read from the
856 * stream with other objects to be returned in their place. This
857 * method is called the first time each object is encountered.
859 * This method must be enabled before it will be called in the
860 * serialization process.
862 * @exception IOException Exception from underlying
863 * <code>OutputStream</code>.
865 * @see #enableResolveObject(boolean)
867 protected Object resolveObject(Object obj) throws IOException
869 return obj;
873 protected Class resolveProxyClass(String[] intfs)
874 throws IOException, ClassNotFoundException
876 ClassLoader cl = currentLoader();
878 Class[] clss = new Class[intfs.length];
879 if(cl == null)
881 for (int i = 0; i < intfs.length; i++)
882 clss[i] = Class.forName(intfs[i]);
883 cl = ClassLoader.getSystemClassLoader();
885 else
886 for (int i = 0; i < intfs.length; i++)
887 clss[i] = cl.loadClass(intfs[i]);
888 try
890 return Proxy.getProxyClass(cl, clss);
892 catch (IllegalArgumentException e)
894 throw new ClassNotFoundException(null, e);
899 * If <code>enable</code> is <code>true</code> and this object is
900 * trusted, then <code>resolveObject (Object)</code> will be called
901 * in subsequent calls to <code>readObject (Object)</code>.
902 * Otherwise, <code>resolveObject (Object)</code> will not be called.
904 * @exception SecurityException This class is not trusted.
906 protected boolean enableResolveObject (boolean enable)
907 throws SecurityException
909 if (enable)
911 SecurityManager sm = System.getSecurityManager();
912 if (sm != null)
913 sm.checkPermission(new SerializablePermission("enableSubstitution"));
916 boolean old_val = this.resolveEnabled;
917 this.resolveEnabled = enable;
918 return old_val;
922 * Reads stream magic and stream version information from the
923 * underlying stream.
925 * @exception IOException Exception from underlying stream.
927 * @exception StreamCorruptedException An invalid stream magic
928 * number or stream version was read from the stream.
930 protected void readStreamHeader()
931 throws IOException, StreamCorruptedException
933 if(dump) dumpElement("STREAM MAGIC ");
934 if (this.realInputStream.readShort() != STREAM_MAGIC)
935 throw new StreamCorruptedException("Invalid stream magic number");
937 if(dump) dumpElementln("STREAM VERSION ");
938 if (this.realInputStream.readShort() != STREAM_VERSION)
939 throw new StreamCorruptedException("Invalid stream version number");
942 public int read() throws IOException
944 if (this.readDataFromBlock)
946 if (this.blockDataPosition >= this.blockDataBytes)
947 readNextBlock();
948 return (this.blockData[this.blockDataPosition++] & 0xff);
950 else
951 return this.realInputStream.read();
954 public int read(byte[] data, int offset, int length) throws IOException
956 if (this.readDataFromBlock)
958 if (this.blockDataPosition + length > this.blockDataBytes)
960 int remain = this.blockDataBytes - this.blockDataPosition;
961 if (remain != 0)
963 System.arraycopy(this.blockData, this.blockDataPosition,
964 data, offset, remain);
965 offset += remain;
966 length -= remain;
968 readNextBlock ();
971 System.arraycopy(this.blockData, this.blockDataPosition,
972 data, offset, length);
973 this.blockDataPosition += length;
975 return length;
977 else
978 return this.realInputStream.read(data, offset, length);
981 public int available() throws IOException
983 if (this.readDataFromBlock)
985 if (this.blockDataPosition >= this.blockDataBytes)
986 readNextBlock ();
988 return this.blockDataBytes - this.blockDataPosition;
990 else
991 return this.realInputStream.available();
994 public void close() throws IOException
996 this.realInputStream.close();
999 public boolean readBoolean() throws IOException
1001 boolean switchmode = true;
1002 boolean oldmode = this.readDataFromBlock;
1003 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1004 switchmode = false;
1005 if (switchmode)
1006 oldmode = setBlockDataMode (true);
1007 boolean value = this.dataInputStream.readBoolean ();
1008 if (switchmode)
1009 setBlockDataMode (oldmode);
1010 return value;
1013 public byte readByte() throws IOException
1015 boolean switchmode = true;
1016 boolean oldmode = this.readDataFromBlock;
1017 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1018 switchmode = false;
1019 if (switchmode)
1020 oldmode = setBlockDataMode(true);
1021 byte value = this.dataInputStream.readByte();
1022 if (switchmode)
1023 setBlockDataMode(oldmode);
1024 return value;
1027 public int readUnsignedByte() throws IOException
1029 boolean switchmode = true;
1030 boolean oldmode = this.readDataFromBlock;
1031 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1032 switchmode = false;
1033 if (switchmode)
1034 oldmode = setBlockDataMode(true);
1035 int value = this.dataInputStream.readUnsignedByte();
1036 if (switchmode)
1037 setBlockDataMode(oldmode);
1038 return value;
1041 public short readShort() throws IOException
1043 boolean switchmode = true;
1044 boolean oldmode = this.readDataFromBlock;
1045 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1046 switchmode = false;
1047 if (switchmode)
1048 oldmode = setBlockDataMode(true);
1049 short value = this.dataInputStream.readShort();
1050 if (switchmode)
1051 setBlockDataMode(oldmode);
1052 return value;
1055 public int readUnsignedShort() throws IOException
1057 boolean switchmode = true;
1058 boolean oldmode = this.readDataFromBlock;
1059 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1060 switchmode = false;
1061 if (switchmode)
1062 oldmode = setBlockDataMode(true);
1063 int value = this.dataInputStream.readUnsignedShort();
1064 if (switchmode)
1065 setBlockDataMode(oldmode);
1066 return value;
1069 public char readChar() throws IOException
1071 boolean switchmode = true;
1072 boolean oldmode = this.readDataFromBlock;
1073 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1074 switchmode = false;
1075 if (switchmode)
1076 oldmode = setBlockDataMode(true);
1077 char value = this.dataInputStream.readChar();
1078 if (switchmode)
1079 setBlockDataMode(oldmode);
1080 return value;
1083 public int readInt() throws IOException
1085 boolean switchmode = true;
1086 boolean oldmode = this.readDataFromBlock;
1087 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1088 switchmode = false;
1089 if (switchmode)
1090 oldmode = setBlockDataMode(true);
1091 int value = this.dataInputStream.readInt();
1092 if (switchmode)
1093 setBlockDataMode(oldmode);
1094 return value;
1097 public long readLong() throws IOException
1099 boolean switchmode = true;
1100 boolean oldmode = this.readDataFromBlock;
1101 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1102 switchmode = false;
1103 if (switchmode)
1104 oldmode = setBlockDataMode(true);
1105 long value = this.dataInputStream.readLong();
1106 if (switchmode)
1107 setBlockDataMode(oldmode);
1108 return value;
1111 public float readFloat() throws IOException
1113 boolean switchmode = true;
1114 boolean oldmode = this.readDataFromBlock;
1115 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1116 switchmode = false;
1117 if (switchmode)
1118 oldmode = setBlockDataMode(true);
1119 float value = this.dataInputStream.readFloat();
1120 if (switchmode)
1121 setBlockDataMode(oldmode);
1122 return value;
1125 public double readDouble() throws IOException
1127 boolean switchmode = true;
1128 boolean oldmode = this.readDataFromBlock;
1129 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1130 switchmode = false;
1131 if (switchmode)
1132 oldmode = setBlockDataMode(true);
1133 double value = this.dataInputStream.readDouble();
1134 if (switchmode)
1135 setBlockDataMode(oldmode);
1136 return value;
1139 public void readFully(byte data[]) throws IOException
1141 this.dataInputStream.readFully(data);
1144 public void readFully(byte data[], int offset, int size)
1145 throws IOException
1147 this.dataInputStream.readFully(data, offset, size);
1150 public int skipBytes(int len) throws IOException
1152 return this.dataInputStream.skipBytes(len);
1156 * @deprecated
1157 * @see java.io.DataInputStream#readLine ()
1159 public String readLine() throws IOException
1161 return this.dataInputStream.readLine();
1164 public String readUTF() throws IOException
1166 return this.dataInputStream.readUTF();
1170 * This class allows a class to specify exactly which fields should
1171 * be read, and what values should be read for these fields.
1173 * XXX: finish up comments
1175 public abstract static class GetField
1177 public abstract ObjectStreamClass getObjectStreamClass();
1179 public abstract boolean defaulted(String name)
1180 throws IOException, IllegalArgumentException;
1182 public abstract boolean get(String name, boolean defvalue)
1183 throws IOException, IllegalArgumentException;
1185 public abstract char get(String name, char defvalue)
1186 throws IOException, IllegalArgumentException;
1188 public abstract byte get(String name, byte defvalue)
1189 throws IOException, IllegalArgumentException;
1191 public abstract short get(String name, short defvalue)
1192 throws IOException, IllegalArgumentException;
1194 public abstract int get(String name, int defvalue)
1195 throws IOException, IllegalArgumentException;
1197 public abstract long get(String name, long defvalue)
1198 throws IOException, IllegalArgumentException;
1200 public abstract float get(String name, float defvalue)
1201 throws IOException, IllegalArgumentException;
1203 public abstract double get(String name, double defvalue)
1204 throws IOException, IllegalArgumentException;
1206 public abstract Object get(String name, Object defvalue)
1207 throws IOException, IllegalArgumentException;
1211 * This method should be called by a method called 'readObject' in the
1212 * deserializing class (if present). It cannot (and should not)be called
1213 * outside of it. Its goal is to read all fields in the real input stream
1214 * and keep them accessible through the {@link #GetField} class. Calling
1215 * this method will not alter the deserializing object.
1217 * @return A valid freshly created 'GetField' instance to get access to
1218 * the deserialized stream.
1219 * @throws IOException An input/output exception occured.
1220 * @throws ClassNotFoundException
1221 * @throws NotActiveException
1223 public GetField readFields()
1224 throws IOException, ClassNotFoundException, NotActiveException
1226 if (this.currentObject == null || this.currentObjectStreamClass == null)
1227 throw new NotActiveException("readFields called by non-active class and/or object");
1229 if (prereadFields != null)
1230 return prereadFields;
1232 if (fieldsAlreadyRead)
1233 throw new NotActiveException("readFields called but fields already read from"
1234 + " stream (by defaultReadObject or readFields)");
1236 final ObjectStreamClass clazz = this.currentObjectStreamClass;
1237 final byte[] prim_field_data = new byte[clazz.primFieldSize];
1238 final Object[] objs = new Object[clazz.objectFieldCount];
1240 // Apparently Block data is not used with GetField as per
1241 // empirical evidence against JDK 1.2. Also see Mauve test
1242 // java.io.ObjectInputOutput.Test.GetPutField.
1243 boolean oldmode = setBlockDataMode(false);
1244 readFully(prim_field_data);
1245 for (int i = 0; i < objs.length; ++ i)
1246 objs[i] = readObject();
1247 setBlockDataMode(oldmode);
1249 prereadFields = new GetField()
1251 public ObjectStreamClass getObjectStreamClass()
1253 return clazz;
1256 public boolean defaulted(String name)
1257 throws IOException, IllegalArgumentException
1259 ObjectStreamField f = clazz.getField(name);
1261 /* First if we have a serialized field use the descriptor */
1262 if (f != null)
1264 /* It is in serialPersistentFields but setClass tells us
1265 * it should not be set. This value is defaulted.
1267 if (f.isPersistent() && !f.isToSet())
1268 return true;
1270 return false;
1273 /* This is not a serialized field. There should be
1274 * a default value only if the field really exists.
1278 return (clazz.forClass().getDeclaredField (name) != null);
1280 catch (NoSuchFieldException e)
1282 throw new IllegalArgumentException(e.getMessage());
1286 public boolean get(String name, boolean defvalue)
1287 throws IOException, IllegalArgumentException
1289 ObjectStreamField field = getField(name, Boolean.TYPE);
1291 if (field == null)
1292 return defvalue;
1294 return prim_field_data[field.getOffset()] == 0 ? false : true;
1297 public char get(String name, char defvalue)
1298 throws IOException, IllegalArgumentException
1300 ObjectStreamField field = getField(name, Character.TYPE);
1302 if (field == null)
1303 return defvalue;
1305 int off = field.getOffset();
1307 return (char)(((prim_field_data[off++] & 0xFF) << 8)
1308 | (prim_field_data[off] & 0xFF));
1311 public byte get(String name, byte defvalue)
1312 throws IOException, IllegalArgumentException
1314 ObjectStreamField field = getField(name, Byte.TYPE);
1316 if (field == null)
1317 return defvalue;
1319 return prim_field_data[field.getOffset()];
1322 public short get(String name, short defvalue)
1323 throws IOException, IllegalArgumentException
1325 ObjectStreamField field = getField(name, Short.TYPE);
1327 if (field == null)
1328 return defvalue;
1330 int off = field.getOffset();
1332 return (short)(((prim_field_data[off++] & 0xFF) << 8)
1333 | (prim_field_data[off] & 0xFF));
1336 public int get(String name, int defvalue)
1337 throws IOException, IllegalArgumentException
1339 ObjectStreamField field = getField(name, Integer.TYPE);
1341 if (field == null)
1342 return defvalue;
1344 int off = field.getOffset();
1346 return ((prim_field_data[off++] & 0xFF) << 24)
1347 | ((prim_field_data[off++] & 0xFF) << 16)
1348 | ((prim_field_data[off++] & 0xFF) << 8)
1349 | (prim_field_data[off] & 0xFF);
1352 public long get(String name, long defvalue)
1353 throws IOException, IllegalArgumentException
1355 ObjectStreamField field = getField(name, Long.TYPE);
1357 if (field == null)
1358 return defvalue;
1360 int off = field.getOffset();
1362 return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1363 | ((prim_field_data[off++] & 0xFFL) << 48)
1364 | ((prim_field_data[off++] & 0xFFL) << 40)
1365 | ((prim_field_data[off++] & 0xFFL) << 32)
1366 | ((prim_field_data[off++] & 0xFF) << 24)
1367 | ((prim_field_data[off++] & 0xFF) << 16)
1368 | ((prim_field_data[off++] & 0xFF) << 8)
1369 | (prim_field_data[off] & 0xFF));
1372 public float get(String name, float defvalue)
1373 throws IOException, IllegalArgumentException
1375 ObjectStreamField field = getField(name, Float.TYPE);
1377 if (field == null)
1378 return defvalue;
1380 int off = field.getOffset();
1382 return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1383 | ((prim_field_data[off++] & 0xFF) << 16)
1384 | ((prim_field_data[off++] & 0xFF) << 8)
1385 | (prim_field_data[off] & 0xFF));
1388 public double get(String name, double defvalue)
1389 throws IOException, IllegalArgumentException
1391 ObjectStreamField field = getField(name, Double.TYPE);
1393 if (field == null)
1394 return defvalue;
1396 int off = field.getOffset();
1398 return Double.longBitsToDouble
1399 ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1400 | ((prim_field_data[off++] & 0xFFL) << 48)
1401 | ((prim_field_data[off++] & 0xFFL) << 40)
1402 | ((prim_field_data[off++] & 0xFFL) << 32)
1403 | ((prim_field_data[off++] & 0xFF) << 24)
1404 | ((prim_field_data[off++] & 0xFF) << 16)
1405 | ((prim_field_data[off++] & 0xFF) << 8)
1406 | (prim_field_data[off] & 0xFF)));
1409 public Object get(String name, Object defvalue)
1410 throws IOException, IllegalArgumentException
1412 ObjectStreamField field =
1413 getField(name, defvalue == null ? null : defvalue.getClass ());
1415 if (field == null)
1416 return defvalue;
1418 return objs[field.getOffset()];
1421 private ObjectStreamField getField(String name, Class type)
1422 throws IllegalArgumentException
1424 ObjectStreamField field = clazz.getField(name);
1425 boolean illegal = false;
1431 Class field_type = field.getType();
1433 if (type == field_type ||
1434 (type == null && !field_type.isPrimitive()))
1436 /* See defaulted */
1437 return field;
1440 illegal = true;
1441 throw new IllegalArgumentException
1442 ("Field requested is of type "
1443 + field_type.getName()
1444 + ", but requested type was "
1445 + (type == null ? "Object" : type.getName()));
1447 catch (NullPointerException _)
1449 /* Here we catch NullPointerException, because it may
1450 only come from the call 'field.getType()'. If field
1451 is null, we have to return null and classpath ethic
1452 say we must try to avoid 'if (xxx == null)'.
1455 catch (IllegalArgumentException e)
1457 throw e;
1460 return null;
1462 finally
1464 /* If this is an unassigned field we should return
1465 * the default value.
1467 if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1468 return null;
1470 /* We do not want to modify transient fields. They should
1471 * be left to 0.
1475 Field f = clazz.forClass().getDeclaredField(name);
1476 if (Modifier.isTransient(f.getModifiers()))
1477 throw new IllegalArgumentException
1478 ("no such field (non transient) " + name);
1479 if (field == null && f.getType() != type)
1480 throw new IllegalArgumentException
1481 ("Invalid requested type for field " + name);
1483 catch (NoSuchFieldException e)
1485 if (field == null)
1486 throw new IllegalArgumentException(e.getMessage());
1493 fieldsAlreadyRead = true;
1494 return prereadFields;
1498 * Protected constructor that allows subclasses to override
1499 * deserialization. This constructor should be called by subclasses
1500 * that wish to override <code>readObject (Object)</code>. This
1501 * method does a security check <i>NOTE: currently not
1502 * implemented</i>, then sets a flag that informs
1503 * <code>readObject (Object)</code> to call the subclasses
1504 * <code>readObjectOverride (Object)</code> method.
1506 * @see #readObjectOverride()
1508 protected ObjectInputStream()
1509 throws IOException, SecurityException
1511 SecurityManager sec_man = System.getSecurityManager();
1512 if (sec_man != null)
1513 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1514 this.useSubclassMethod = true;
1518 * This method allows subclasses to override the default
1519 * de serialization mechanism provided by
1520 * <code>ObjectInputStream</code>. To make this method be used for
1521 * writing objects, subclasses must invoke the 0-argument
1522 * constructor on this class from their constructor.
1524 * @see #ObjectInputStream()
1526 protected Object readObjectOverride()
1527 throws ClassNotFoundException, IOException, OptionalDataException
1529 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1533 * Assigns the next available handle to <code>obj</code>.
1535 * @param obj The object for which we want a new handle.
1536 * @return A valid handle for the specified object.
1538 private int assignNewHandle(Object obj)
1540 this.objectLookupTable.put(new Integer(this.nextOID),
1541 new ObjectIdentityWrapper(obj));
1542 return this.nextOID++;
1545 private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
1546 throws IOException
1548 if (osc != null && obj instanceof Serializable)
1552 Method m = osc.readResolveMethod;
1553 if(m != null)
1555 obj = m.invoke(obj, new Object[] {});
1558 catch (IllegalAccessException ignore)
1561 catch (InvocationTargetException ignore)
1566 if (this.resolveEnabled)
1567 obj = resolveObject(obj);
1569 this.objectLookupTable.put(new Integer(handle),
1570 new ObjectIdentityWrapper(obj));
1572 return obj;
1575 private void clearHandles()
1577 this.objectLookupTable.clear();
1578 this.nextOID = baseWireHandle;
1581 private void readNextBlock() throws IOException
1583 readNextBlock(this.realInputStream.readByte());
1586 private void readNextBlock(byte marker) throws IOException
1588 if (marker == TC_BLOCKDATA)
1590 if(dump) dumpElement("BLOCK DATA SIZE=");
1591 this.blockDataBytes = this.realInputStream.readUnsignedByte();
1592 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1594 else if (marker == TC_BLOCKDATALONG)
1596 if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1597 this.blockDataBytes = this.realInputStream.readInt();
1598 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1600 else
1602 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1605 if (this.blockData.length < this.blockDataBytes)
1606 this.blockData = new byte[this.blockDataBytes];
1608 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1609 this.blockDataPosition = 0;
1612 private void readArrayElements (Object array, Class clazz)
1613 throws ClassNotFoundException, IOException
1615 if (clazz.isPrimitive())
1617 if (clazz == Boolean.TYPE)
1619 boolean[] cast_array = (boolean[])array;
1620 for (int i=0; i < cast_array.length; i++)
1621 cast_array[i] = this.realInputStream.readBoolean();
1622 return;
1624 if (clazz == Byte.TYPE)
1626 byte[] cast_array = (byte[])array;
1627 for (int i=0; i < cast_array.length; i++)
1628 cast_array[i] = this.realInputStream.readByte();
1629 return;
1631 if (clazz == Character.TYPE)
1633 char[] cast_array = (char[])array;
1634 for (int i=0; i < cast_array.length; i++)
1635 cast_array[i] = this.realInputStream.readChar();
1636 return;
1638 if (clazz == Double.TYPE)
1640 double[] cast_array = (double[])array;
1641 for (int i=0; i < cast_array.length; i++)
1642 cast_array[i] = this.realInputStream.readDouble();
1643 return;
1645 if (clazz == Float.TYPE)
1647 float[] cast_array = (float[])array;
1648 for (int i=0; i < cast_array.length; i++)
1649 cast_array[i] = this.realInputStream.readFloat();
1650 return;
1652 if (clazz == Integer.TYPE)
1654 int[] cast_array = (int[])array;
1655 for (int i=0; i < cast_array.length; i++)
1656 cast_array[i] = this.realInputStream.readInt();
1657 return;
1659 if (clazz == Long.TYPE)
1661 long[] cast_array = (long[])array;
1662 for (int i=0; i < cast_array.length; i++)
1663 cast_array[i] = this.realInputStream.readLong();
1664 return;
1666 if (clazz == Short.TYPE)
1668 short[] cast_array = (short[])array;
1669 for (int i=0; i < cast_array.length; i++)
1670 cast_array[i] = this.realInputStream.readShort();
1671 return;
1674 else
1676 Object[] cast_array = (Object[])array;
1677 for (int i=0; i < cast_array.length; i++)
1678 cast_array[i] = readObject();
1682 private void readFields (Object obj, ObjectStreamClass stream_osc)
1683 throws ClassNotFoundException, IOException
1685 ObjectStreamField[] fields = stream_osc.fieldMapping;
1687 for (int i = 0; i < fields.length; i += 2)
1689 ObjectStreamField stream_field = fields[i];
1690 ObjectStreamField real_field = fields[i + 1];
1691 boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1692 boolean set_value = (real_field != null && real_field.isToSet());
1693 String field_name;
1694 char type;
1696 if (stream_field != null)
1698 field_name = stream_field.getName();
1699 type = stream_field.getTypeCode();
1701 else
1703 field_name = real_field.getName();
1704 type = real_field.getTypeCode();
1707 switch(type)
1709 case 'Z':
1711 boolean value =
1712 read_value ? this.realInputStream.readBoolean() : false;
1713 if (dump && read_value && set_value)
1714 dumpElementln(" " + field_name + ": " + value);
1715 if (set_value)
1716 real_field.setBooleanField(obj, value);
1717 break;
1719 case 'B':
1721 byte value =
1722 read_value ? this.realInputStream.readByte() : 0;
1723 if (dump && read_value && set_value)
1724 dumpElementln(" " + field_name + ": " + value);
1725 if (set_value)
1726 real_field.setByteField(obj, value);
1727 break;
1729 case 'C':
1731 char value =
1732 read_value ? this.realInputStream.readChar(): 0;
1733 if (dump && read_value && set_value)
1734 dumpElementln(" " + field_name + ": " + value);
1735 if (set_value)
1736 real_field.setCharField(obj, value);
1737 break;
1739 case 'D':
1741 double value =
1742 read_value ? this.realInputStream.readDouble() : 0;
1743 if (dump && read_value && set_value)
1744 dumpElementln(" " + field_name + ": " + value);
1745 if (set_value)
1746 real_field.setDoubleField(obj, value);
1747 break;
1749 case 'F':
1751 float value =
1752 read_value ? this.realInputStream.readFloat() : 0;
1753 if (dump && read_value && set_value)
1754 dumpElementln(" " + field_name + ": " + value);
1755 if (set_value)
1756 real_field.setFloatField(obj, value);
1757 break;
1759 case 'I':
1761 int value =
1762 read_value ? this.realInputStream.readInt() : 0;
1763 if (dump && read_value && set_value)
1764 dumpElementln(" " + field_name + ": " + value);
1765 if (set_value)
1766 real_field.setIntField(obj, value);
1767 break;
1769 case 'J':
1771 long value =
1772 read_value ? this.realInputStream.readLong() : 0;
1773 if (dump && read_value && set_value)
1774 dumpElementln(" " + field_name + ": " + value);
1775 if (set_value)
1776 real_field.setLongField(obj, value);
1777 break;
1779 case 'S':
1781 short value =
1782 read_value ? this.realInputStream.readShort() : 0;
1783 if (dump && read_value && set_value)
1784 dumpElementln(" " + field_name + ": " + value);
1785 if (set_value)
1786 real_field.setShortField(obj, value);
1787 break;
1789 case 'L':
1790 case '[':
1792 Object value =
1793 read_value ? readObject() : null;
1794 if (set_value)
1795 real_field.setObjectField(obj, value);
1796 break;
1798 default:
1799 throw new InternalError("Invalid type code: " + type);
1804 // Toggles writing primitive data to block-data buffer.
1805 private boolean setBlockDataMode (boolean on)
1807 boolean oldmode = this.readDataFromBlock;
1808 this.readDataFromBlock = on;
1810 if (on)
1811 this.dataInputStream = this.blockDataInput;
1812 else
1813 this.dataInputStream = this.realInputStream;
1814 return oldmode;
1817 // returns a new instance of REAL_CLASS that has been constructed
1818 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1819 private Object newObject (Class real_class, Constructor constructor)
1820 throws ClassNotFoundException, IOException
1822 if (constructor == null)
1823 throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
1826 return allocateObject(real_class, constructor.getDeclaringClass(), constructor);
1828 catch (InstantiationException e)
1830 throw new ClassNotFoundException
1831 ("Instance of " + real_class + " could not be created");
1835 // runs all registered ObjectInputValidations in prioritized order
1836 // on OBJ
1837 private void invokeValidators() throws InvalidObjectException
1839 Object[] validators = new Object[this.validators.size()];
1840 this.validators.copyInto (validators);
1841 Arrays.sort (validators);
1845 for (int i=0; i < validators.length; i++)
1846 ((ObjectInputValidation)validators[i]).validateObject();
1848 finally
1850 this.validators.removeAllElements();
1854 private void callReadMethod (Method readObject, Class klass, Object obj)
1855 throws ClassNotFoundException, IOException
1859 readObject.invoke(obj, new Object[] { this });
1861 catch (InvocationTargetException x)
1863 /* Rethrow if possible. */
1864 Throwable exception = x.getTargetException();
1865 if (exception instanceof RuntimeException)
1866 throw (RuntimeException) exception;
1867 if (exception instanceof IOException)
1868 throw (IOException) exception;
1869 if (exception instanceof ClassNotFoundException)
1870 throw (ClassNotFoundException) exception;
1872 throw new IOException("Exception thrown from readObject() on " +
1873 klass + ": " + exception.getClass().getName());
1875 catch (Exception x)
1877 throw new IOException("Failure invoking readObject() on " +
1878 klass + ": " + x.getClass().getName());
1881 // Invalidate fields which has been read through readFields.
1882 prereadFields = null;
1885 private native Object allocateObject(Class clazz, Class constr_clazz, Constructor constructor)
1886 throws InstantiationException;
1888 private static final int BUFFER_SIZE = 1024;
1890 private DataInputStream realInputStream;
1891 private DataInputStream dataInputStream;
1892 private DataInputStream blockDataInput;
1893 private int blockDataPosition;
1894 private int blockDataBytes;
1895 private byte[] blockData;
1896 private boolean useSubclassMethod;
1897 private int nextOID;
1898 private boolean resolveEnabled;
1899 private Hashtable objectLookupTable;
1900 private Object currentObject;
1901 private ObjectStreamClass currentObjectStreamClass;
1902 private boolean readDataFromBlock;
1903 private boolean isDeserializing;
1904 private boolean fieldsAlreadyRead;
1905 private Vector validators;
1906 private Hashtable classLookupTable;
1907 private GetField prereadFields;
1909 private ClassLoader callersClassLoader;
1910 private static boolean dump;
1912 // The nesting depth for debugging output
1913 private int depth = 0;
1915 private void dumpElement (String msg)
1917 System.out.print(msg);
1920 private void dumpElementln (String msg)
1922 System.out.println(msg);
1923 for (int i = 0; i < depth; i++)
1924 System.out.print (" ");
1925 System.out.print (Thread.currentThread() + ": ");
1928 static
1930 if (Configuration.INIT_LOAD_LIBRARY)
1932 System.loadLibrary ("javaio");
1936 // used to keep a prioritized list of object validators
1937 private static final class ValidatorAndPriority implements Comparable
1939 int priority;
1940 ObjectInputValidation validator;
1942 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1944 this.priority = priority;
1945 this.validator = validator;
1948 public int compareTo (Object o)
1950 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1951 return this.priority - vap.priority;