1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java
.lang
.reflect
.Array
;
42 import java
.lang
.reflect
.Modifier
;
43 import java
.lang
.reflect
.Proxy
;
44 import java
.security
.PrivilegedAction
;
45 import java
.security
.AccessController
;
46 import java
.util
.Arrays
;
47 import java
.util
.Hashtable
;
48 import java
.util
.Vector
;
51 import gnu
.java
.io
.ObjectIdentityWrapper
;
52 import gnu
.java
.lang
.reflect
.TypeSignature
;
53 import java
.lang
.reflect
.Field
;
54 import java
.lang
.reflect
.Method
;
55 import java
.lang
.reflect
.InvocationTargetException
;
57 import gnu
.classpath
.Configuration
;
59 public class ObjectInputStream
extends InputStream
60 implements ObjectInput
, ObjectStreamConstants
63 * Creates a new <code>ObjectInputStream</code> that will do all of
64 * its reading from <code>in</code>. This method also checks
65 * the stream by reading the header information (stream magic number
66 * and stream version).
68 * @exception IOException Reading stream header from underlying
69 * stream cannot be completed.
71 * @exception StreamCorruptedException An invalid stream magic
72 * number or stream version was read from the stream.
74 * @see #readStreamHeader()
76 public ObjectInputStream(InputStream in
)
77 throws IOException
, StreamCorruptedException
79 if (Configuration
.DEBUG
)
81 String val
= System
.getProperty("gcj.dumpobjects");
82 if (dump
== false && val
!= null && !val
.equals(""))
85 System
.out
.println ("Serialization debugging enabled");
87 else if (dump
== true && (val
== null || val
.equals("")))
90 System
.out
.println ("Serialization debugging disabled");
94 this.resolveEnabled
= false;
95 this.isDeserializing
= false;
96 this.blockDataPosition
= 0;
97 this.blockDataBytes
= 0;
98 this.blockData
= new byte[BUFFER_SIZE
];
99 this.blockDataInput
= new DataInputStream(this);
100 this.realInputStream
= new DataInputStream(in
);
101 this.nextOID
= baseWireHandle
;
102 this.objectLookupTable
= new Hashtable();
103 this.validators
= new Vector();
104 this.classLookupTable
= new Hashtable();
105 setBlockDataMode(true);
111 * Returns the next deserialized object read from the underlying stream.
113 * This method can be overriden by a class by implementing
114 * <code>private void readObject (ObjectInputStream)</code>.
116 * If an exception is thrown from this method, the stream is left in
117 * an undefined state.
119 * @exception ClassNotFoundException The class that an object being
120 * read in belongs to cannot be found.
122 * @exception IOException Exception from underlying
123 * <code>InputStream</code>.
125 public final Object
readObject() throws ClassNotFoundException
, IOException
127 if (this.useSubclassMethod
)
128 return readObjectOverride();
130 boolean was_deserializing
;
133 was_deserializing
= this.isDeserializing
;
135 boolean is_consumed
= false;
136 boolean old_mode
= setBlockDataMode(false);
138 this.isDeserializing
= true;
140 byte marker
= this.realInputStream
.readByte();
141 dumpElement("MARKER: 0x" + Integer
.toHexString(marker
) + " ");
147 case TC_ENDBLOCKDATA
:
155 case TC_BLOCKDATALONG
:
157 if (marker
== TC_BLOCKDATALONG
)
158 dumpElementln("BLOCKDATALONG");
160 dumpElementln("BLOCKDATA");
161 readNextBlock(marker
);
162 throw new StreamCorruptedException("Unexpected blockData");
167 dumpElementln("NULL");
174 dumpElement("REFERENCE ");
175 Integer oid
= new Integer(this.realInputStream
.readInt());
176 dumpElementln(Integer
.toHexString(oid
.intValue()));
177 ret_val
= ((ObjectIdentityWrapper
)
178 this.objectLookupTable
.get(oid
)).object
;
184 dumpElementln("CLASS");
185 ObjectStreamClass osc
= (ObjectStreamClass
)readObject();
186 Class clazz
= osc
.forClass();
187 assignNewHandle(clazz
);
192 case TC_PROXYCLASSDESC
:
194 dumpElementln("PROXYCLASS");
195 int n_intf
= this.realInputStream
.readInt();
196 String
[] intfs
= new String
[n_intf
];
197 for (int i
= 0; i
< n_intf
; i
++)
199 intfs
[i
] = this.realInputStream
.readUTF();
200 System
.out
.println(intfs
[i
]);
203 boolean oldmode
= setBlockDataMode(true);
204 Class cl
= resolveProxyClass(intfs
);
205 setBlockDataMode(oldmode
);
207 ObjectStreamClass osc
= lookupClass(cl
);
208 assignNewHandle(osc
);
212 byte b
= this.realInputStream
.readByte();
213 if (b
!= TC_ENDBLOCKDATA
)
214 throw new IOException("Data annotated to class was not consumed." + b
);
218 ObjectStreamClass superosc
= (ObjectStreamClass
)readObject();
219 osc
.setSuperclass(superosc
);
226 ObjectStreamClass osc
= readClassDescriptor();
230 byte b
= this.realInputStream
.readByte();
231 if (b
!= TC_ENDBLOCKDATA
)
232 throw new IOException("Data annotated to class was not consumed." + b
);
237 osc
.setSuperclass ((ObjectStreamClass
)readObject());
245 dumpElement("STRING=");
246 String s
= this.realInputStream
.readUTF();
248 ret_val
= processResolution(s
, assignNewHandle(s
));
254 dumpElementln("ARRAY");
255 ObjectStreamClass osc
= (ObjectStreamClass
)readObject();
256 Class componentType
= osc
.forClass().getComponentType();
257 dumpElement("ARRAY LENGTH=");
258 int length
= this.realInputStream
.readInt();
259 dumpElementln (length
+ "; COMPONENT TYPE=" + componentType
);
260 Object array
= Array
.newInstance(componentType
, length
);
261 int handle
= assignNewHandle(array
);
262 readArrayElements(array
, componentType
);
263 for (int i
= 0, len
= Array
.getLength(array
); i
< len
; i
++)
264 dumpElementln(" ELEMENT[" + i
+ "]=" + Array
.get(array
, i
));
265 ret_val
= processResolution(array
, handle
);
271 dumpElementln("OBJECT");
272 ObjectStreamClass osc
= (ObjectStreamClass
)readObject();
273 Class clazz
= osc
.forClass();
275 if (!Serializable
.class.isAssignableFrom(clazz
))
276 throw new NotSerializableException
277 (clazz
+ " is not Serializable, and thus cannot be deserialized.");
279 if (Externalizable
.class.isAssignableFrom(clazz
))
281 Externalizable obj
= null;
285 obj
= (Externalizable
)clazz
.newInstance();
287 catch (InstantiationException e
)
289 throw new ClassNotFoundException
290 ("Instance of " + clazz
+ " could not be created");
292 catch (IllegalAccessException e
)
294 throw new ClassNotFoundException
295 ("Instance of " + clazz
+ " could not be created because class or "
296 + "zero-argument constructor is not accessible");
298 catch (NoSuchMethodError e
)
300 throw new ClassNotFoundException
301 ("Instance of " + clazz
302 + " could not be created because zero-argument constructor is not defined");
305 int handle
= assignNewHandle(obj
);
307 boolean read_from_blocks
= ((osc
.getFlags() & SC_BLOCK_DATA
) != 0);
309 boolean oldmode
= this.readDataFromBlock
;
310 if (read_from_blocks
)
311 setBlockDataMode(true);
313 obj
.readExternal(this);
315 if (read_from_blocks
)
316 setBlockDataMode(oldmode
);
318 ret_val
= processResolution(obj
, handle
);
320 } // end if (Externalizable.class.isAssignableFrom (clazz))
322 // find the first non-serializable, non-abstract
323 // class in clazz's inheritance hierarchy
324 Class first_nonserial
= clazz
.getSuperclass();
325 while (Serializable
.class.isAssignableFrom(first_nonserial
)
326 || Modifier
.isAbstract(first_nonserial
.getModifiers()))
327 first_nonserial
= first_nonserial
.getSuperclass();
330 obj
= newObject(clazz
, first_nonserial
);
333 throw new ClassNotFoundException
334 ("Instance of " + clazz
+ " could not be created");
336 int handle
= assignNewHandle(obj
);
337 this.currentObject
= obj
;
338 ObjectStreamClass
[] hierarchy
=
339 inputGetObjectStreamClasses(clazz
);
341 for (int i
= 0; i
< hierarchy
.length
; i
++)
343 this.currentObjectStreamClass
= hierarchy
[i
];
345 dumpElementln("Reading fields of " + this.currentObjectStreamClass
.getName ());
347 // XXX: should initialize fields in classes in the hierarchy
348 // that aren't in the stream
349 // should skip over classes in the stream that aren't in the
350 // real classes hierarchy
352 if (this.currentObjectStreamClass
.hasReadMethod())
354 fieldsAlreadyRead
= false;
355 boolean oldmode
= setBlockDataMode(true);
356 callReadMethod(obj
, this.currentObjectStreamClass
);
357 setBlockDataMode(oldmode
);
358 dumpElement("ENDBLOCKDATA? ");
361 // FIXME: XXX: This try block is to catch EOF which is
362 // thrown for some objects. That indicates a bug in the logic.
363 if (this.realInputStream
.readByte() != TC_ENDBLOCKDATA
)
364 throw new IOException
365 ("No end of block data seen for class with readObject (ObjectInputStream) method.");
366 dumpElementln("yes");
368 catch (EOFException e
)
370 dumpElementln("no, got EOFException");
372 catch (IOException e
)
374 dumpElementln("no, got IOException");
379 readFields(obj
, currentObjectStreamClass
);
383 this.currentObject
= null;
384 this.currentObjectStreamClass
= null;
385 ret_val
= processResolution(obj
, handle
);
390 dumpElementln("RESET");
392 ret_val
= readObject();
397 dumpElement("EXCEPTION=");
398 Exception e
= (Exception
)readObject();
399 dumpElementln(e
.toString());
401 throw new WriteAbortedException("Exception thrown during writing of stream", e
);
405 throw new IOException("Unknown marker on stream: " + marker
);
410 setBlockDataMode(old_mode
);
412 this.isDeserializing
= was_deserializing
;
414 if (! was_deserializing
)
416 if (validators
.size() > 0)
425 * This method reads a class descriptor from the real input stream
426 * and use these data to create a new instance of ObjectStreamClass.
427 * Fields are sorted and ordered for the real read which occurs for
428 * each instance of the described class. Be aware that if you call that
429 * method you must ensure that the stream is synchronized, in the other
430 * case it may be completely desynchronized.
432 * @return A new instance of ObjectStreamClass containing the freshly
433 * created descriptor.
434 * @throws ClassNotFoundException if the required class to build the
435 * descriptor has not been found in the system.
436 * @throws IOException An input/output error occured.
437 * @throws InvalidClassException If there was a compatibility problem
438 * between the class present in the system and the serialized class.
440 protected ObjectStreamClass
readClassDescriptor()
441 throws ClassNotFoundException
, IOException
443 dumpElement("CLASSDESC NAME=");
444 String name
= this.realInputStream
.readUTF();
445 dumpElement(name
+ "; UID=");
446 long uid
= this.realInputStream
.readLong ();
447 dumpElement(Long
.toHexString(uid
) + "; FLAGS=");
448 byte flags
= this.realInputStream
.readByte ();
449 dumpElement(Integer
.toHexString(flags
) + "; FIELD COUNT=");
450 short field_count
= this.realInputStream
.readShort();
451 dumpElementln(Short
.toString(field_count
));
452 ObjectStreamField
[] fields
= new ObjectStreamField
[field_count
];
453 ObjectStreamClass osc
= new ObjectStreamClass(name
, uid
,
455 assignNewHandle(osc
);
457 for (int i
= 0; i
< field_count
; i
++)
459 dumpElement(" TYPE CODE=");
460 char type_code
= (char)this.realInputStream
.readByte();
461 dumpElement(type_code
+ "; FIELD NAME=");
462 String field_name
= this.realInputStream
.readUTF();
463 dumpElementln(field_name
);
466 // If the type code is an array or an object we must
467 // decode a String here. In the other case we convert
468 // the type code and pass it to ObjectStreamField.
469 // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
470 if (type_code
== 'L' || type_code
== '[')
471 class_name
= (String
)readObject();
473 class_name
= String
.valueOf(type_code
);
476 new ObjectStreamField(field_name
, class_name
, currentLoader());
479 /* Now that fields have been read we may resolve the class
480 * (and read annotation if needed). */
481 Class clazz
= resolveClass(osc
);
483 for (int i
= 0; i
< field_count
; i
++)
489 f
= clazz
.getDeclaredField(fields
[i
].getName());
490 if (f
!= null && !f
.getType().equals(fields
[i
].getType()))
491 throw new InvalidClassException
492 ("invalid field type for " + fields
[i
].getName() + " in class "
493 + name
+ " (requested was \"" + fields
[i
].getType()
494 + " and found \"" + f
.getType() + "\")");
496 catch (NoSuchFieldException _
)
501 boolean oldmode
= setBlockDataMode(true);
502 osc
.setClass(clazz
, lookupClass(clazz
.getSuperclass()));
503 classLookupTable
.put(clazz
, osc
);
504 setBlockDataMode(oldmode
);
510 * Reads the current objects non-transient, non-static fields from
511 * the current class from the underlying output stream.
513 * This method is intended to be called from within a object's
514 * <code>private void readObject (ObjectInputStream)</code>
517 * @exception ClassNotFoundException The class that an object being
518 * read in belongs to cannot be found.
520 * @exception NotActiveException This method was called from a
521 * context other than from the current object's and current class's
522 * <code>private void readObject (ObjectInputStream)</code>
525 * @exception IOException Exception from underlying
526 * <code>OutputStream</code>.
528 public void defaultReadObject()
529 throws ClassNotFoundException
, IOException
, NotActiveException
531 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
532 throw new NotActiveException("defaultReadObject called by non-active"
533 + " class and/or object");
535 if (fieldsAlreadyRead
)
536 throw new NotActiveException("defaultReadObject called but fields "
537 + "already read from stream (by "
538 + "defaultReadObject or readFields)");
540 boolean oldmode
= setBlockDataMode(false);
541 readFields(this.currentObject
, this.currentObjectStreamClass
);
542 setBlockDataMode(oldmode
);
544 fieldsAlreadyRead
= true;
549 * Registers a <code>ObjectInputValidation</code> to be carried out
550 * on the object graph currently being deserialized before it is
551 * returned to the original caller of <code>readObject ()</code>.
552 * The order of validation for multiple
553 * <code>ObjectInputValidation</code>s can be controled using
554 * <code>priority</code>. Validators with higher priorities are
557 * @see java.io.ObjectInputValidation
559 * @exception InvalidObjectException <code>validator</code> is
562 * @exception NotActiveException an attempt was made to add a
563 * validator outside of the <code>readObject</code> method of the
564 * object currently being deserialized
566 public void registerValidation(ObjectInputValidation validator
,
568 throws InvalidObjectException
, NotActiveException
570 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
571 throw new NotActiveException("registerValidation called by non-active "
572 + "class and/or object");
574 if (validator
== null)
575 throw new InvalidObjectException("attempt to add a null "
576 + "ObjectInputValidation object");
578 this.validators
.addElement(new ValidatorAndPriority (validator
,
584 * Called when a class is being deserialized. This is a hook to
585 * allow subclasses to read in information written by the
586 * <code>annotateClass (Class)</code> method of an
587 * <code>ObjectOutputStream</code>.
589 * This implementation looks up the active call stack for a
590 * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
591 * it is used to load the class associated with <code>osc</code>,
592 * otherwise, the default system <code>ClassLoader</code> is used.
594 * @exception IOException Exception from underlying
595 * <code>OutputStream</code>.
597 * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
599 protected Class
resolveClass(ObjectStreamClass osc
)
600 throws ClassNotFoundException
, IOException
602 return Class
.forName(osc
.getName(), true, currentLoader());
606 * This method invokes the method currentClassLoader for the
607 * current security manager (or build an empty one if it is not
610 * @return The most recent non-system ClassLoader on the execution stack.
611 * @see java.lang.SecurityManager#currentClassLoader()
613 private ClassLoader
currentLoader()
615 SecurityManager sm
= System
.getSecurityManager();
617 sm
= new SecurityManager () {};
619 return currentClassLoader(sm
);
623 * Lookup a class stored in the local hashtable. If it is not
624 * use the global lookup function in ObjectStreamClass to build
625 * the ObjectStreamClass. This method is requested according to
626 * the behaviour detected in the JDK by Kaffe's team.
628 * @param clazz Class to lookup in the hash table or for which
629 * we must build a descriptor.
630 * @return A valid instance of ObjectStreamClass corresponding
631 * to the specified class.
633 private ObjectStreamClass
lookupClass(Class clazz
)
635 ObjectStreamClass oclazz
;
637 oclazz
= (ObjectStreamClass
)classLookupTable
.get(clazz
);
639 return ObjectStreamClass
.lookup(clazz
);
645 * Reconstruct class hierarchy the same way
646 * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
647 * but using lookupClass instead of ObjectStreamClass.lookup. This
648 * dup is necessary localize the lookup table. Hopefully some future
649 * rewritings will be able to prevent this.
651 * @param clazz This is the class for which we want the hierarchy.
653 * @return An array of valid {@link java.io.ObjectStreamClass} instances which
654 * represent the class hierarchy for clazz.
656 private ObjectStreamClass
[] inputGetObjectStreamClasses(Class clazz
)
658 ObjectStreamClass osc
= lookupClass(clazz
);
661 return new ObjectStreamClass
[0];
664 Vector oscs
= new Vector();
668 oscs
.addElement(osc
);
669 osc
= osc
.getSuper();
672 int count
= oscs
.size();
673 ObjectStreamClass
[] sorted_oscs
= new ObjectStreamClass
[count
];
675 for (int i
= count
- 1; i
>= 0; i
--)
676 sorted_oscs
[count
- i
- 1] = (ObjectStreamClass
) oscs
.elementAt(i
);
683 * Allows subclasses to resolve objects that are read from the
684 * stream with other objects to be returned in their place. This
685 * method is called the first time each object is encountered.
687 * This method must be enabled before it will be called in the
688 * serialization process.
690 * @exception IOException Exception from underlying
691 * <code>OutputStream</code>.
693 * @see #enableResolveObject(boolean)
695 protected Object
resolveObject(Object obj
) throws IOException
701 protected Class
resolveProxyClass(String
[] intfs
)
702 throws IOException
, ClassNotFoundException
704 SecurityManager sm
= System
.getSecurityManager();
707 sm
= new SecurityManager() {};
709 ClassLoader cl
= currentClassLoader(sm
);
711 Class
[] clss
= new Class
[intfs
.length
];
714 for (int i
= 0; i
< intfs
.length
; i
++)
715 clss
[i
] = Class
.forName(intfs
[i
]);
716 cl
= ClassLoader
.getSystemClassLoader();
719 for (int i
= 0; i
< intfs
.length
; i
++)
720 clss
[i
] = cl
.loadClass(intfs
[i
]);
723 return Proxy
.getProxyClass(cl
, clss
);
725 catch (IllegalArgumentException e
)
727 throw new ClassNotFoundException(null, e
);
732 * If <code>enable</code> is <code>true</code> and this object is
733 * trusted, then <code>resolveObject (Object)</code> will be called
734 * in subsequent calls to <code>readObject (Object)</code>.
735 * Otherwise, <code>resolveObject (Object)</code> will not be called.
737 * @exception SecurityException This class is not trusted.
739 protected boolean enableResolveObject (boolean enable
)
740 throws SecurityException
744 SecurityManager sm
= System
.getSecurityManager();
746 sm
.checkPermission(new SerializablePermission("enableSubstitution"));
749 boolean old_val
= this.resolveEnabled
;
750 this.resolveEnabled
= enable
;
755 * Reads stream magic and stream version information from the
758 * @exception IOException Exception from underlying stream.
760 * @exception StreamCorruptedException An invalid stream magic
761 * number or stream version was read from the stream.
763 protected void readStreamHeader()
764 throws IOException
, StreamCorruptedException
766 dumpElement("STREAM MAGIC ");
767 if (this.realInputStream
.readShort() != STREAM_MAGIC
)
768 throw new StreamCorruptedException("Invalid stream magic number");
770 dumpElementln("STREAM VERSION ");
771 if (this.realInputStream
.readShort() != STREAM_VERSION
)
772 throw new StreamCorruptedException("Invalid stream version number");
775 public int read() throws IOException
777 if (this.readDataFromBlock
)
779 if (this.blockDataPosition
>= this.blockDataBytes
)
781 return (this.blockData
[this.blockDataPosition
++] & 0xff);
784 return this.realInputStream
.read();
787 public int read(byte[] data
, int offset
, int length
) throws IOException
789 if (this.readDataFromBlock
)
791 if (this.blockDataPosition
+ length
> this.blockDataBytes
)
793 int remain
= this.blockDataBytes
- this.blockDataPosition
;
796 System
.arraycopy(this.blockData
, this.blockDataPosition
,
797 data
, offset
, remain
);
804 System
.arraycopy(this.blockData
, this.blockDataPosition
,
805 data
, offset
, length
);
806 this.blockDataPosition
+= length
;
811 return this.realInputStream
.read(data
, offset
, length
);
814 public int available() throws IOException
816 if (this.readDataFromBlock
)
818 if (this.blockDataPosition
>= this.blockDataBytes
)
821 return this.blockDataBytes
- this.blockDataPosition
;
824 return this.realInputStream
.available();
827 public void close() throws IOException
829 this.realInputStream
.close();
832 public boolean readBoolean() throws IOException
834 boolean switchmode
= true;
835 boolean oldmode
= this.readDataFromBlock
;
836 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 1)
839 oldmode
= setBlockDataMode (true);
840 boolean value
= this.dataInputStream
.readBoolean ();
842 setBlockDataMode (oldmode
);
846 public byte readByte() throws IOException
848 boolean switchmode
= true;
849 boolean oldmode
= this.readDataFromBlock
;
850 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 1)
853 oldmode
= setBlockDataMode(true);
854 byte value
= this.dataInputStream
.readByte();
856 setBlockDataMode(oldmode
);
860 public int readUnsignedByte() throws IOException
862 boolean switchmode
= true;
863 boolean oldmode
= this.readDataFromBlock
;
864 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 1)
867 oldmode
= setBlockDataMode(true);
868 int value
= this.dataInputStream
.readUnsignedByte();
870 setBlockDataMode(oldmode
);
874 public short readShort() throws IOException
876 boolean switchmode
= true;
877 boolean oldmode
= this.readDataFromBlock
;
878 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 2)
881 oldmode
= setBlockDataMode(true);
882 short value
= this.dataInputStream
.readShort();
884 setBlockDataMode(oldmode
);
888 public int readUnsignedShort() throws IOException
890 boolean switchmode
= true;
891 boolean oldmode
= this.readDataFromBlock
;
892 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 2)
895 oldmode
= setBlockDataMode(true);
896 int value
= this.dataInputStream
.readUnsignedShort();
898 setBlockDataMode(oldmode
);
902 public char readChar() throws IOException
904 boolean switchmode
= true;
905 boolean oldmode
= this.readDataFromBlock
;
906 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 2)
909 oldmode
= setBlockDataMode(true);
910 char value
= this.dataInputStream
.readChar();
912 setBlockDataMode(oldmode
);
916 public int readInt() throws IOException
918 boolean switchmode
= true;
919 boolean oldmode
= this.readDataFromBlock
;
920 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 4)
923 oldmode
= setBlockDataMode(true);
924 int value
= this.dataInputStream
.readInt();
926 setBlockDataMode(oldmode
);
930 public long readLong() throws IOException
932 boolean switchmode
= true;
933 boolean oldmode
= this.readDataFromBlock
;
934 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 8)
937 oldmode
= setBlockDataMode(true);
938 long value
= this.dataInputStream
.readLong();
940 setBlockDataMode(oldmode
);
944 public float readFloat() throws IOException
946 boolean switchmode
= true;
947 boolean oldmode
= this.readDataFromBlock
;
948 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 4)
951 oldmode
= setBlockDataMode(true);
952 float value
= this.dataInputStream
.readFloat();
954 setBlockDataMode(oldmode
);
958 public double readDouble() throws IOException
960 boolean switchmode
= true;
961 boolean oldmode
= this.readDataFromBlock
;
962 if (!oldmode
|| this.blockDataBytes
- this.blockDataPosition
>= 8)
965 oldmode
= setBlockDataMode(true);
966 double value
= this.dataInputStream
.readDouble();
968 setBlockDataMode(oldmode
);
972 public void readFully(byte data
[]) throws IOException
974 this.dataInputStream
.readFully(data
);
977 public void readFully(byte data
[], int offset
, int size
)
980 this.dataInputStream
.readFully(data
, offset
, size
);
983 public int skipBytes(int len
) throws IOException
985 return this.dataInputStream
.skipBytes(len
);
990 * @see java.io.DataInputStream#readLine ()
992 public String
readLine() throws IOException
994 return this.dataInputStream
.readLine();
997 public String
readUTF() throws IOException
999 return this.dataInputStream
.readUTF();
1003 * This class allows a class to specify exactly which fields should
1004 * be read, and what values should be read for these fields.
1006 * XXX: finish up comments
1008 public static abstract class GetField
1010 public abstract ObjectStreamClass
getObjectStreamClass();
1012 public abstract boolean defaulted(String name
)
1013 throws IOException
, IllegalArgumentException
;
1015 public abstract boolean get(String name
, boolean defvalue
)
1016 throws IOException
, IllegalArgumentException
;
1018 public abstract char get(String name
, char defvalue
)
1019 throws IOException
, IllegalArgumentException
;
1021 public abstract byte get(String name
, byte defvalue
)
1022 throws IOException
, IllegalArgumentException
;
1024 public abstract short get(String name
, short defvalue
)
1025 throws IOException
, IllegalArgumentException
;
1027 public abstract int get(String name
, int defvalue
)
1028 throws IOException
, IllegalArgumentException
;
1030 public abstract long get(String name
, long defvalue
)
1031 throws IOException
, IllegalArgumentException
;
1033 public abstract float get(String name
, float defvalue
)
1034 throws IOException
, IllegalArgumentException
;
1036 public abstract double get(String name
, double defvalue
)
1037 throws IOException
, IllegalArgumentException
;
1039 public abstract Object
get(String name
, Object defvalue
)
1040 throws IOException
, IllegalArgumentException
;
1044 * This method should be called by a method called 'readObject' in the
1045 * deserializing class (if present). It cannot (and should not)be called
1046 * outside of it. Its goal is to read all fields in the real input stream
1047 * and keep them accessible through the {@link #GetField} class. Calling
1048 * this method will not alterate the deserializing object.
1050 * @return A valid freshly created 'GetField' instance to get access to
1051 * the deserialized stream.
1052 * @throws IOException An input/output exception occured.
1053 * @throws ClassNotFoundException
1054 * @throws NotActiveException
1056 public GetField
readFields()
1057 throws IOException
, ClassNotFoundException
, NotActiveException
1059 if (this.currentObject
== null || this.currentObjectStreamClass
== null)
1060 throw new NotActiveException("readFields called by non-active class and/or object");
1062 if (prereadFields
!= null)
1063 return prereadFields
;
1065 if (fieldsAlreadyRead
)
1066 throw new NotActiveException("readFields called but fields already read from"
1067 + " stream (by defaultReadObject or readFields)");
1069 final ObjectStreamClass clazz
= this.currentObjectStreamClass
;
1070 final byte[] prim_field_data
= new byte[clazz
.primFieldSize
];
1071 final Object
[] objs
= new Object
[clazz
.objectFieldCount
];
1073 // Apparently Block data is not used with GetField as per
1074 // empirical evidence against JDK 1.2. Also see Mauve test
1075 // java.io.ObjectInputOutput.Test.GetPutField.
1076 boolean oldmode
= setBlockDataMode(false);
1077 readFully(prim_field_data
);
1078 for (int i
= 0; i
< objs
.length
; ++ i
)
1079 objs
[i
] = readObject();
1080 setBlockDataMode(oldmode
);
1082 prereadFields
= new GetField()
1084 public ObjectStreamClass
getObjectStreamClass()
1089 public boolean defaulted(String name
)
1090 throws IOException
, IllegalArgumentException
1092 ObjectStreamField f
= clazz
.getField(name
);
1094 /* First if we have a serialized field use the descriptor */
1097 /* It is in serialPersistentFields but setClass tells us
1098 * it should not be set. This value is defaulted.
1100 if (f
.isPersistent() && !f
.isToSet())
1106 /* This is not a serialized field. There should be
1107 * a default value only if the field really exists.
1111 return (clazz
.forClass().getDeclaredField (name
) != null);
1113 catch (NoSuchFieldException e
)
1115 throw new IllegalArgumentException(e
.getMessage());
1119 public boolean get(String name
, boolean defvalue
)
1120 throws IOException
, IllegalArgumentException
1122 ObjectStreamField field
= getField(name
, Boolean
.TYPE
);
1127 return prim_field_data
[field
.getOffset()] == 0 ?
false : true;
1130 public char get(String name
, char defvalue
)
1131 throws IOException
, IllegalArgumentException
1133 ObjectStreamField field
= getField(name
, Character
.TYPE
);
1138 int off
= field
.getOffset();
1140 return (char)(((prim_field_data
[off
++] & 0xFF) << 8)
1141 | (prim_field_data
[off
] & 0xFF));
1144 public byte get(String name
, byte defvalue
)
1145 throws IOException
, IllegalArgumentException
1147 ObjectStreamField field
= getField(name
, Byte
.TYPE
);
1152 return prim_field_data
[field
.getOffset()];
1155 public short get(String name
, short defvalue
)
1156 throws IOException
, IllegalArgumentException
1158 ObjectStreamField field
= getField(name
, Short
.TYPE
);
1163 int off
= field
.getOffset();
1165 return (short)(((prim_field_data
[off
++] & 0xFF) << 8)
1166 | (prim_field_data
[off
] & 0xFF));
1169 public int get(String name
, int defvalue
)
1170 throws IOException
, IllegalArgumentException
1172 ObjectStreamField field
= getField(name
, Integer
.TYPE
);
1177 int off
= field
.getOffset();
1179 return ((prim_field_data
[off
++] & 0xFF) << 24)
1180 | ((prim_field_data
[off
++] & 0xFF) << 16)
1181 | ((prim_field_data
[off
++] & 0xFF) << 8)
1182 | (prim_field_data
[off
] & 0xFF);
1185 public long get(String name
, long defvalue
)
1186 throws IOException
, IllegalArgumentException
1188 ObjectStreamField field
= getField(name
, Long
.TYPE
);
1193 int off
= field
.getOffset();
1195 return (long)(((prim_field_data
[off
++] & 0xFF) << 56)
1196 | ((prim_field_data
[off
++] & 0xFF) << 48)
1197 | ((prim_field_data
[off
++] & 0xFF) << 40)
1198 | ((prim_field_data
[off
++] & 0xFF) << 32)
1199 | ((prim_field_data
[off
++] & 0xFF) << 24)
1200 | ((prim_field_data
[off
++] & 0xFF) << 16)
1201 | ((prim_field_data
[off
++] & 0xFF) << 8)
1202 | (prim_field_data
[off
] & 0xFF));
1205 public float get(String name
, float defvalue
)
1206 throws IOException
, IllegalArgumentException
1208 ObjectStreamField field
= getField(name
, Float
.TYPE
);
1213 int off
= field
.getOffset();
1215 return Float
.intBitsToFloat(((prim_field_data
[off
++] & 0xFF) << 24)
1216 | ((prim_field_data
[off
++] & 0xFF) << 16)
1217 | ((prim_field_data
[off
++] & 0xFF) << 8)
1218 | (prim_field_data
[off
] & 0xFF));
1221 public double get(String name
, double defvalue
)
1222 throws IOException
, IllegalArgumentException
1224 ObjectStreamField field
= getField(name
, Double
.TYPE
);
1229 int off
= field
.getOffset();
1231 return Double
.longBitsToDouble
1232 ( (long) (((prim_field_data
[off
++] & 0xFF) << 56)
1233 | ((prim_field_data
[off
++] & 0xFF) << 48)
1234 | ((prim_field_data
[off
++] & 0xFF) << 40)
1235 | ((prim_field_data
[off
++] & 0xFF) << 32)
1236 | ((prim_field_data
[off
++] & 0xFF) << 24)
1237 | ((prim_field_data
[off
++] & 0xFF) << 16)
1238 | ((prim_field_data
[off
++] & 0xFF) << 8)
1239 | (prim_field_data
[off
] & 0xFF)));
1242 public Object
get(String name
, Object defvalue
)
1243 throws IOException
, IllegalArgumentException
1245 ObjectStreamField field
=
1246 getField(name
, defvalue
== null ?
null : defvalue
.getClass ());
1251 return objs
[field
.getOffset()];
1254 private ObjectStreamField
getField(String name
, Class type
)
1255 throws IllegalArgumentException
1257 ObjectStreamField field
= clazz
.getField(name
);
1258 boolean illegal
= false;
1264 Class field_type
= field
.getType();
1266 if (type
== field_type
||
1267 (type
== null && !field_type
.isPrimitive()))
1274 throw new IllegalArgumentException
1275 ("Field requested is of type "
1276 + field_type
.getName()
1277 + ", but requested type was "
1278 + (type
== null ?
"Object" : type
.getName()));
1280 catch (NullPointerException _
)
1282 /* Here we catch NullPointerException, because it may
1283 only come from the call 'field.getType()'. If field
1284 is null, we have to return null and classpath ethic
1285 say we must try to avoid 'if (xxx == null)'.
1288 catch (IllegalArgumentException e
)
1297 /* If this is an unassigned field we should return
1298 * the default value.
1300 if (!illegal
&& field
!= null && !field
.isToSet() && field
.isPersistent())
1303 /* We do not want to modify transient fields. They should
1308 Field f
= clazz
.forClass().getDeclaredField(name
);
1309 if (Modifier
.isTransient(f
.getModifiers()))
1310 throw new IllegalArgumentException
1311 ("no such field (non transient) " + name
);
1312 if (field
== null && f
.getType() != type
)
1313 throw new IllegalArgumentException
1314 ("Invalid requested type for field " + name
);
1316 catch (NoSuchFieldException e
)
1319 throw new IllegalArgumentException(e
.getMessage());
1326 fieldsAlreadyRead
= true;
1327 return prereadFields
;
1331 * Protected constructor that allows subclasses to override
1332 * deserialization. This constructor should be called by subclasses
1333 * that wish to override <code>readObject (Object)</code>. This
1334 * method does a security check <i>NOTE: currently not
1335 * implemented</i>, then sets a flag that informs
1336 * <code>readObject (Object)</code> to call the subclasses
1337 * <code>readObjectOverride (Object)</code> method.
1339 * @see #readObjectOverride()
1341 protected ObjectInputStream()
1342 throws IOException
, SecurityException
1344 SecurityManager sec_man
= System
.getSecurityManager();
1345 if (sec_man
!= null)
1346 sec_man
.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION
);
1347 this.useSubclassMethod
= true;
1351 * This method allows subclasses to override the default
1352 * de serialization mechanism provided by
1353 * <code>ObjectInputStream</code>. To make this method be used for
1354 * writing objects, subclasses must invoke the 0-argument
1355 * constructor on this class from their constructor.
1357 * @see #ObjectInputStream()
1359 protected Object
readObjectOverride()
1360 throws ClassNotFoundException
, IOException
, OptionalDataException
1362 throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1366 * Assigns the next available handle to <code>obj</code>.
1368 * @param obj The object for which we want a new handle.
1369 * @return A valid handle for the specified object.
1371 private int assignNewHandle(Object obj
)
1373 this.objectLookupTable
.put(new Integer(this.nextOID
),
1374 new ObjectIdentityWrapper(obj
));
1375 return this.nextOID
++;
1378 private Object
processResolution(Object obj
, int handle
)
1381 if (obj
instanceof Serializable
)
1386 Class classArgs
[] = {};
1387 m
= getMethod(obj
.getClass(), "readResolve", classArgs
);
1388 obj
= m
.invoke(obj
, new Object
[] {});
1390 catch (NoSuchMethodException ignore
)
1393 catch (IllegalAccessException ignore
)
1396 catch (InvocationTargetException ignore
)
1401 if (this.resolveEnabled
)
1402 obj
= resolveObject(obj
);
1404 this.objectLookupTable
.put(new Integer(handle
),
1405 new ObjectIdentityWrapper(obj
));
1410 private void clearHandles()
1412 this.objectLookupTable
.clear();
1413 this.nextOID
= baseWireHandle
;
1416 private void readNextBlock() throws IOException
1418 readNextBlock(this.realInputStream
.readByte());
1421 private void readNextBlock(byte marker
) throws IOException
1423 if (marker
== TC_BLOCKDATA
)
1425 dumpElement("BLOCK DATA SIZE=");
1426 this.blockDataBytes
= this.realInputStream
.readUnsignedByte();
1427 dumpElementln (Integer
.toString(this.blockDataBytes
));
1429 else if (marker
== TC_BLOCKDATALONG
)
1431 dumpElement("BLOCK DATA LONG SIZE=");
1432 this.blockDataBytes
= this.realInputStream
.readInt();
1433 dumpElementln (Integer
.toString(this.blockDataBytes
));
1437 throw new EOFException("Attempt to read primitive data, but no data block is active.");
1440 if (this.blockData
.length
< this.blockDataBytes
)
1441 this.blockData
= new byte[this.blockDataBytes
];
1443 this.realInputStream
.readFully (this.blockData
, 0, this.blockDataBytes
);
1444 this.blockDataPosition
= 0;
1447 private void readArrayElements (Object array
, Class clazz
)
1448 throws ClassNotFoundException
, IOException
1450 if (clazz
.isPrimitive())
1452 if (clazz
== Boolean
.TYPE
)
1454 boolean[] cast_array
= (boolean[])array
;
1455 for (int i
=0; i
< cast_array
.length
; i
++)
1456 cast_array
[i
] = this.realInputStream
.readBoolean();
1459 if (clazz
== Byte
.TYPE
)
1461 byte[] cast_array
= (byte[])array
;
1462 for (int i
=0; i
< cast_array
.length
; i
++)
1463 cast_array
[i
] = this.realInputStream
.readByte();
1466 if (clazz
== Character
.TYPE
)
1468 char[] cast_array
= (char[])array
;
1469 for (int i
=0; i
< cast_array
.length
; i
++)
1470 cast_array
[i
] = this.realInputStream
.readChar();
1473 if (clazz
== Double
.TYPE
)
1475 double[] cast_array
= (double[])array
;
1476 for (int i
=0; i
< cast_array
.length
; i
++)
1477 cast_array
[i
] = this.realInputStream
.readDouble();
1480 if (clazz
== Float
.TYPE
)
1482 float[] cast_array
= (float[])array
;
1483 for (int i
=0; i
< cast_array
.length
; i
++)
1484 cast_array
[i
] = this.realInputStream
.readFloat();
1487 if (clazz
== Integer
.TYPE
)
1489 int[] cast_array
= (int[])array
;
1490 for (int i
=0; i
< cast_array
.length
; i
++)
1491 cast_array
[i
] = this.realInputStream
.readInt();
1494 if (clazz
== Long
.TYPE
)
1496 long[] cast_array
= (long[])array
;
1497 for (int i
=0; i
< cast_array
.length
; i
++)
1498 cast_array
[i
] = this.realInputStream
.readLong();
1501 if (clazz
== Short
.TYPE
)
1503 short[] cast_array
= (short[])array
;
1504 for (int i
=0; i
< cast_array
.length
; i
++)
1505 cast_array
[i
] = this.realInputStream
.readShort();
1511 Object
[] cast_array
= (Object
[])array
;
1512 for (int i
=0; i
< cast_array
.length
; i
++)
1513 cast_array
[i
] = readObject();
1517 private void readFields (Object obj
, ObjectStreamClass stream_osc
)
1518 throws ClassNotFoundException
, IOException
1520 ObjectStreamField
[] stream_fields
= stream_osc
.fields
;
1521 ObjectStreamField
[] real_fields
=
1522 lookupClass(stream_osc
.forClass()).fields
;
1524 boolean default_initialize
, set_value
;
1525 String field_name
= null;
1527 ObjectStreamField stream_field
= null;
1528 ObjectStreamField real_field
= null;
1532 while (stream_idx
< stream_fields
.length
1533 && real_idx
< real_fields
.length
)
1535 default_initialize
= false;
1538 if (stream_idx
== stream_fields
.length
)
1539 default_initialize
= true;
1542 stream_field
= stream_fields
[stream_idx
];
1543 type
= stream_field
.getType();
1546 if (real_idx
== real_fields
.length
)
1550 real_field
= real_fields
[real_idx
];
1551 type
= real_field
.getType();
1552 field_name
= real_field
.getName();
1555 if (set_value
&& !default_initialize
)
1558 real_field
.compareTo (stream_field
);
1562 default_initialize
= true;
1565 else if (comp_val
> 0)
1577 if (stream_field
.getOffset() < 0)
1579 default_initialize
= true;
1583 if (!stream_field
.isToSet())
1588 if (type
== Boolean
.TYPE
)
1591 default_initialize ?
false : this.realInputStream
.readBoolean();
1592 if (!default_initialize
&& set_value
)
1593 dumpElementln(" " + field_name
+ ": " + value
);
1595 setBooleanField(obj
, stream_osc
.forClass(), field_name
, value
);
1597 else if (type
== Byte
.TYPE
)
1600 default_initialize ?
0 : this.realInputStream
.readByte();
1601 if (!default_initialize
&& set_value
)
1602 dumpElementln(" " + field_name
+ ": " + value
);
1604 setByteField(obj
, stream_osc
.forClass(), field_name
, value
);
1606 else if (type
== Character
.TYPE
)
1609 default_initialize ?
(char)0 : this.realInputStream
.readChar();
1610 if (!default_initialize
&& set_value
)
1611 dumpElementln(" " + field_name
+ ": " + value
);
1613 setCharField(obj
, stream_osc
.forClass(), field_name
, value
);
1615 else if (type
== Double
.TYPE
)
1618 default_initialize ?
0 : this.realInputStream
.readDouble();
1619 if (!default_initialize
&& set_value
)
1620 dumpElementln(" " + field_name
+ ": " + value
);
1622 setDoubleField(obj
, stream_osc
.forClass(), field_name
, value
);
1624 else if (type
== Float
.TYPE
)
1627 default_initialize ?
0 : this.realInputStream
.readFloat();
1628 if (!default_initialize
&& set_value
)
1629 dumpElementln(" " + field_name
+ ": " + value
);
1631 setFloatField(obj
, stream_osc
.forClass(), field_name
, value
);
1633 else if (type
== Integer
.TYPE
)
1636 default_initialize ?
0 : this.realInputStream
.readInt();
1637 if (!default_initialize
&& set_value
)
1638 dumpElementln(" " + field_name
+ ": " + value
);
1640 setIntField(obj
, stream_osc
.forClass(), field_name
, value
);
1642 else if (type
== Long
.TYPE
)
1645 default_initialize ?
0 : this.realInputStream
.readLong();
1646 if (!default_initialize
&& set_value
)
1647 dumpElementln(" " + field_name
+ ": " + value
);
1649 setLongField(obj
, stream_osc
.forClass(), field_name
, value
);
1651 else if (type
== Short
.TYPE
)
1654 default_initialize ?
(short)0 : this.realInputStream
.readShort();
1655 if (!default_initialize
&& set_value
)
1656 dumpElementln(" " + field_name
+ ": " + value
);
1658 setShortField(obj
, stream_osc
.forClass(), field_name
, value
);
1663 default_initialize ?
null : readObject();
1665 setObjectField(obj
, stream_osc
.forClass(), field_name
,
1666 real_field
.getTypeString(), value
);
1669 catch (NoSuchFieldError e
)
1671 dumpElementln("XXXX " + field_name
+ " does not exist.");
1676 // Toggles writing primitive data to block-data buffer.
1677 private boolean setBlockDataMode (boolean on
)
1679 boolean oldmode
= this.readDataFromBlock
;
1680 this.readDataFromBlock
= on
;
1683 this.dataInputStream
= this.blockDataInput
;
1685 this.dataInputStream
= this.realInputStream
;
1689 // returns a new instance of REAL_CLASS that has been constructed
1690 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1691 private Object
newObject (Class real_class
, Class constructor_class
)
1695 Object obj
= allocateObject (real_class
);
1696 callConstructor (constructor_class
, obj
);
1699 catch (InstantiationException e
)
1705 // runs all registered ObjectInputValidations in prioritized order
1707 private void invokeValidators() throws InvalidObjectException
1709 Object
[] validators
= new Object
[this.validators
.size()];
1710 this.validators
.copyInto (validators
);
1711 Arrays
.sort (validators
);
1715 for (int i
=0; i
< validators
.length
; i
++)
1716 ((ObjectInputValidation
)validators
[i
]).validateObject();
1720 this.validators
.removeAllElements();
1725 * This native method is used to get access to the protected method
1726 * of the same name in SecurityManger.
1728 * @param sm SecurityManager instance which should be called.
1729 * @return The current class loader in the calling stack.
1731 private static ClassLoader
currentClassLoader (SecurityManager sm
)
1733 // FIXME: This is too simple.
1734 return ClassLoader
.getSystemClassLoader ();
1738 * This method tries to access a precise field called in the
1739 * specified class. Before accessing the field, it tries to
1740 * gain control on this field. If the field is either declared as
1741 * not persistent or transient then it returns null
1744 * @param klass Class to get the field from.
1745 * @param name Name of the field to access.
1746 * @return Field instance representing the requested field.
1747 * @throws NoSuchFieldException if the field does not exist.
1749 private Field
getField(Class klass
, String name
)
1750 throws java
.lang
.NoSuchFieldException
1752 final Field f
= klass
.getDeclaredField(name
);
1753 ObjectStreamField sf
= lookupClass(klass
).getField(name
);
1755 AccessController
.doPrivileged(new PrivilegedAction()
1759 f
.setAccessible(true);
1764 /* We do not want to modify transient fields. They should
1766 * N.B.: Not valid if the field is in serialPersistentFields.
1768 if (Modifier
.isTransient(f
.getModifiers()) && !sf
.isPersistent())
1774 private static Method
getMethod (Class klass
, String name
, Class args
[])
1775 throws java
.lang
.NoSuchMethodException
1777 final Method m
= klass
.getDeclaredMethod(name
, args
);
1778 AccessController
.doPrivileged(new PrivilegedAction()
1782 m
.setAccessible(true);
1789 private void callReadMethod (Object obj
, ObjectStreamClass osc
) throws IOException
1791 Class klass
= osc
.forClass();
1794 Class classArgs
[] = {ObjectInputStream
.class};
1795 Method m
= getMethod (klass
, "readObject", classArgs
);
1796 Object args
[] = {this};
1797 m
.invoke(obj
, args
);
1799 catch (NoSuchMethodException nsme
)
1803 catch (InvocationTargetException x
)
1805 /* Rethrow if possible. */
1806 Throwable exception
= x
.getTargetException();
1807 if (exception
instanceof RuntimeException
)
1808 throw (RuntimeException
) exception
;
1809 if (exception
instanceof IOException
)
1810 throw (IOException
) exception
;
1812 throw new IOException("Exception thrown from readObject() on " +
1813 klass
+ ": " + exception
.getClass().getName());
1817 throw new IOException("Failure invoking readObject() on " +
1818 klass
+ ": " + x
.getClass().getName());
1821 // Invalidate fields which has been read through readFields.
1822 prereadFields
= null;
1825 private native Object
allocateObject (Class clazz
)
1826 throws InstantiationException
;
1828 private native void callConstructor (Class clazz
, Object obj
);
1831 * This method writes a "boolean" value <code>val</code> in the specified field
1832 * of the instance <code>obj</code> of the type <code>klass</code>.
1834 * @param obj Instance to setup.
1835 * @param klass Class type of the specified instance.
1836 * @param field_name Name of the field in the specified class type.
1837 * @param val The boolean value to write into the field.
1838 * @throws InvalidClassException if the specified field has not the required type.
1839 * @throws IOException if there is no field of that name in the specified class.
1841 private void setBooleanField(Object obj
, Class klass
, String field_name
,
1842 boolean val
) throws IOException
, InvalidClassException
1846 Field f
= getField(klass
, field_name
);
1847 f
.setBoolean(obj
, val
);
1849 catch (IllegalArgumentException _
)
1851 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
1859 * This method writes a "byte" value <code>val</code> in the specified field
1860 * of the instance <code>obj</code> of the type <code>klass</code>.
1862 * @param obj Instance to setup.
1863 * @param klass Class type of the specified instance.
1864 * @param field_name Name of the field in the specified class type.
1865 * @param val The byte value to write into the field.
1866 * @throws InvalidClassException if the specified field has not the required type.
1867 * @throws IOException if there is no field of that name in the specified class.
1869 private void setByteField(Object obj
, Class klass
, String field_name
,
1870 byte val
) throws IOException
, InvalidClassException
1874 Field f
= getField(klass
, field_name
);
1875 f
.setByte(obj
, val
);
1877 catch (IllegalArgumentException _
)
1879 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
1887 * This method writes a "character" value <code>val</code> in the specified field
1888 * of the instance <code>obj</code> of the type <code>klass</code>.
1890 * @param obj Instance to setup.
1891 * @param klass Class type of the specified instance.
1892 * @param field_name Name of the field in the specified class type.
1893 * @param val The character value to write into the field.
1894 * @throws InvalidClassException if the specified field has not the required type.
1895 * @throws IOException if there is no field of that name in the specified class.
1897 private void setCharField(Object obj
, Class klass
, String field_name
,
1898 char val
) throws IOException
, InvalidClassException
1902 Field f
= getField(klass
, field_name
);
1903 f
.setChar(obj
, val
);
1905 catch (IllegalArgumentException _
)
1907 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
1915 * This method writes a "double" value <code>val</code> in the specified field
1916 * of the instance <code>obj</code> of the type <code>klass</code>.
1918 * @param obj Instance to setup.
1919 * @param klass Class type of the specified instance.
1920 * @param field_name Name of the field in the specified class type.
1921 * @param val The double value to write into the field.
1922 * @throws InvalidClassException if the specified field has not the required type.
1923 * @throws IOException if there is no field of that name in the specified class.
1925 private void setDoubleField(Object obj
, Class klass
, String field_name
,
1926 double val
) throws IOException
, InvalidClassException
1930 Field f
= getField(klass
, field_name
);
1931 f
.setDouble(obj
, val
);
1933 catch (IllegalArgumentException _
)
1935 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
1943 * This method writes a "float" value <code>val</code> in the specified field
1944 * of the instance <code>obj</code> of the type <code>klass</code>.
1946 * @param obj Instance to setup.
1947 * @param klass Class type of the specified instance.
1948 * @param field_name Name of the field in the specified class type.
1949 * @param val The float value to write into the field.
1950 * @throws InvalidClassException if the specified field has not the required type.
1951 * @throws IOException if there is no field of that name in the specified class.
1953 private void setFloatField(Object obj
, Class klass
, String field_name
,
1954 float val
) throws IOException
, InvalidClassException
1958 Field f
= getField(klass
, field_name
);
1959 f
.setFloat(obj
, val
);
1961 catch (IllegalArgumentException _
)
1963 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
1971 * This method writes an "integer" value <code>val</code> in the specified field
1972 * of the instance <code>obj</code> of the type <code>klass</code>.
1974 * @param obj Instance to setup.
1975 * @param klass Class type of the specified instance.
1976 * @param field_name Name of the field in the specified class type.
1977 * @param val The integer value to write into the field.
1978 * @throws InvalidClassException if the specified field has not the required type.
1979 * @throws IOException if there is no field of that name in the specified class.
1981 private void setIntField(Object obj
, Class klass
, String field_name
,
1982 int val
) throws IOException
, InvalidClassException
1986 Field f
= getField(klass
, field_name
);
1989 catch (IllegalArgumentException _
)
1991 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
1999 * This method writes the long value <code>val</code> in the specified field
2000 * of the instance <code>obj</code> of the type <code>klass</code>.
2002 * @param obj Instance to setup.
2003 * @param klass Class type of the specified instance.
2004 * @param field_name Name of the field in the specified class type.
2005 * @param val The long value to write into the field.
2006 * @throws InvalidClassException if the specified field has not the required type.
2007 * @throws IOException if there is no field of that name in the specified class.
2009 private void setLongField(Object obj
, Class klass
, String field_name
,
2010 long val
) throws IOException
, InvalidClassException
2014 Field f
= getField(klass
, field_name
);
2015 f
.setLong(obj
, val
);
2017 catch (IllegalArgumentException _
)
2019 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
2027 * This method writes a "short" value <code>val</code> in the specified field
2028 * of the instance <code>obj</code> of the type <code>klass</code>.
2030 * @param obj Instance to setup.
2031 * @param klass Class type of the specified instance.
2032 * @param field_name Name of the field in the specified class type.
2033 * @param val The short value to write into the field.
2034 * @throws InvalidClassException if the specified field has not the required type.
2035 * @throws IOException if there is no field of that name in the specified class.
2037 private void setShortField(Object obj
, Class klass
, String field_name
,
2038 short val
) throws IOException
, InvalidClassException
2042 Field f
= getField(klass
, field_name
);
2043 f
.setShort(obj
, val
);
2045 catch (IllegalArgumentException _
)
2047 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
2055 * This method writes an "object" value <code>val</code> in the specified field
2056 * of the instance <code>obj</code> of the type <code>klass</code>.
2058 * @param obj Instance to setup.
2059 * @param klass Class type of the specified instance.
2060 * @param field_name Name of the field in the specified class type.
2061 * @param val The "object" value to write into the field.
2062 * @throws InvalidClassException if the specified field has not the required type.
2063 * @throws IOException if there is no field of that name in the specified class.
2065 private void setObjectField(Object obj
, Class klass
, String field_name
,
2066 String type_code
, Object val
) throws IOException
, InvalidClassException
2070 Field f
= getField(klass
, field_name
);
2071 ObjectStreamField of
= new ObjectStreamField(field_name
, f
.getType());
2073 if (of
.getTypeString() == null ||
2074 !of
.getTypeString().equals(type_code
))
2075 throw new InvalidClassException("incompatible field type for " + klass
.getName() + "." + field_name
);
2078 catch (InvalidClassException e
)
2087 private static final int BUFFER_SIZE
= 1024;
2088 private static final Class
[] readObjectParams
= { ObjectInputStream
.class };
2090 private DataInputStream realInputStream
;
2091 private DataInputStream dataInputStream
;
2092 private DataInputStream blockDataInput
;
2093 private int blockDataPosition
;
2094 private int blockDataBytes
;
2095 private byte[] blockData
;
2096 private boolean useSubclassMethod
;
2097 private int nextOID
;
2098 private boolean resolveEnabled
;
2099 private Hashtable objectLookupTable
;
2100 private Object currentObject
;
2101 private ObjectStreamClass currentObjectStreamClass
;
2102 private boolean readDataFromBlock
;
2103 private boolean isDeserializing
;
2104 private boolean fieldsAlreadyRead
;
2105 private Vector validators
;
2106 private Hashtable classLookupTable
;
2107 private GetField prereadFields
;
2109 private static boolean dump
;
2111 private void dumpElement (String msg
)
2113 if (Configuration
.DEBUG
&& dump
)
2114 System
.out
.print(msg
);
2117 private void dumpElementln (String msg
)
2119 if (Configuration
.DEBUG
&& dump
)
2120 System
.out
.println(msg
);
2125 if (Configuration
.INIT_LOAD_LIBRARY
)
2127 System
.loadLibrary ("javaio");
2133 // used to keep a prioritized list of object validators
2134 class ValidatorAndPriority
implements Comparable
2137 ObjectInputValidation validator
;
2139 ValidatorAndPriority (ObjectInputValidation validator
, int priority
)
2141 this.priority
= priority
;
2142 this.validator
= validator
;
2145 public int compareTo (Object o
)
2147 ValidatorAndPriority vap
= (ValidatorAndPriority
)o
;
2148 return this.priority
- vap
.priority
;