Merge from the pain train
[official-gcc.git] / libjava / java / io / ObjectInputStream.java
blob2cfe4c99419bdfee8d00a9243de70cece540305c
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 * This method invokes the method currentClassLoader for the
787 * current security manager (or build an empty one if it is not
788 * present).
790 * @return The most recent non-system ClassLoader on the execution stack.
791 * @see java.lang.SecurityManager#currentClassLoader()
793 private ClassLoader currentLoader()
795 SecurityManager sm = System.getSecurityManager();
796 if (sm == null)
797 sm = new SecurityManager () {};
799 return currentClassLoader(sm);
803 * Lookup a class stored in the local hashtable. If it is not
804 * use the global lookup function in ObjectStreamClass to build
805 * the ObjectStreamClass. This method is requested according to
806 * the behaviour detected in the JDK by Kaffe's team.
808 * @param clazz Class to lookup in the hash table or for which
809 * we must build a descriptor.
810 * @return A valid instance of ObjectStreamClass corresponding
811 * to the specified class.
813 private ObjectStreamClass lookupClass(Class clazz)
815 if (clazz == null)
816 return null;
818 ObjectStreamClass oclazz;
819 oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
820 if (oclazz == null)
821 return ObjectStreamClass.lookup(clazz);
822 else
823 return oclazz;
827 * Reconstruct class hierarchy the same way
828 * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
829 * but using lookupClass instead of ObjectStreamClass.lookup. This
830 * dup is necessary localize the lookup table. Hopefully some future
831 * rewritings will be able to prevent this.
833 * @param clazz This is the class for which we want the hierarchy.
835 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
836 * represent the class hierarchy for clazz.
838 private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
840 ObjectStreamClass osc = lookupClass(clazz);
842 if (osc == null)
843 return new ObjectStreamClass[0];
844 else
846 Vector oscs = new Vector();
848 while (osc != null)
850 oscs.addElement(osc);
851 osc = osc.getSuper();
854 int count = oscs.size();
855 ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
857 for (int i = count - 1; i >= 0; i--)
858 sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
860 return sorted_oscs;
865 * Allows subclasses to resolve objects that are read from the
866 * stream with other objects to be returned in their place. This
867 * method is called the first time each object is encountered.
869 * This method must be enabled before it will be called in the
870 * serialization process.
872 * @exception IOException Exception from underlying
873 * <code>OutputStream</code>.
875 * @see #enableResolveObject(boolean)
877 protected Object resolveObject(Object obj) throws IOException
879 return obj;
883 protected Class resolveProxyClass(String[] intfs)
884 throws IOException, ClassNotFoundException
886 SecurityManager sm = System.getSecurityManager();
888 if (sm == null)
889 sm = new SecurityManager() {};
891 ClassLoader cl = currentClassLoader(sm);
893 Class[] clss = new Class[intfs.length];
894 if(cl == null)
896 for (int i = 0; i < intfs.length; i++)
897 clss[i] = Class.forName(intfs[i]);
898 cl = ClassLoader.getSystemClassLoader();
900 else
901 for (int i = 0; i < intfs.length; i++)
902 clss[i] = cl.loadClass(intfs[i]);
903 try
905 return Proxy.getProxyClass(cl, clss);
907 catch (IllegalArgumentException e)
909 throw new ClassNotFoundException(null, e);
914 * If <code>enable</code> is <code>true</code> and this object is
915 * trusted, then <code>resolveObject (Object)</code> will be called
916 * in subsequent calls to <code>readObject (Object)</code>.
917 * Otherwise, <code>resolveObject (Object)</code> will not be called.
919 * @exception SecurityException This class is not trusted.
921 protected boolean enableResolveObject (boolean enable)
922 throws SecurityException
924 if (enable)
926 SecurityManager sm = System.getSecurityManager();
927 if (sm != null)
928 sm.checkPermission(new SerializablePermission("enableSubstitution"));
931 boolean old_val = this.resolveEnabled;
932 this.resolveEnabled = enable;
933 return old_val;
937 * Reads stream magic and stream version information from the
938 * underlying stream.
940 * @exception IOException Exception from underlying stream.
942 * @exception StreamCorruptedException An invalid stream magic
943 * number or stream version was read from the stream.
945 protected void readStreamHeader()
946 throws IOException, StreamCorruptedException
948 if(dump) dumpElement("STREAM MAGIC ");
949 if (this.realInputStream.readShort() != STREAM_MAGIC)
950 throw new StreamCorruptedException("Invalid stream magic number");
952 if(dump) dumpElementln("STREAM VERSION ");
953 if (this.realInputStream.readShort() != STREAM_VERSION)
954 throw new StreamCorruptedException("Invalid stream version number");
957 public int read() throws IOException
959 if (this.readDataFromBlock)
961 if (this.blockDataPosition >= this.blockDataBytes)
962 readNextBlock();
963 return (this.blockData[this.blockDataPosition++] & 0xff);
965 else
966 return this.realInputStream.read();
969 public int read(byte[] data, int offset, int length) throws IOException
971 if (this.readDataFromBlock)
973 if (this.blockDataPosition + length > this.blockDataBytes)
975 int remain = this.blockDataBytes - this.blockDataPosition;
976 if (remain != 0)
978 System.arraycopy(this.blockData, this.blockDataPosition,
979 data, offset, remain);
980 offset += remain;
981 length -= remain;
983 readNextBlock ();
986 System.arraycopy(this.blockData, this.blockDataPosition,
987 data, offset, length);
988 this.blockDataPosition += length;
990 return length;
992 else
993 return this.realInputStream.read(data, offset, length);
996 public int available() throws IOException
998 if (this.readDataFromBlock)
1000 if (this.blockDataPosition >= this.blockDataBytes)
1001 readNextBlock ();
1003 return this.blockDataBytes - this.blockDataPosition;
1005 else
1006 return this.realInputStream.available();
1009 public void close() throws IOException
1011 this.realInputStream.close();
1014 public boolean readBoolean() throws IOException
1016 boolean switchmode = true;
1017 boolean oldmode = this.readDataFromBlock;
1018 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1019 switchmode = false;
1020 if (switchmode)
1021 oldmode = setBlockDataMode (true);
1022 boolean value = this.dataInputStream.readBoolean ();
1023 if (switchmode)
1024 setBlockDataMode (oldmode);
1025 return value;
1028 public byte readByte() throws IOException
1030 boolean switchmode = true;
1031 boolean oldmode = this.readDataFromBlock;
1032 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1033 switchmode = false;
1034 if (switchmode)
1035 oldmode = setBlockDataMode(true);
1036 byte value = this.dataInputStream.readByte();
1037 if (switchmode)
1038 setBlockDataMode(oldmode);
1039 return value;
1042 public int readUnsignedByte() throws IOException
1044 boolean switchmode = true;
1045 boolean oldmode = this.readDataFromBlock;
1046 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1047 switchmode = false;
1048 if (switchmode)
1049 oldmode = setBlockDataMode(true);
1050 int value = this.dataInputStream.readUnsignedByte();
1051 if (switchmode)
1052 setBlockDataMode(oldmode);
1053 return value;
1056 public short readShort() throws IOException
1058 boolean switchmode = true;
1059 boolean oldmode = this.readDataFromBlock;
1060 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1061 switchmode = false;
1062 if (switchmode)
1063 oldmode = setBlockDataMode(true);
1064 short value = this.dataInputStream.readShort();
1065 if (switchmode)
1066 setBlockDataMode(oldmode);
1067 return value;
1070 public int readUnsignedShort() throws IOException
1072 boolean switchmode = true;
1073 boolean oldmode = this.readDataFromBlock;
1074 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1075 switchmode = false;
1076 if (switchmode)
1077 oldmode = setBlockDataMode(true);
1078 int value = this.dataInputStream.readUnsignedShort();
1079 if (switchmode)
1080 setBlockDataMode(oldmode);
1081 return value;
1084 public char readChar() throws IOException
1086 boolean switchmode = true;
1087 boolean oldmode = this.readDataFromBlock;
1088 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1089 switchmode = false;
1090 if (switchmode)
1091 oldmode = setBlockDataMode(true);
1092 char value = this.dataInputStream.readChar();
1093 if (switchmode)
1094 setBlockDataMode(oldmode);
1095 return value;
1098 public int readInt() throws IOException
1100 boolean switchmode = true;
1101 boolean oldmode = this.readDataFromBlock;
1102 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1103 switchmode = false;
1104 if (switchmode)
1105 oldmode = setBlockDataMode(true);
1106 int value = this.dataInputStream.readInt();
1107 if (switchmode)
1108 setBlockDataMode(oldmode);
1109 return value;
1112 public long readLong() throws IOException
1114 boolean switchmode = true;
1115 boolean oldmode = this.readDataFromBlock;
1116 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1117 switchmode = false;
1118 if (switchmode)
1119 oldmode = setBlockDataMode(true);
1120 long value = this.dataInputStream.readLong();
1121 if (switchmode)
1122 setBlockDataMode(oldmode);
1123 return value;
1126 public float readFloat() throws IOException
1128 boolean switchmode = true;
1129 boolean oldmode = this.readDataFromBlock;
1130 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1131 switchmode = false;
1132 if (switchmode)
1133 oldmode = setBlockDataMode(true);
1134 float value = this.dataInputStream.readFloat();
1135 if (switchmode)
1136 setBlockDataMode(oldmode);
1137 return value;
1140 public double readDouble() throws IOException
1142 boolean switchmode = true;
1143 boolean oldmode = this.readDataFromBlock;
1144 if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1145 switchmode = false;
1146 if (switchmode)
1147 oldmode = setBlockDataMode(true);
1148 double value = this.dataInputStream.readDouble();
1149 if (switchmode)
1150 setBlockDataMode(oldmode);
1151 return value;
1154 public void readFully(byte data[]) throws IOException
1156 this.dataInputStream.readFully(data);
1159 public void readFully(byte data[], int offset, int size)
1160 throws IOException
1162 this.dataInputStream.readFully(data, offset, size);
1165 public int skipBytes(int len) throws IOException
1167 return this.dataInputStream.skipBytes(len);
1171 * @deprecated
1172 * @see java.io.DataInputStream#readLine ()
1174 public String readLine() throws IOException
1176 return this.dataInputStream.readLine();
1179 public String readUTF() throws IOException
1181 return this.dataInputStream.readUTF();
1185 * This class allows a class to specify exactly which fields should
1186 * be read, and what values should be read for these fields.
1188 * XXX: finish up comments
1190 public abstract static class GetField
1192 public abstract ObjectStreamClass getObjectStreamClass();
1194 public abstract boolean defaulted(String name)
1195 throws IOException, IllegalArgumentException;
1197 public abstract boolean get(String name, boolean defvalue)
1198 throws IOException, IllegalArgumentException;
1200 public abstract char get(String name, char defvalue)
1201 throws IOException, IllegalArgumentException;
1203 public abstract byte get(String name, byte defvalue)
1204 throws IOException, IllegalArgumentException;
1206 public abstract short get(String name, short defvalue)
1207 throws IOException, IllegalArgumentException;
1209 public abstract int get(String name, int defvalue)
1210 throws IOException, IllegalArgumentException;
1212 public abstract long get(String name, long defvalue)
1213 throws IOException, IllegalArgumentException;
1215 public abstract float get(String name, float defvalue)
1216 throws IOException, IllegalArgumentException;
1218 public abstract double get(String name, double defvalue)
1219 throws IOException, IllegalArgumentException;
1221 public abstract Object get(String name, Object defvalue)
1222 throws IOException, IllegalArgumentException;
1226 * This method should be called by a method called 'readObject' in the
1227 * deserializing class (if present). It cannot (and should not)be called
1228 * outside of it. Its goal is to read all fields in the real input stream
1229 * and keep them accessible through the {@link #GetField} class. Calling
1230 * this method will not alter the deserializing object.
1232 * @return A valid freshly created 'GetField' instance to get access to
1233 * the deserialized stream.
1234 * @throws IOException An input/output exception occured.
1235 * @throws ClassNotFoundException
1236 * @throws NotActiveException
1238 public GetField readFields()
1239 throws IOException, ClassNotFoundException, NotActiveException
1241 if (this.currentObject == null || this.currentObjectStreamClass == null)
1242 throw new NotActiveException("readFields called by non-active class and/or object");
1244 if (prereadFields != null)
1245 return prereadFields;
1247 if (fieldsAlreadyRead)
1248 throw new NotActiveException("readFields called but fields already read from"
1249 + " stream (by defaultReadObject or readFields)");
1251 final ObjectStreamClass clazz = this.currentObjectStreamClass;
1252 final byte[] prim_field_data = new byte[clazz.primFieldSize];
1253 final Object[] objs = new Object[clazz.objectFieldCount];
1255 // Apparently Block data is not used with GetField as per
1256 // empirical evidence against JDK 1.2. Also see Mauve test
1257 // java.io.ObjectInputOutput.Test.GetPutField.
1258 boolean oldmode = setBlockDataMode(false);
1259 readFully(prim_field_data);
1260 for (int i = 0; i < objs.length; ++ i)
1261 objs[i] = readObject();
1262 setBlockDataMode(oldmode);
1264 prereadFields = new GetField()
1266 public ObjectStreamClass getObjectStreamClass()
1268 return clazz;
1271 public boolean defaulted(String name)
1272 throws IOException, IllegalArgumentException
1274 ObjectStreamField f = clazz.getField(name);
1276 /* First if we have a serialized field use the descriptor */
1277 if (f != null)
1279 /* It is in serialPersistentFields but setClass tells us
1280 * it should not be set. This value is defaulted.
1282 if (f.isPersistent() && !f.isToSet())
1283 return true;
1285 return false;
1288 /* This is not a serialized field. There should be
1289 * a default value only if the field really exists.
1293 return (clazz.forClass().getDeclaredField (name) != null);
1295 catch (NoSuchFieldException e)
1297 throw new IllegalArgumentException(e.getMessage());
1301 public boolean get(String name, boolean defvalue)
1302 throws IOException, IllegalArgumentException
1304 ObjectStreamField field = getField(name, Boolean.TYPE);
1306 if (field == null)
1307 return defvalue;
1309 return prim_field_data[field.getOffset()] == 0 ? false : true;
1312 public char get(String name, char defvalue)
1313 throws IOException, IllegalArgumentException
1315 ObjectStreamField field = getField(name, Character.TYPE);
1317 if (field == null)
1318 return defvalue;
1320 int off = field.getOffset();
1322 return (char)(((prim_field_data[off++] & 0xFF) << 8)
1323 | (prim_field_data[off] & 0xFF));
1326 public byte get(String name, byte defvalue)
1327 throws IOException, IllegalArgumentException
1329 ObjectStreamField field = getField(name, Byte.TYPE);
1331 if (field == null)
1332 return defvalue;
1334 return prim_field_data[field.getOffset()];
1337 public short get(String name, short defvalue)
1338 throws IOException, IllegalArgumentException
1340 ObjectStreamField field = getField(name, Short.TYPE);
1342 if (field == null)
1343 return defvalue;
1345 int off = field.getOffset();
1347 return (short)(((prim_field_data[off++] & 0xFF) << 8)
1348 | (prim_field_data[off] & 0xFF));
1351 public int get(String name, int defvalue)
1352 throws IOException, IllegalArgumentException
1354 ObjectStreamField field = getField(name, Integer.TYPE);
1356 if (field == null)
1357 return defvalue;
1359 int off = field.getOffset();
1361 return ((prim_field_data[off++] & 0xFF) << 24)
1362 | ((prim_field_data[off++] & 0xFF) << 16)
1363 | ((prim_field_data[off++] & 0xFF) << 8)
1364 | (prim_field_data[off] & 0xFF);
1367 public long get(String name, long defvalue)
1368 throws IOException, IllegalArgumentException
1370 ObjectStreamField field = getField(name, Long.TYPE);
1372 if (field == null)
1373 return defvalue;
1375 int off = field.getOffset();
1377 return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1378 | ((prim_field_data[off++] & 0xFFL) << 48)
1379 | ((prim_field_data[off++] & 0xFFL) << 40)
1380 | ((prim_field_data[off++] & 0xFFL) << 32)
1381 | ((prim_field_data[off++] & 0xFF) << 24)
1382 | ((prim_field_data[off++] & 0xFF) << 16)
1383 | ((prim_field_data[off++] & 0xFF) << 8)
1384 | (prim_field_data[off] & 0xFF));
1387 public float get(String name, float defvalue)
1388 throws IOException, IllegalArgumentException
1390 ObjectStreamField field = getField(name, Float.TYPE);
1392 if (field == null)
1393 return defvalue;
1395 int off = field.getOffset();
1397 return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1398 | ((prim_field_data[off++] & 0xFF) << 16)
1399 | ((prim_field_data[off++] & 0xFF) << 8)
1400 | (prim_field_data[off] & 0xFF));
1403 public double get(String name, double defvalue)
1404 throws IOException, IllegalArgumentException
1406 ObjectStreamField field = getField(name, Double.TYPE);
1408 if (field == null)
1409 return defvalue;
1411 int off = field.getOffset();
1413 return Double.longBitsToDouble
1414 ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1415 | ((prim_field_data[off++] & 0xFFL) << 48)
1416 | ((prim_field_data[off++] & 0xFFL) << 40)
1417 | ((prim_field_data[off++] & 0xFFL) << 32)
1418 | ((prim_field_data[off++] & 0xFF) << 24)
1419 | ((prim_field_data[off++] & 0xFF) << 16)
1420 | ((prim_field_data[off++] & 0xFF) << 8)
1421 | (prim_field_data[off] & 0xFF)));
1424 public Object get(String name, Object defvalue)
1425 throws IOException, IllegalArgumentException
1427 ObjectStreamField field =
1428 getField(name, defvalue == null ? null : defvalue.getClass ());
1430 if (field == null)
1431 return defvalue;
1433 return objs[field.getOffset()];
1436 private ObjectStreamField getField(String name, Class type)
1437 throws IllegalArgumentException
1439 ObjectStreamField field = clazz.getField(name);
1440 boolean illegal = false;
1446 Class field_type = field.getType();
1448 if (type == field_type ||
1449 (type == null && !field_type.isPrimitive()))
1451 /* See defaulted */
1452 return field;
1455 illegal = true;
1456 throw new IllegalArgumentException
1457 ("Field requested is of type "
1458 + field_type.getName()
1459 + ", but requested type was "
1460 + (type == null ? "Object" : type.getName()));
1462 catch (NullPointerException _)
1464 /* Here we catch NullPointerException, because it may
1465 only come from the call 'field.getType()'. If field
1466 is null, we have to return null and classpath ethic
1467 say we must try to avoid 'if (xxx == null)'.
1470 catch (IllegalArgumentException e)
1472 throw e;
1475 return null;
1477 finally
1479 /* If this is an unassigned field we should return
1480 * the default value.
1482 if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1483 return null;
1485 /* We do not want to modify transient fields. They should
1486 * be left to 0.
1490 Field f = clazz.forClass().getDeclaredField(name);
1491 if (Modifier.isTransient(f.getModifiers()))
1492 throw new IllegalArgumentException
1493 ("no such field (non transient) " + name);
1494 if (field == null && f.getType() != type)
1495 throw new IllegalArgumentException
1496 ("Invalid requested type for field " + name);
1498 catch (NoSuchFieldException e)
1500 if (field == null)
1501 throw new IllegalArgumentException(e.getMessage());
1508 fieldsAlreadyRead = true;
1509 return prereadFields;
1513 * Protected constructor that allows subclasses to override
1514 * deserialization. This constructor should be called by subclasses
1515 * that wish to override <code>readObject (Object)</code>. This
1516 * method does a security check <i>NOTE: currently not
1517 * implemented</i>, then sets a flag that informs
1518 * <code>readObject (Object)</code> to call the subclasses
1519 * <code>readObjectOverride (Object)</code> method.
1521 * @see #readObjectOverride()
1523 protected ObjectInputStream()
1524 throws IOException, SecurityException
1526 SecurityManager sec_man = System.getSecurityManager();
1527 if (sec_man != null)
1528 sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1529 this.useSubclassMethod = true;
1533 * This method allows subclasses to override the default
1534 * de serialization mechanism provided by
1535 * <code>ObjectInputStream</code>. To make this method be used for
1536 * writing objects, subclasses must invoke the 0-argument
1537 * constructor on this class from their constructor.
1539 * @see #ObjectInputStream()
1541 protected Object readObjectOverride()
1542 throws ClassNotFoundException, IOException, OptionalDataException
1544 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1548 * Assigns the next available handle to <code>obj</code>.
1550 * @param obj The object for which we want a new handle.
1551 * @return A valid handle for the specified object.
1553 private int assignNewHandle(Object obj)
1555 this.objectLookupTable.put(new Integer(this.nextOID),
1556 new ObjectIdentityWrapper(obj));
1557 return this.nextOID++;
1560 private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
1561 throws IOException
1563 if (osc != null && obj instanceof Serializable)
1567 Method m = osc.readResolveMethod;
1568 if(m != null)
1570 obj = m.invoke(obj, new Object[] {});
1573 catch (IllegalAccessException ignore)
1576 catch (InvocationTargetException ignore)
1581 if (this.resolveEnabled)
1582 obj = resolveObject(obj);
1584 this.objectLookupTable.put(new Integer(handle),
1585 new ObjectIdentityWrapper(obj));
1587 return obj;
1590 private void clearHandles()
1592 this.objectLookupTable.clear();
1593 this.nextOID = baseWireHandle;
1596 private void readNextBlock() throws IOException
1598 readNextBlock(this.realInputStream.readByte());
1601 private void readNextBlock(byte marker) throws IOException
1603 if (marker == TC_BLOCKDATA)
1605 if(dump) dumpElement("BLOCK DATA SIZE=");
1606 this.blockDataBytes = this.realInputStream.readUnsignedByte();
1607 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1609 else if (marker == TC_BLOCKDATALONG)
1611 if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1612 this.blockDataBytes = this.realInputStream.readInt();
1613 if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1615 else
1617 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1620 if (this.blockData.length < this.blockDataBytes)
1621 this.blockData = new byte[this.blockDataBytes];
1623 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1624 this.blockDataPosition = 0;
1627 private void readArrayElements (Object array, Class clazz)
1628 throws ClassNotFoundException, IOException
1630 if (clazz.isPrimitive())
1632 if (clazz == Boolean.TYPE)
1634 boolean[] cast_array = (boolean[])array;
1635 for (int i=0; i < cast_array.length; i++)
1636 cast_array[i] = this.realInputStream.readBoolean();
1637 return;
1639 if (clazz == Byte.TYPE)
1641 byte[] cast_array = (byte[])array;
1642 for (int i=0; i < cast_array.length; i++)
1643 cast_array[i] = this.realInputStream.readByte();
1644 return;
1646 if (clazz == Character.TYPE)
1648 char[] cast_array = (char[])array;
1649 for (int i=0; i < cast_array.length; i++)
1650 cast_array[i] = this.realInputStream.readChar();
1651 return;
1653 if (clazz == Double.TYPE)
1655 double[] cast_array = (double[])array;
1656 for (int i=0; i < cast_array.length; i++)
1657 cast_array[i] = this.realInputStream.readDouble();
1658 return;
1660 if (clazz == Float.TYPE)
1662 float[] cast_array = (float[])array;
1663 for (int i=0; i < cast_array.length; i++)
1664 cast_array[i] = this.realInputStream.readFloat();
1665 return;
1667 if (clazz == Integer.TYPE)
1669 int[] cast_array = (int[])array;
1670 for (int i=0; i < cast_array.length; i++)
1671 cast_array[i] = this.realInputStream.readInt();
1672 return;
1674 if (clazz == Long.TYPE)
1676 long[] cast_array = (long[])array;
1677 for (int i=0; i < cast_array.length; i++)
1678 cast_array[i] = this.realInputStream.readLong();
1679 return;
1681 if (clazz == Short.TYPE)
1683 short[] cast_array = (short[])array;
1684 for (int i=0; i < cast_array.length; i++)
1685 cast_array[i] = this.realInputStream.readShort();
1686 return;
1689 else
1691 Object[] cast_array = (Object[])array;
1692 for (int i=0; i < cast_array.length; i++)
1693 cast_array[i] = readObject();
1697 private void readFields (Object obj, ObjectStreamClass stream_osc)
1698 throws ClassNotFoundException, IOException
1700 ObjectStreamField[] fields = stream_osc.fieldMapping;
1702 for (int i = 0; i < fields.length; i += 2)
1704 ObjectStreamField stream_field = fields[i];
1705 ObjectStreamField real_field = fields[i + 1];
1706 boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1707 boolean set_value = (real_field != null && real_field.isToSet());
1708 String field_name;
1709 char type;
1711 if (stream_field != null)
1713 field_name = stream_field.getName();
1714 type = stream_field.getTypeCode();
1716 else
1718 field_name = real_field.getName();
1719 type = real_field.getTypeCode();
1722 switch(type)
1724 case 'Z':
1726 boolean value =
1727 read_value ? this.realInputStream.readBoolean() : false;
1728 if (dump && read_value && set_value)
1729 dumpElementln(" " + field_name + ": " + value);
1730 if (set_value)
1731 real_field.setBooleanField(obj, value);
1732 break;
1734 case 'B':
1736 byte value =
1737 read_value ? this.realInputStream.readByte() : 0;
1738 if (dump && read_value && set_value)
1739 dumpElementln(" " + field_name + ": " + value);
1740 if (set_value)
1741 real_field.setByteField(obj, value);
1742 break;
1744 case 'C':
1746 char value =
1747 read_value ? this.realInputStream.readChar(): 0;
1748 if (dump && read_value && set_value)
1749 dumpElementln(" " + field_name + ": " + value);
1750 if (set_value)
1751 real_field.setCharField(obj, value);
1752 break;
1754 case 'D':
1756 double value =
1757 read_value ? this.realInputStream.readDouble() : 0;
1758 if (dump && read_value && set_value)
1759 dumpElementln(" " + field_name + ": " + value);
1760 if (set_value)
1761 real_field.setDoubleField(obj, value);
1762 break;
1764 case 'F':
1766 float value =
1767 read_value ? this.realInputStream.readFloat() : 0;
1768 if (dump && read_value && set_value)
1769 dumpElementln(" " + field_name + ": " + value);
1770 if (set_value)
1771 real_field.setFloatField(obj, value);
1772 break;
1774 case 'I':
1776 int value =
1777 read_value ? this.realInputStream.readInt() : 0;
1778 if (dump && read_value && set_value)
1779 dumpElementln(" " + field_name + ": " + value);
1780 if (set_value)
1781 real_field.setIntField(obj, value);
1782 break;
1784 case 'J':
1786 long value =
1787 read_value ? this.realInputStream.readLong() : 0;
1788 if (dump && read_value && set_value)
1789 dumpElementln(" " + field_name + ": " + value);
1790 if (set_value)
1791 real_field.setLongField(obj, value);
1792 break;
1794 case 'S':
1796 short value =
1797 read_value ? this.realInputStream.readShort() : 0;
1798 if (dump && read_value && set_value)
1799 dumpElementln(" " + field_name + ": " + value);
1800 if (set_value)
1801 real_field.setShortField(obj, value);
1802 break;
1804 case 'L':
1805 case '[':
1807 Object value =
1808 read_value ? readObject() : null;
1809 if (set_value)
1810 real_field.setObjectField(obj, value);
1811 break;
1813 default:
1814 throw new InternalError("Invalid type code: " + type);
1819 // Toggles writing primitive data to block-data buffer.
1820 private boolean setBlockDataMode (boolean on)
1822 boolean oldmode = this.readDataFromBlock;
1823 this.readDataFromBlock = on;
1825 if (on)
1826 this.dataInputStream = this.blockDataInput;
1827 else
1828 this.dataInputStream = this.realInputStream;
1829 return oldmode;
1832 // returns a new instance of REAL_CLASS that has been constructed
1833 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1834 private Object newObject (Class real_class, Constructor constructor)
1835 throws ClassNotFoundException, IOException
1837 if (constructor == null)
1838 throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
1841 return allocateObject(real_class, constructor.getDeclaringClass(), constructor);
1843 catch (InstantiationException e)
1845 throw new ClassNotFoundException
1846 ("Instance of " + real_class + " could not be created");
1850 // runs all registered ObjectInputValidations in prioritized order
1851 // on OBJ
1852 private void invokeValidators() throws InvalidObjectException
1854 Object[] validators = new Object[this.validators.size()];
1855 this.validators.copyInto (validators);
1856 Arrays.sort (validators);
1860 for (int i=0; i < validators.length; i++)
1861 ((ObjectInputValidation)validators[i]).validateObject();
1863 finally
1865 this.validators.removeAllElements();
1870 * This native method is used to get access to the protected method
1871 * of the same name in SecurityManger.
1873 * @param sm SecurityManager instance which should be called.
1874 * @return The current class loader in the calling stack.
1876 private static native ClassLoader currentClassLoader (SecurityManager sm);
1878 private void callReadMethod (Method readObject, Class klass, Object obj)
1879 throws ClassNotFoundException, IOException
1883 readObject.invoke(obj, new Object[] { this });
1885 catch (InvocationTargetException x)
1887 /* Rethrow if possible. */
1888 Throwable exception = x.getTargetException();
1889 if (exception instanceof RuntimeException)
1890 throw (RuntimeException) exception;
1891 if (exception instanceof IOException)
1892 throw (IOException) exception;
1893 if (exception instanceof ClassNotFoundException)
1894 throw (ClassNotFoundException) exception;
1896 throw new IOException("Exception thrown from readObject() on " +
1897 klass + ": " + exception.getClass().getName());
1899 catch (Exception x)
1901 throw new IOException("Failure invoking readObject() on " +
1902 klass + ": " + x.getClass().getName());
1905 // Invalidate fields which has been read through readFields.
1906 prereadFields = null;
1909 private native Object allocateObject(Class clazz, Class constr_clazz, Constructor constructor)
1910 throws InstantiationException;
1912 private static final int BUFFER_SIZE = 1024;
1914 private DataInputStream realInputStream;
1915 private DataInputStream dataInputStream;
1916 private DataInputStream blockDataInput;
1917 private int blockDataPosition;
1918 private int blockDataBytes;
1919 private byte[] blockData;
1920 private boolean useSubclassMethod;
1921 private int nextOID;
1922 private boolean resolveEnabled;
1923 private Hashtable objectLookupTable;
1924 private Object currentObject;
1925 private ObjectStreamClass currentObjectStreamClass;
1926 private boolean readDataFromBlock;
1927 private boolean isDeserializing;
1928 private boolean fieldsAlreadyRead;
1929 private Vector validators;
1930 private Hashtable classLookupTable;
1931 private GetField prereadFields;
1933 private ClassLoader callersClassLoader;
1934 private static boolean dump;
1936 // The nesting depth for debugging output
1937 private int depth = 0;
1939 private void dumpElement (String msg)
1941 System.out.print(msg);
1944 private void dumpElementln (String msg)
1946 System.out.println(msg);
1947 for (int i = 0; i < depth; i++)
1948 System.out.print (" ");
1949 System.out.print (Thread.currentThread() + ": ");
1952 static
1954 if (Configuration.INIT_LOAD_LIBRARY)
1956 System.loadLibrary ("javaio");
1960 // used to keep a prioritized list of object validators
1961 private static final class ValidatorAndPriority implements Comparable
1963 int priority;
1964 ObjectInputValidation validator;
1966 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1968 this.priority = priority;
1969 this.validator = validator;
1972 public int compareTo (Object o)
1974 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1975 return this.priority - vap.priority;