1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
42 import gnu
.classpath
.Configuration
;
43 import gnu
.java
.io
.ObjectIdentityWrapper
;
45 import java
.lang
.reflect
.Array
;
46 import java
.lang
.reflect
.Constructor
;
47 import java
.lang
.reflect
.Field
;
48 import java
.lang
.reflect
.InvocationTargetException
;
49 import java
.lang
.reflect
.Method
;
50 import java
.lang
.reflect
.Modifier
;
51 import java
.lang
.reflect
.Proxy
;
52 import java
.security
.AccessController
;
53 import java
.security
.PrivilegedAction
;
54 import java
.util
.Arrays
;
55 import java
.util
.Hashtable
;
56 import java
.util
.Vector
;
58 public class ObjectInputStream
extends InputStream
59 implements ObjectInput
, ObjectStreamConstants
62 * Creates a new <code>ObjectInputStream</code> that will do all of
63 * its reading from <code>in</code>. This method also checks
64 * the stream by reading the header information (stream magic number
65 * and stream version).
67 * @exception IOException Reading stream header from underlying
68 * stream cannot be completed.
70 * @exception StreamCorruptedException An invalid stream magic
71 * number or stream version was read from the stream.
73 * @see #readStreamHeader()
75 public ObjectInputStream(InputStream in
)
76 throws IOException
, StreamCorruptedException
78 if (Configuration
.DEBUG
)
80 String val
= System
.getProperty("gcj.dumpobjects");
81 if (dump
== false && val
!= null && !val
.equals(""))
84 System
.out
.println ("Serialization debugging enabled");
86 else if (dump
== true && (val
== null || val
.equals("")))
89 System
.out
.println ("Serialization debugging disabled");
93 this.resolveEnabled
= false;
94 this.isDeserializing
= false;
95 this.blockDataPosition
= 0;
96 this.blockDataBytes
= 0;
97 this.blockData
= new byte[BUFFER_SIZE
];
98 this.blockDataInput
= new DataInputStream(this);
99 this.realInputStream
= new DataInputStream(in
);
100 this.nextOID
= baseWireHandle
;
101 this.objectLookupTable
= new Hashtable();
102 this.validators
= new Vector();
103 this.classLookupTable
= new Hashtable();
104 setBlockDataMode(true);
110 * Returns the next deserialized object read from the underlying stream.
112 * This method can be overriden by a class by implementing
113 * <code>private void readObject (ObjectInputStream)</code>.
115 * If an exception is thrown from this method, the stream is left in
116 * an undefined state. This method can also throw Errors and
117 * RuntimeExceptions if caused by existing readResolve() user code.
119 * @return The object read from the underlying stream.
121 * @exception ClassNotFoundException The class that an object being
122 * read in belongs to cannot be found.
124 * @exception IOException Exception from underlying
125 * <code>InputStream</code>.
127 public final Object
readObject() throws ClassNotFoundException
, IOException
129 if (this.useSubclassMethod
)
130 return readObjectOverride();
132 boolean was_deserializing
;
135 was_deserializing
= this.isDeserializing
;
137 boolean is_consumed
= false;
138 boolean old_mode
= setBlockDataMode(false);
140 this.isDeserializing
= true;
142 byte marker
= this.realInputStream
.readByte();
146 if(dump
) dumpElement("MARKER: 0x" + Integer
.toHexString(marker
) + " ");
152 case TC_ENDBLOCKDATA
:
160 case TC_BLOCKDATALONG
:
162 if (marker
== TC_BLOCKDATALONG
)
163 { if(dump
) dumpElementln("BLOCKDATALONG"); }
165 { if(dump
) dumpElementln("BLOCKDATA"); }
166 readNextBlock(marker
);
167 throw new StreamCorruptedException("Unexpected blockData");
172 if(dump
) dumpElementln("NULL");
179 if(dump
) dumpElement("REFERENCE ");
180 Integer oid
= new Integer(this.realInputStream
.readInt());
181 if(dump
) dumpElementln(Integer
.toHexString(oid
.intValue()));
182 ret_val
= ((ObjectIdentityWrapper
)
183 this.objectLookupTable
.get(oid
)).object
;
189 if(dump
) dumpElementln("CLASS");
190 ObjectStreamClass osc
= (ObjectStreamClass
)readObject();
191 Class clazz
= osc
.forClass();
192 assignNewHandle(clazz
);
197 case TC_PROXYCLASSDESC
:
199 if(dump
) dumpElementln("PROXYCLASS");
200 int n_intf
= this.realInputStream
.readInt();
201 String
[] intfs
= new String
[n_intf
];
202 for (int i
= 0; i
< n_intf
; i
++)
204 intfs
[i
] = this.realInputStream
.readUTF();
207 boolean oldmode
= setBlockDataMode(true);
208 Class cl
= resolveProxyClass(intfs
);
209 setBlockDataMode(oldmode
);
211 ObjectStreamClass osc
= lookupClass(cl
);
212 if (osc
.firstNonSerializableParentConstructor
== null)
214 osc
.realClassIsSerializable
= true;
215 osc
.fields
= osc
.fieldMapping
= new ObjectStreamField
[0];
218 osc
.firstNonSerializableParentConstructor
=
219 Object
.class.getConstructor(new Class
[0]);
221 catch (NoSuchMethodException x
)
223 throw (InternalError
)
224 new InternalError("Object ctor missing").initCause(x
);
227 assignNewHandle(osc
);
231 byte b
= this.realInputStream
.readByte();
232 if (b
!= TC_ENDBLOCKDATA
)
233 throw new IOException("Data annotated to class was not consumed." + b
);
237 ObjectStreamClass superosc
= (ObjectStreamClass
)readObject();
238 osc
.setSuperclass(superosc
);
245 ObjectStreamClass osc
= readClassDescriptor();
249 byte b
= this.realInputStream
.readByte();
250 if (b
!= TC_ENDBLOCKDATA
)
251 throw new IOException("Data annotated to class was not consumed." + b
);
256 osc
.setSuperclass ((ObjectStreamClass
)readObject());
264 if(dump
) dumpElement("STRING=");
265 String s
= this.realInputStream
.readUTF();
266 if(dump
) dumpElementln(s
);
267 ret_val
= processResolution(null, s
, assignNewHandle(s
));
273 if(dump
) dumpElementln("ARRAY");
274 ObjectStreamClass osc
= (ObjectStreamClass
)readObject();
275 Class componentType
= osc
.forClass().getComponentType();
276 if(dump
) dumpElement("ARRAY LENGTH=");
277 int length
= this.realInputStream
.readInt();
278 if(dump
) dumpElementln (length
+ "; COMPONENT TYPE=" + componentType
);
279 Object array
= Array
.newInstance(componentType
, length
);
280 int handle
= assignNewHandle(array
);
281 readArrayElements(array
, componentType
);
283 for (int i
= 0, len
= Array
.getLength(array
); i
< len
; i
++)
284 dumpElementln(" ELEMENT[" + i
+ "]=" + Array
.get(array
, i
));
285 ret_val
= processResolution(null, array
, handle
);
291 if(dump
) dumpElementln("OBJECT");
292 ObjectStreamClass osc
= (ObjectStreamClass
)readObject();
293 Class clazz
= osc
.forClass();
295 if (!osc
.realClassIsSerializable
)
296 throw new NotSerializableException
297 (clazz
+ " is not Serializable, and thus cannot be deserialized.");
299 if (osc
.realClassIsExternalizable
)
301 Externalizable obj
= osc
.newInstance();
303 int handle
= assignNewHandle(obj
);
305 boolean read_from_blocks
= ((osc
.getFlags() & SC_BLOCK_DATA
) != 0);
307 boolean oldmode
= this.readDataFromBlock
;
308 if (read_from_blocks
)
309 setBlockDataMode(true);
311 obj
.readExternal(this);
313 if (read_from_blocks
)
315 setBlockDataMode(oldmode
);
317 if (this.realInputStream
.readByte() != TC_ENDBLOCKDATA
)
318 throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
321 ret_val
= processResolution(osc
, obj
, handle
);
323 } // end if (osc.realClassIsExternalizable)
325 Object obj
= newObject(clazz
, osc
.firstNonSerializableParentConstructor
);
327 int handle
= assignNewHandle(obj
);
328 Object prevObject
= this.currentObject
;
329 ObjectStreamClass prevObjectStreamClass
= this.currentObjectStreamClass
;
331 this.currentObject
= obj
;
332 ObjectStreamClass
[] hierarchy
=
333 inputGetObjectStreamClasses(clazz
);
335 for (int i
= 0; i
< hierarchy
.length
; i
++)
337 this.currentObjectStreamClass
= hierarchy
[i
];
339 if(dump
) dumpElementln("Reading fields of " + this.currentObjectStreamClass
.getName ());
341 // XXX: should initialize fields in classes in the hierarchy
342 // that aren't in the stream
343 // should skip over classes in the stream that aren't in the
344 // real classes hierarchy
346 Method readObjectMethod
= this.currentObjectStreamClass
.readObjectMethod
;
347 if (readObjectMethod
!= null)
349 fieldsAlreadyRead
= false;
350 boolean oldmode
= setBlockDataMode(true);
351 callReadMethod(readObjectMethod
, this.currentObjectStreamClass
.forClass(), obj
);
352 setBlockDataMode(oldmode
);
356 readFields(obj
, currentObjectStreamClass
);
359 if (this.currentObjectStreamClass
.hasWriteMethod())
361 if(dump
) dumpElement("ENDBLOCKDATA? ");
364 // FIXME: XXX: This try block is to
365 // catch EOF which is thrown for some
366 // objects. That indicates a bug in
369 if (this.realInputStream
.readByte() != TC_ENDBLOCKDATA
)
370 throw new IOException
371 ("No end of block data seen for class with readObject (ObjectInputStream) method.");
372 if(dump
) dumpElementln("yes");
374 // catch (EOFException e)
376 // if(dump) dumpElementln("no, got EOFException");
378 catch (IOException e
)
380 if(dump
) dumpElementln("no, got IOException");
385 this.currentObject
= prevObject
;
386 this.currentObjectStreamClass
= prevObjectStreamClass
;
387 ret_val
= processResolution(osc
, obj
, handle
);
393 if(dump
) dumpElementln("RESET");
395 ret_val
= readObject();
400 if(dump
) dumpElement("EXCEPTION=");
401 Exception e
= (Exception
)readObject();
402 if(dump
) dumpElementln(e
.toString());
404 throw new WriteAbortedException("Exception thrown during writing of stream", e
);
408 throw new IOException("Unknown marker on stream: " + marker
);
413 setBlockDataMode(old_mode
);
415 this.isDeserializing
= was_deserializing
;
419 if (! was_deserializing
)
421 if (validators
.size() > 0)
430 * This method makes a partial check of types for the fields
431 * contained given in arguments. It checks primitive types of
432 * fields1 against non primitive types of fields2. This method
433 * assumes the two lists has already been sorted according to
434 * the Java specification.
436 * @param name Name of the class owning the given fields.
437 * @param fields1 First list to check.
438 * @param fields2 Second list to check.
439 * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
440 * in the non primitive part in fields2.
442 private void checkTypeConsistency(String name
, ObjectStreamField
[] fields1
, ObjectStreamField
[] fields2
)
443 throws InvalidClassException
445 int nonPrimitive
= 0;
447 for (nonPrimitive
= 0;
448 nonPrimitive
< fields1
.length
449 && fields1
[nonPrimitive
].isPrimitive(); nonPrimitive
++)
453 if (nonPrimitive
== fields1
.length
)
457 ObjectStreamField f1
;
458 ObjectStreamField f2
;
460 while (i
< fields2
.length
461 && nonPrimitive
< fields1
.length
)
463 f1
= fields1
[nonPrimitive
];
466 if (!f2
.isPrimitive())
469 int compVal
= f1
.getName().compareTo (f2
.getName());
475 else if (compVal
> 0)
481 throw new InvalidClassException
482 ("invalid field type for " + f2
.getName() +
483 " in class " + name
);
489 * This method reads a class descriptor from the real input stream
490 * and use these data to create a new instance of ObjectStreamClass.
491 * Fields are sorted and ordered for the real read which occurs for
492 * each instance of the described class. Be aware that if you call that
493 * method you must ensure that the stream is synchronized, in the other
494 * case it may be completely desynchronized.
496 * @return A new instance of ObjectStreamClass containing the freshly
497 * created descriptor.
498 * @throws ClassNotFoundException if the required class to build the
499 * descriptor has not been found in the system.
500 * @throws IOException An input/output error occured.
501 * @throws InvalidClassException If there was a compatibility problem
502 * between the class present in the system and the serialized class.
504 protected ObjectStreamClass
readClassDescriptor()
505 throws ClassNotFoundException
, IOException
507 if(dump
) dumpElement("CLASSDESC NAME=");
508 String name
= this.realInputStream
.readUTF();
509 if(dump
) dumpElement(name
+ "; UID=");
510 long uid
= this.realInputStream
.readLong ();
511 if(dump
) dumpElement(Long
.toHexString(uid
) + "; FLAGS=");
512 byte flags
= this.realInputStream
.readByte ();
513 if(dump
) dumpElement(Integer
.toHexString(flags
) + "; FIELD COUNT=");
514 short field_count
= this.realInputStream
.readShort();
515 if(dump
) dumpElementln(Short
.toString(field_count
));
516 ObjectStreamField
[] fields
= new ObjectStreamField
[field_count
];
517 ObjectStreamClass osc
= new ObjectStreamClass(name
, uid
,
519 assignNewHandle(osc
);
521 if (callersClassLoader
== null)
522 callersClassLoader
= currentLoader();
524 for (int i
= 0; i
< field_count
; i
++)
526 if(dump
) dumpElement(" TYPE CODE=");
527 char type_code
= (char)this.realInputStream
.readByte();
528 if(dump
) dumpElement(type_code
+ "; FIELD NAME=");
529 String field_name
= this.realInputStream
.readUTF();
530 if(dump
) dumpElementln(field_name
);
533 // If the type code is an array or an object we must
534 // decode a String here. In the other case we convert
535 // the type code and pass it to ObjectStreamField.
536 // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
537 if (type_code
== 'L' || type_code
== '[')
538 class_name
= (String
)readObject();
540 class_name
= String
.valueOf(type_code
);
543 new ObjectStreamField(field_name
, class_name
, callersClassLoader
);
546 /* Now that fields have been read we may resolve the class
547 * (and read annotation if needed). */
551 clazz
= resolveClass(osc
);
553 catch (ClassNotFoundException cnfe
)
555 // Maybe it was an primitive class?
556 if (name
.equals("void"))
558 else if (name
.equals("boolean"))
559 clazz
= Boolean
.TYPE
;
560 else if (name
.equals("byte"))
562 else if (name
.equals("short"))
564 else if (name
.equals("char"))
565 clazz
= Character
.TYPE
;
566 else if (name
.equals("int"))
567 clazz
= Integer
.TYPE
;
568 else if (name
.equals("long"))
570 else if (name
.equals("float"))
572 else if (name
.equals("double"))
578 boolean oldmode
= setBlockDataMode(true);
579 osc
.setClass(clazz
, lookupClass(clazz
.getSuperclass()));
580 classLookupTable
.put(clazz
, osc
);
581 setBlockDataMode(oldmode
);
583 // find the first non-serializable, non-abstract
584 // class in clazz's inheritance hierarchy
585 Class first_nonserial
= clazz
.getSuperclass();
586 // Maybe it is a primitive class, those don't have a super class,
587 // or Object itself. Otherwise we can keep getting the superclass
588 // till we hit the Object class, or some other non-serializable class.
590 if (first_nonserial
== null)
591 first_nonserial
= clazz
;
593 while (Serializable
.class.isAssignableFrom(first_nonserial
)
594 || Modifier
.isAbstract(first_nonserial
.getModifiers()))
595 first_nonserial
= first_nonserial
.getSuperclass();
597 final Class local_constructor_class
= first_nonserial
;
599 osc
.firstNonSerializableParentConstructor
=
600 (Constructor
)AccessController
.doPrivileged(new PrivilegedAction()
606 Constructor c
= local_constructor_class
.
607 getDeclaredConstructor(new Class
[0]);
608 if (Modifier
.isPrivate(c
.getModifiers()))
612 catch (NoSuchMethodException e
)
614 // error will be reported later, in newObject()
620 osc
.realClassIsSerializable
= Serializable
.class.isAssignableFrom(clazz
);
621 osc
.realClassIsExternalizable
= Externalizable
.class.isAssignableFrom(clazz
);
623 ObjectStreamField
[] stream_fields
= osc
.fields
;
624 ObjectStreamField
[] real_fields
= ObjectStreamClass
.lookupForClassObject(clazz
).fields
;
625 ObjectStreamField
[] fieldmapping
= new ObjectStreamField
[2 * Math
.max(stream_fields
.length
, real_fields
.length
)];
632 * Check that there is no type inconsistencies between the lists.
633 * A special checking must be done for the two groups: primitive types and
634 * not primitive types.
636 checkTypeConsistency(name
, real_fields
, stream_fields
);
637 checkTypeConsistency(name
, stream_fields
, real_fields
);
640 while (stream_idx
< stream_fields
.length
641 || real_idx
< real_fields
.length
)
643 ObjectStreamField stream_field
= null;
644 ObjectStreamField real_field
= null;
646 if (stream_idx
== stream_fields
.length
)
648 real_field
= real_fields
[real_idx
++];
650 else if (real_idx
== real_fields
.length
)
652 stream_field
= stream_fields
[stream_idx
++];
657 real_fields
[real_idx
].compareTo (stream_fields
[stream_idx
]);
661 real_field
= real_fields
[real_idx
++];
663 else if (comp_val
> 0)
665 stream_field
= stream_fields
[stream_idx
++];
669 stream_field
= stream_fields
[stream_idx
++];
670 real_field
= real_fields
[real_idx
++];
671 if (stream_field
.getType() != real_field
.getType())
672 throw new InvalidClassException
673 ("invalid field type for " + real_field
.getName() +
674 " in class " + name
);
678 /* If some of stream_fields does not correspond to any of real_fields,
679 * or the opposite, then fieldmapping will go short.
681 if (map_idx
== fieldmapping
.length
)
683 ObjectStreamField
[] newfieldmapping
=
684 new ObjectStreamField
[fieldmapping
.length
+ 2];
685 System
.arraycopy(fieldmapping
, 0,
686 newfieldmapping
, 0, fieldmapping
.length
);
687 fieldmapping
= newfieldmapping
;
689 fieldmapping
[map_idx
++] = stream_field
;
690 fieldmapping
[map_idx
++] = real_field
;
692 osc
.fieldMapping
= fieldmapping
;
698 * Reads the current objects non-transient, non-static fields from
699 * the current class from the underlying output stream.
701 * This method is intended to be called from within a object's
702 * <code>private void readObject (ObjectInputStream)</code>
705 * @exception ClassNotFoundException The class that an object being
706 * read in belongs to cannot be found.
708 * @exception NotActiveException This method was called from a
709 * context other than from the current object's and current class's
710 * <code>private void readObject (ObjectInputStream)</code>
713 * @exception IOException Exception from underlying
714 * <code>OutputStream</code>.
716 public void defaultReadObject()
717 throws ClassNotFoundException
, IOException
, NotActiveException
719 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
720 throw new NotActiveException("defaultReadObject called by non-active"
721 + " class and/or object");
723 if (fieldsAlreadyRead
)
724 throw new NotActiveException("defaultReadObject called but fields "
725 + "already read from stream (by "
726 + "defaultReadObject or readFields)");
728 boolean oldmode
= setBlockDataMode(false);
729 readFields(this.currentObject
, this.currentObjectStreamClass
);
730 setBlockDataMode(oldmode
);
732 fieldsAlreadyRead
= true;
737 * Registers a <code>ObjectInputValidation</code> to be carried out
738 * on the object graph currently being deserialized before it is
739 * returned to the original caller of <code>readObject ()</code>.
740 * The order of validation for multiple
741 * <code>ObjectInputValidation</code>s can be controled using
742 * <code>priority</code>. Validators with higher priorities are
745 * @see java.io.ObjectInputValidation
747 * @exception InvalidObjectException <code>validator</code> is
750 * @exception NotActiveException an attempt was made to add a
751 * validator outside of the <code>readObject</code> method of the
752 * object currently being deserialized
754 public void registerValidation(ObjectInputValidation validator
,
756 throws InvalidObjectException
, NotActiveException
758 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
759 throw new NotActiveException("registerValidation called by non-active "
760 + "class and/or object");
762 if (validator
== null)
763 throw new InvalidObjectException("attempt to add a null "
764 + "ObjectInputValidation object");
766 this.validators
.addElement(new ValidatorAndPriority (validator
,
772 * Called when a class is being deserialized. This is a hook to
773 * allow subclasses to read in information written by the
774 * <code>annotateClass (Class)</code> method of an
775 * <code>ObjectOutputStream</code>.
777 * This implementation looks up the active call stack for a
778 * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
779 * it is used to load the class associated with <code>osc</code>,
780 * otherwise, the default system <code>ClassLoader</code> is used.
782 * @exception IOException Exception from underlying
783 * <code>OutputStream</code>.
785 * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
787 protected Class
resolveClass(ObjectStreamClass osc
)
788 throws ClassNotFoundException
, IOException
790 if (callersClassLoader
== null)
792 callersClassLoader
= currentLoader ();
793 if (Configuration
.DEBUG
&& dump
)
795 dumpElementln ("CallersClassLoader = " + callersClassLoader
);
799 return Class
.forName(osc
.getName(), true, callersClassLoader
);
803 * Returns the most recent user defined ClassLoader on the execution stack
804 * or null if none is found.
806 // GCJ LOCAL: native method.
807 private native ClassLoader
currentLoader();
810 * Lookup a class stored in the local hashtable. If it is not
811 * use the global lookup function in ObjectStreamClass to build
812 * the ObjectStreamClass. This method is requested according to
813 * the behaviour detected in the JDK by Kaffe's team.
815 * @param clazz Class to lookup in the hash table or for which
816 * we must build a descriptor.
817 * @return A valid instance of ObjectStreamClass corresponding
818 * to the specified class.
820 private ObjectStreamClass
lookupClass(Class clazz
)
825 ObjectStreamClass oclazz
;
826 oclazz
= (ObjectStreamClass
)classLookupTable
.get(clazz
);
828 return ObjectStreamClass
.lookup(clazz
);
834 * Reconstruct class hierarchy the same way
835 * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
836 * but using lookupClass instead of ObjectStreamClass.lookup. This
837 * dup is necessary localize the lookup table. Hopefully some future
838 * rewritings will be able to prevent this.
840 * @param clazz This is the class for which we want the hierarchy.
842 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
843 * represent the class hierarchy for clazz.
845 private ObjectStreamClass
[] inputGetObjectStreamClasses(Class clazz
)
847 ObjectStreamClass osc
= lookupClass(clazz
);
850 return new ObjectStreamClass
[0];
853 Vector oscs
= new Vector();
857 oscs
.addElement(osc
);
858 osc
= osc
.getSuper();
861 int count
= oscs
.size();
862 ObjectStreamClass
[] sorted_oscs
= new ObjectStreamClass
[count
];
864 for (int i
= count
- 1; i
>= 0; i
--)
865 sorted_oscs
[count
- i
- 1] = (ObjectStreamClass
) oscs
.elementAt(i
);
872 * Allows subclasses to resolve objects that are read from the
873 * stream with other objects to be returned in their place. This
874 * method is called the first time each object is encountered.
876 * This method must be enabled before it will be called in the
877 * serialization process.
879 * @exception IOException Exception from underlying
880 * <code>OutputStream</code>.
882 * @see #enableResolveObject(boolean)
884 protected Object
resolveObject(Object obj
) throws IOException
890 protected Class
resolveProxyClass(String
[] intfs
)
891 throws IOException
, ClassNotFoundException
893 ClassLoader cl
= currentLoader();
895 Class
[] clss
= new Class
[intfs
.length
];
898 for (int i
= 0; i
< intfs
.length
; i
++)
899 clss
[i
] = Class
.forName(intfs
[i
]);
900 cl
= ClassLoader
.getSystemClassLoader();
903 for (int i
= 0; i
< intfs
.length
; i
++)
904 clss
[i
] = cl
.loadClass(intfs
[i
]);
907 return Proxy
.getProxyClass(cl
, clss
);
909 catch (IllegalArgumentException e
)
911 throw new ClassNotFoundException(null, e
);
916 * If <code>enable</code> is <code>true</code> and this object is
917 * trusted, then <code>resolveObject (Object)</code> will be called
918 * in subsequent calls to <code>readObject (Object)</code>.
919 * Otherwise, <code>resolveObject (Object)</code> will not be called.
921 * @exception SecurityException This class is not trusted.
923 protected boolean enableResolveObject (boolean enable
)
924 throws SecurityException
928 SecurityManager sm
= System
.getSecurityManager();
930 sm
.checkPermission(new SerializablePermission("enableSubstitution"));
933 boolean old_val
= this.resolveEnabled
;
934 this.resolveEnabled
= enable
;
939 * Reads stream magic and stream version information from the
942 * @exception IOException Exception from underlying stream.
944 * @exception StreamCorruptedException An invalid stream magic
945 * number or stream version was read from the stream.
947 protected void readStreamHeader()
948 throws IOException
, StreamCorruptedException
950 if(dump
) dumpElement("STREAM MAGIC ");
951 if (this.realInputStream
.readShort() != STREAM_MAGIC
)
952 throw new StreamCorruptedException("Invalid stream magic number");
954 if(dump
) dumpElementln("STREAM VERSION ");
955 if (this.realInputStream
.readShort() != STREAM_VERSION
)
956 throw new StreamCorruptedException("Invalid stream version number");
959 public int read() throws IOException
961 if (this.readDataFromBlock
)
963 if (this.blockDataPosition
>= this.blockDataBytes
)
965 return (this.blockData
[this.blockDataPosition
++] & 0xff);
968 return this.realInputStream
.read();
971 public int read(byte[] data
, int offset
, int length
) throws IOException
973 if (this.readDataFromBlock
)
975 if (this.blockDataPosition
+ length
> this.blockDataBytes
)
977 int remain
= this.blockDataBytes
- this.blockDataPosition
;
980 System
.arraycopy(this.blockData
, this.blockDataPosition
,
981 data
, offset
, remain
);
988 System
.arraycopy(this.blockData
, this.blockDataPosition
,
989 data
, offset
, length
);
990 this.blockDataPosition
+= length
;
995 return this.realInputStream
.read(data
, offset
, length
);
998 public int available() throws IOException
1000 if (this.readDataFromBlock
)
1002 if (this.blockDataPosition
>= this.blockDataBytes
)
1005 return this.blockDataBytes
- this.blockDataPosition
;
1008 return this.realInputStream
.available();
1011 public void close() throws IOException
1013 this.realInputStream
.close();
1016 public boolean readBoolean() throws IOException
1018 boolean switchmode
= true;
1019 boolean oldmode
= this.readDataFromBlock
;
1020 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 1)
1023 oldmode
= setBlockDataMode (true);
1024 boolean value
= this.dataInputStream
.readBoolean ();
1026 setBlockDataMode (oldmode
);
1030 public byte readByte() throws IOException
1032 boolean switchmode
= true;
1033 boolean oldmode
= this.readDataFromBlock
;
1034 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 1)
1037 oldmode
= setBlockDataMode(true);
1038 byte value
= this.dataInputStream
.readByte();
1040 setBlockDataMode(oldmode
);
1044 public int readUnsignedByte() throws IOException
1046 boolean switchmode
= true;
1047 boolean oldmode
= this.readDataFromBlock
;
1048 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 1)
1051 oldmode
= setBlockDataMode(true);
1052 int value
= this.dataInputStream
.readUnsignedByte();
1054 setBlockDataMode(oldmode
);
1058 public short readShort() throws IOException
1060 boolean switchmode
= true;
1061 boolean oldmode
= this.readDataFromBlock
;
1062 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 2)
1065 oldmode
= setBlockDataMode(true);
1066 short value
= this.dataInputStream
.readShort();
1068 setBlockDataMode(oldmode
);
1072 public int readUnsignedShort() throws IOException
1074 boolean switchmode
= true;
1075 boolean oldmode
= this.readDataFromBlock
;
1076 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 2)
1079 oldmode
= setBlockDataMode(true);
1080 int value
= this.dataInputStream
.readUnsignedShort();
1082 setBlockDataMode(oldmode
);
1086 public char readChar() throws IOException
1088 boolean switchmode
= true;
1089 boolean oldmode
= this.readDataFromBlock
;
1090 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 2)
1093 oldmode
= setBlockDataMode(true);
1094 char value
= this.dataInputStream
.readChar();
1096 setBlockDataMode(oldmode
);
1100 public int readInt() throws IOException
1102 boolean switchmode
= true;
1103 boolean oldmode
= this.readDataFromBlock
;
1104 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 4)
1107 oldmode
= setBlockDataMode(true);
1108 int value
= this.dataInputStream
.readInt();
1110 setBlockDataMode(oldmode
);
1114 public long readLong() throws IOException
1116 boolean switchmode
= true;
1117 boolean oldmode
= this.readDataFromBlock
;
1118 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 8)
1121 oldmode
= setBlockDataMode(true);
1122 long value
= this.dataInputStream
.readLong();
1124 setBlockDataMode(oldmode
);
1128 public float readFloat() throws IOException
1130 boolean switchmode
= true;
1131 boolean oldmode
= this.readDataFromBlock
;
1132 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 4)
1135 oldmode
= setBlockDataMode(true);
1136 float value
= this.dataInputStream
.readFloat();
1138 setBlockDataMode(oldmode
);
1142 public double readDouble() throws IOException
1144 boolean switchmode
= true;
1145 boolean oldmode
= this.readDataFromBlock
;
1146 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 8)
1149 oldmode
= setBlockDataMode(true);
1150 double value
= this.dataInputStream
.readDouble();
1152 setBlockDataMode(oldmode
);
1156 public void readFully(byte data
[]) throws IOException
1158 this.dataInputStream
.readFully(data
);
1161 public void readFully(byte data
[], int offset
, int size
)
1164 this.dataInputStream
.readFully(data
, offset
, size
);
1167 public int skipBytes(int len
) throws IOException
1169 return this.dataInputStream
.skipBytes(len
);
1174 * @see java.io.DataInputStream#readLine ()
1176 public String
readLine() throws IOException
1178 return this.dataInputStream
.readLine();
1181 public String
readUTF() throws IOException
1183 return this.dataInputStream
.readUTF();
1187 * This class allows a class to specify exactly which fields should
1188 * be read, and what values should be read for these fields.
1190 * XXX: finish up comments
1192 public abstract static class GetField
1194 public abstract ObjectStreamClass
getObjectStreamClass();
1196 public abstract boolean defaulted(String name
)
1197 throws IOException
, IllegalArgumentException
;
1199 public abstract boolean get(String name
, boolean defvalue
)
1200 throws IOException
, IllegalArgumentException
;
1202 public abstract char get(String name
, char defvalue
)
1203 throws IOException
, IllegalArgumentException
;
1205 public abstract byte get(String name
, byte defvalue
)
1206 throws IOException
, IllegalArgumentException
;
1208 public abstract short get(String name
, short defvalue
)
1209 throws IOException
, IllegalArgumentException
;
1211 public abstract int get(String name
, int defvalue
)
1212 throws IOException
, IllegalArgumentException
;
1214 public abstract long get(String name
, long defvalue
)
1215 throws IOException
, IllegalArgumentException
;
1217 public abstract float get(String name
, float defvalue
)
1218 throws IOException
, IllegalArgumentException
;
1220 public abstract double get(String name
, double defvalue
)
1221 throws IOException
, IllegalArgumentException
;
1223 public abstract Object
get(String name
, Object defvalue
)
1224 throws IOException
, IllegalArgumentException
;
1228 * This method should be called by a method called 'readObject' in the
1229 * deserializing class (if present). It cannot (and should not)be called
1230 * outside of it. Its goal is to read all fields in the real input stream
1231 * and keep them accessible through the {@link #GetField} class. Calling
1232 * this method will not alter the deserializing object.
1234 * @return A valid freshly created 'GetField' instance to get access to
1235 * the deserialized stream.
1236 * @throws IOException An input/output exception occured.
1237 * @throws ClassNotFoundException
1238 * @throws NotActiveException
1240 public GetField
readFields()
1241 throws IOException
, ClassNotFoundException
, NotActiveException
1243 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
1244 throw new NotActiveException("readFields called by non-active class and/or object");
1246 if (prereadFields
!= null)
1247 return prereadFields
;
1249 if (fieldsAlreadyRead
)
1250 throw new NotActiveException("readFields called but fields already read from"
1251 + " stream (by defaultReadObject or readFields)");
1253 final ObjectStreamClass clazz
= this.currentObjectStreamClass
;
1254 final byte[] prim_field_data
= new byte[clazz
.primFieldSize
];
1255 final Object
[] objs
= new Object
[clazz
.objectFieldCount
];
1257 // Apparently Block data is not used with GetField as per
1258 // empirical evidence against JDK 1.2. Also see Mauve test
1259 // java.io.ObjectInputOutput.Test.GetPutField.
1260 boolean oldmode
= setBlockDataMode(false);
1261 readFully(prim_field_data
);
1262 for (int i
= 0; i
< objs
.length
; ++ i
)
1263 objs
[i
] = readObject();
1264 setBlockDataMode(oldmode
);
1266 prereadFields
= new GetField()
1268 public ObjectStreamClass
getObjectStreamClass()
1273 public boolean defaulted(String name
)
1274 throws IOException
, IllegalArgumentException
1276 ObjectStreamField f
= clazz
.getField(name
);
1278 /* First if we have a serialized field use the descriptor */
1281 /* It is in serialPersistentFields but setClass tells us
1282 * it should not be set. This value is defaulted.
1284 if (f
.isPersistent() && !f
.isToSet())
1290 /* This is not a serialized field. There should be
1291 * a default value only if the field really exists.
1295 return (clazz
.forClass().getDeclaredField (name
) != null);
1297 catch (NoSuchFieldException e
)
1299 throw new IllegalArgumentException(e
.getMessage());
1303 public boolean get(String name
, boolean defvalue
)
1304 throws IOException
, IllegalArgumentException
1306 ObjectStreamField field
= getField(name
, Boolean
.TYPE
);
1311 return prim_field_data
[field
.getOffset()] == 0 ?
false : true;
1314 public char get(String name
, char defvalue
)
1315 throws IOException
, IllegalArgumentException
1317 ObjectStreamField field
= getField(name
, Character
.TYPE
);
1322 int off
= field
.getOffset();
1324 return (char)(((prim_field_data
[off
++] & 0xFF) << 8)
1325 | (prim_field_data
[off
] & 0xFF));
1328 public byte get(String name
, byte defvalue
)
1329 throws IOException
, IllegalArgumentException
1331 ObjectStreamField field
= getField(name
, Byte
.TYPE
);
1336 return prim_field_data
[field
.getOffset()];
1339 public short get(String name
, short defvalue
)
1340 throws IOException
, IllegalArgumentException
1342 ObjectStreamField field
= getField(name
, Short
.TYPE
);
1347 int off
= field
.getOffset();
1349 return (short)(((prim_field_data
[off
++] & 0xFF) << 8)
1350 | (prim_field_data
[off
] & 0xFF));
1353 public int get(String name
, int defvalue
)
1354 throws IOException
, IllegalArgumentException
1356 ObjectStreamField field
= getField(name
, Integer
.TYPE
);
1361 int off
= field
.getOffset();
1363 return ((prim_field_data
[off
++] & 0xFF) << 24)
1364 | ((prim_field_data
[off
++] & 0xFF) << 16)
1365 | ((prim_field_data
[off
++] & 0xFF) << 8)
1366 | (prim_field_data
[off
] & 0xFF);
1369 public long get(String name
, long defvalue
)
1370 throws IOException
, IllegalArgumentException
1372 ObjectStreamField field
= getField(name
, Long
.TYPE
);
1377 int off
= field
.getOffset();
1379 return (long)(((prim_field_data
[off
++] & 0xFFL
) << 56)
1380 | ((prim_field_data
[off
++] & 0xFFL
) << 48)
1381 | ((prim_field_data
[off
++] & 0xFFL
) << 40)
1382 | ((prim_field_data
[off
++] & 0xFFL
) << 32)
1383 | ((prim_field_data
[off
++] & 0xFF) << 24)
1384 | ((prim_field_data
[off
++] & 0xFF) << 16)
1385 | ((prim_field_data
[off
++] & 0xFF) << 8)
1386 | (prim_field_data
[off
] & 0xFF));
1389 public float get(String name
, float defvalue
)
1390 throws IOException
, IllegalArgumentException
1392 ObjectStreamField field
= getField(name
, Float
.TYPE
);
1397 int off
= field
.getOffset();
1399 return Float
.intBitsToFloat(((prim_field_data
[off
++] & 0xFF) << 24)
1400 | ((prim_field_data
[off
++] & 0xFF) << 16)
1401 | ((prim_field_data
[off
++] & 0xFF) << 8)
1402 | (prim_field_data
[off
] & 0xFF));
1405 public double get(String name
, double defvalue
)
1406 throws IOException
, IllegalArgumentException
1408 ObjectStreamField field
= getField(name
, Double
.TYPE
);
1413 int off
= field
.getOffset();
1415 return Double
.longBitsToDouble
1416 ( (long) (((prim_field_data
[off
++] & 0xFFL
) << 56)
1417 | ((prim_field_data
[off
++] & 0xFFL
) << 48)
1418 | ((prim_field_data
[off
++] & 0xFFL
) << 40)
1419 | ((prim_field_data
[off
++] & 0xFFL
) << 32)
1420 | ((prim_field_data
[off
++] & 0xFF) << 24)
1421 | ((prim_field_data
[off
++] & 0xFF) << 16)
1422 | ((prim_field_data
[off
++] & 0xFF) << 8)
1423 | (prim_field_data
[off
] & 0xFF)));
1426 public Object
get(String name
, Object defvalue
)
1427 throws IOException
, IllegalArgumentException
1429 ObjectStreamField field
=
1430 getField(name
, defvalue
== null ?
null : defvalue
.getClass ());
1435 return objs
[field
.getOffset()];
1438 private ObjectStreamField
getField(String name
, Class type
)
1439 throws IllegalArgumentException
1441 ObjectStreamField field
= clazz
.getField(name
);
1442 boolean illegal
= false;
1448 Class field_type
= field
.getType();
1450 if (type
== field_type
||
1451 (type
== null && !field_type
.isPrimitive()))
1458 throw new IllegalArgumentException
1459 ("Field requested is of type "
1460 + field_type
.getName()
1461 + ", but requested type was "
1462 + (type
== null ?
"Object" : type
.getName()));
1464 catch (NullPointerException _
)
1466 /* Here we catch NullPointerException, because it may
1467 only come from the call 'field.getType()'. If field
1468 is null, we have to return null and classpath ethic
1469 say we must try to avoid 'if (xxx == null)'.
1472 catch (IllegalArgumentException e
)
1481 /* If this is an unassigned field we should return
1482 * the default value.
1484 if (!illegal
&& field
!= null && !field
.isToSet() && field
.isPersistent())
1487 /* We do not want to modify transient fields. They should
1492 Field f
= clazz
.forClass().getDeclaredField(name
);
1493 if (Modifier
.isTransient(f
.getModifiers()))
1494 throw new IllegalArgumentException
1495 ("no such field (non transient) " + name
);
1496 if (field
== null && f
.getType() != type
)
1497 throw new IllegalArgumentException
1498 ("Invalid requested type for field " + name
);
1500 catch (NoSuchFieldException e
)
1503 throw new IllegalArgumentException(e
.getMessage());
1510 fieldsAlreadyRead
= true;
1511 return prereadFields
;
1515 * Protected constructor that allows subclasses to override
1516 * deserialization. This constructor should be called by subclasses
1517 * that wish to override <code>readObject (Object)</code>. This
1518 * method does a security check <i>NOTE: currently not
1519 * implemented</i>, then sets a flag that informs
1520 * <code>readObject (Object)</code> to call the subclasses
1521 * <code>readObjectOverride (Object)</code> method.
1523 * @see #readObjectOverride()
1525 protected ObjectInputStream()
1526 throws IOException
, SecurityException
1528 SecurityManager sec_man
= System
.getSecurityManager();
1529 if (sec_man
!= null)
1530 sec_man
.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION
);
1531 this.useSubclassMethod
= true;
1535 * This method allows subclasses to override the default
1536 * de serialization mechanism provided by
1537 * <code>ObjectInputStream</code>. To make this method be used for
1538 * writing objects, subclasses must invoke the 0-argument
1539 * constructor on this class from their constructor.
1541 * @see #ObjectInputStream()
1543 protected Object
readObjectOverride()
1544 throws ClassNotFoundException
, IOException
, OptionalDataException
1546 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1550 * Assigns the next available handle to <code>obj</code>.
1552 * @param obj The object for which we want a new handle.
1553 * @return A valid handle for the specified object.
1555 private int assignNewHandle(Object obj
)
1557 this.objectLookupTable
.put(new Integer(this.nextOID
),
1558 new ObjectIdentityWrapper(obj
));
1559 return this.nextOID
++;
1562 private Object
processResolution(ObjectStreamClass osc
, Object obj
, int handle
)
1565 if (osc
!= null && obj
instanceof Serializable
)
1569 Method m
= osc
.readResolveMethod
;
1572 obj
= m
.invoke(obj
, new Object
[] {});
1575 catch (IllegalAccessException ignore
)
1578 catch (InvocationTargetException exception
)
1580 Throwable cause
= exception
.getCause();
1581 if (cause
instanceof ObjectStreamException
)
1582 throw (ObjectStreamException
) cause
;
1583 else if (cause
instanceof RuntimeException
)
1584 throw (RuntimeException
) cause
;
1585 else if (cause
instanceof Error
)
1586 throw (Error
) cause
;
1590 if (this.resolveEnabled
)
1591 obj
= resolveObject(obj
);
1593 this.objectLookupTable
.put(new Integer(handle
),
1594 new ObjectIdentityWrapper(obj
));
1599 private void clearHandles()
1601 this.objectLookupTable
.clear();
1602 this.nextOID
= baseWireHandle
;
1605 private void readNextBlock() throws IOException
1607 readNextBlock(this.realInputStream
.readByte());
1610 private void readNextBlock(byte marker
) throws IOException
1612 if (marker
== TC_BLOCKDATA
)
1614 if(dump
) dumpElement("BLOCK DATA SIZE=");
1615 this.blockDataBytes
= this.realInputStream
.readUnsignedByte();
1616 if(dump
) dumpElementln (Integer
.toString(this.blockDataBytes
));
1618 else if (marker
== TC_BLOCKDATALONG
)
1620 if(dump
) dumpElement("BLOCK DATA LONG SIZE=");
1621 this.blockDataBytes
= this.realInputStream
.readInt();
1622 if(dump
) dumpElementln (Integer
.toString(this.blockDataBytes
));
1626 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1629 if (this.blockData
.length
< this.blockDataBytes
)
1630 this.blockData
= new byte[this.blockDataBytes
];
1632 this.realInputStream
.readFully (this.blockData
, 0, this.blockDataBytes
);
1633 this.blockDataPosition
= 0;
1636 private void readArrayElements (Object array
, Class clazz
)
1637 throws ClassNotFoundException
, IOException
1639 if (clazz
.isPrimitive())
1641 if (clazz
== Boolean
.TYPE
)
1643 boolean[] cast_array
= (boolean[])array
;
1644 for (int i
=0; i
< cast_array
.length
; i
++)
1645 cast_array
[i
] = this.realInputStream
.readBoolean();
1648 if (clazz
== Byte
.TYPE
)
1650 byte[] cast_array
= (byte[])array
;
1651 for (int i
=0; i
< cast_array
.length
; i
++)
1652 cast_array
[i
] = this.realInputStream
.readByte();
1655 if (clazz
== Character
.TYPE
)
1657 char[] cast_array
= (char[])array
;
1658 for (int i
=0; i
< cast_array
.length
; i
++)
1659 cast_array
[i
] = this.realInputStream
.readChar();
1662 if (clazz
== Double
.TYPE
)
1664 double[] cast_array
= (double[])array
;
1665 for (int i
=0; i
< cast_array
.length
; i
++)
1666 cast_array
[i
] = this.realInputStream
.readDouble();
1669 if (clazz
== Float
.TYPE
)
1671 float[] cast_array
= (float[])array
;
1672 for (int i
=0; i
< cast_array
.length
; i
++)
1673 cast_array
[i
] = this.realInputStream
.readFloat();
1676 if (clazz
== Integer
.TYPE
)
1678 int[] cast_array
= (int[])array
;
1679 for (int i
=0; i
< cast_array
.length
; i
++)
1680 cast_array
[i
] = this.realInputStream
.readInt();
1683 if (clazz
== Long
.TYPE
)
1685 long[] cast_array
= (long[])array
;
1686 for (int i
=0; i
< cast_array
.length
; i
++)
1687 cast_array
[i
] = this.realInputStream
.readLong();
1690 if (clazz
== Short
.TYPE
)
1692 short[] cast_array
= (short[])array
;
1693 for (int i
=0; i
< cast_array
.length
; i
++)
1694 cast_array
[i
] = this.realInputStream
.readShort();
1700 Object
[] cast_array
= (Object
[])array
;
1701 for (int i
=0; i
< cast_array
.length
; i
++)
1702 cast_array
[i
] = readObject();
1706 private void readFields (Object obj
, ObjectStreamClass stream_osc
)
1707 throws ClassNotFoundException
, IOException
1709 ObjectStreamField
[] fields
= stream_osc
.fieldMapping
;
1711 for (int i
= 0; i
< fields
.length
; i
+= 2)
1713 ObjectStreamField stream_field
= fields
[i
];
1714 ObjectStreamField real_field
= fields
[i
+ 1];
1715 boolean read_value
= (stream_field
!= null && stream_field
.getOffset() >= 0 && stream_field
.isToSet());
1716 boolean set_value
= (real_field
!= null && real_field
.isToSet());
1720 if (stream_field
!= null)
1722 field_name
= stream_field
.getName();
1723 type
= stream_field
.getTypeCode();
1727 field_name
= real_field
.getName();
1728 type
= real_field
.getTypeCode();
1736 read_value ?
this.realInputStream
.readBoolean() : false;
1737 if (dump
&& read_value
&& set_value
)
1738 dumpElementln(" " + field_name
+ ": " + value
);
1740 real_field
.setBooleanField(obj
, value
);
1746 read_value ?
this.realInputStream
.readByte() : 0;
1747 if (dump
&& read_value
&& set_value
)
1748 dumpElementln(" " + field_name
+ ": " + value
);
1750 real_field
.setByteField(obj
, value
);
1756 read_value ?
this.realInputStream
.readChar(): 0;
1757 if (dump
&& read_value
&& set_value
)
1758 dumpElementln(" " + field_name
+ ": " + value
);
1760 real_field
.setCharField(obj
, value
);
1766 read_value ?
this.realInputStream
.readDouble() : 0;
1767 if (dump
&& read_value
&& set_value
)
1768 dumpElementln(" " + field_name
+ ": " + value
);
1770 real_field
.setDoubleField(obj
, value
);
1776 read_value ?
this.realInputStream
.readFloat() : 0;
1777 if (dump
&& read_value
&& set_value
)
1778 dumpElementln(" " + field_name
+ ": " + value
);
1780 real_field
.setFloatField(obj
, value
);
1786 read_value ?
this.realInputStream
.readInt() : 0;
1787 if (dump
&& read_value
&& set_value
)
1788 dumpElementln(" " + field_name
+ ": " + value
);
1790 real_field
.setIntField(obj
, value
);
1796 read_value ?
this.realInputStream
.readLong() : 0;
1797 if (dump
&& read_value
&& set_value
)
1798 dumpElementln(" " + field_name
+ ": " + value
);
1800 real_field
.setLongField(obj
, value
);
1806 read_value ?
this.realInputStream
.readShort() : 0;
1807 if (dump
&& read_value
&& set_value
)
1808 dumpElementln(" " + field_name
+ ": " + value
);
1810 real_field
.setShortField(obj
, value
);
1817 read_value ?
readObject() : null;
1819 real_field
.setObjectField(obj
, value
);
1823 throw new InternalError("Invalid type code: " + type
);
1828 // Toggles writing primitive data to block-data buffer.
1829 private boolean setBlockDataMode (boolean on
)
1831 boolean oldmode
= this.readDataFromBlock
;
1832 this.readDataFromBlock
= on
;
1835 this.dataInputStream
= this.blockDataInput
;
1837 this.dataInputStream
= this.realInputStream
;
1841 // returns a new instance of REAL_CLASS that has been constructed
1842 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1843 private Object
newObject (Class real_class
, Constructor constructor
)
1844 throws ClassNotFoundException
, IOException
1846 if (constructor
== null)
1847 throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class
.getName());
1850 return allocateObject(real_class
, constructor
.getDeclaringClass(), constructor
);
1852 catch (InstantiationException e
)
1854 throw new ClassNotFoundException
1855 ("Instance of " + real_class
+ " could not be created");
1859 // runs all registered ObjectInputValidations in prioritized order
1861 private void invokeValidators() throws InvalidObjectException
1863 Object
[] validators
= new Object
[this.validators
.size()];
1864 this.validators
.copyInto (validators
);
1865 Arrays
.sort (validators
);
1869 for (int i
=0; i
< validators
.length
; i
++)
1870 ((ObjectInputValidation
)validators
[i
]).validateObject();
1874 this.validators
.removeAllElements();
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());
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() + ": ");
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
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
;