]> gcc.gnu.org Git - gcc.git/blob - libjava/java/io/ObjectInputStream.java
ObjectInputStream.java (resolveProxyClass): New method from Classpath.
[gcc.git] / libjava / java / io / ObjectInputStream.java
1 /* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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)
9 any later version.
10
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.
15
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
19 02111-1307 USA.
20
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
24 combination.
25
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. */
37
38
39 package java.io;
40
41 import gnu.classpath.Configuration;
42
43 import java.lang.reflect.Array;
44 import java.lang.reflect.Modifier;
45 import java.lang.reflect.Proxy;
46 import java.util.Arrays;
47 import java.util.Hashtable;
48 import java.util.Vector;
49
50 import gnu.java.io.ObjectIdentityWrapper;
51 import gnu.java.lang.reflect.TypeSignature;
52 import java.lang.reflect.Field;
53 import java.lang.reflect.Method;
54 import java.lang.reflect.InvocationTargetException;
55
56
57
58 public class ObjectInputStream extends InputStream
59 implements ObjectInput, ObjectStreamConstants
60 {
61 /**
62 Creates a new <code>ObjectInputStream</code> that will do all of
63 its reading from <code>in</code>. This method also checks
64 the stream by reading the header information (stream magic number
65 and stream version).
66
67 @exception IOException Reading stream header from underlying
68 stream cannot be completed.
69
70 @exception StreamCorruptedException An invalid stream magic
71 number or stream version was read from the stream.
72
73 @see readStreamHeader ()
74 */
75 public ObjectInputStream (InputStream in)
76 throws IOException, StreamCorruptedException
77 {
78 if (Configuration.DEBUG)
79 {
80 String val = System.getProperty("gcj.dumpobjects");
81 if (dump == false && val != null && !val.equals(""))
82 {
83 dump = true;
84 System.out.println ("Serialization debugging enabled");
85 }
86 else if (dump == true && (val == null || val.equals("")))
87 {
88 dump = false;
89 System.out.println ("Serialization debugging disabled");
90 }
91 }
92
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 setBlockDataMode (true);
104 readStreamHeader ();
105 }
106
107
108 /**
109 Returns the next deserialized object read from the underlying stream.
110
111 This method can be overriden by a class by implementing
112 <code>private void readObject (ObjectInputStream)</code>.
113
114 If an exception is thrown from this method, the stream is left in
115 an undefined state.
116
117 @exception ClassNotFoundException The class that an object being
118 read in belongs to cannot be found.
119
120 @exception IOException Exception from underlying
121 <code>InputStream</code>.
122 */
123 public final Object readObject () throws ClassNotFoundException, IOException
124 {
125 if (this.useSubclassMethod)
126 return readObjectOverride ();
127
128 boolean was_deserializing;
129
130 Object ret_val;
131 was_deserializing = this.isDeserializing;
132
133 if (! was_deserializing)
134 setBlockDataMode (false);
135
136 this.isDeserializing = true;
137
138 byte marker = this.realInputStream.readByte ();
139 dumpElement ("MARKER: 0x" + Integer.toHexString(marker) + " ");
140
141 switch (marker)
142 {
143 case TC_BLOCKDATA:
144 case TC_BLOCKDATALONG:
145 if (marker == TC_BLOCKDATALONG)
146 dumpElementln ("BLOCKDATALONG");
147 else
148 dumpElementln ("BLOCKDATA");
149 readNextBlock (marker);
150 throw new StreamCorruptedException ("Unexpected blockData");
151
152 case TC_NULL:
153 dumpElementln ("NULL");
154 ret_val = null;
155 break;
156
157 case TC_REFERENCE:
158 {
159 dumpElement ("REFERENCE ");
160 Integer oid = new Integer (this.realInputStream.readInt ());
161 dumpElementln (Integer.toHexString(oid.intValue()));
162 ret_val = ((ObjectIdentityWrapper)
163 this.objectLookupTable.get (oid)).object;
164 break;
165 }
166
167 case TC_CLASS:
168 {
169 dumpElementln ("CLASS");
170 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
171 Class clazz = osc.forClass ();
172 assignNewHandle (clazz);
173 ret_val = clazz;
174 break;
175 }
176
177 case TC_CLASSDESC:
178 {
179 dumpElement ("CLASSDESC NAME=");
180 String name = this.realInputStream.readUTF ();
181 dumpElement (name + "; UID=");
182 long uid = this.realInputStream.readLong ();
183 dumpElement (Long.toHexString(uid) + "; FLAGS=");
184 byte flags = this.realInputStream.readByte ();
185 dumpElement (Integer.toHexString(flags) + "; FIELD COUNT=");
186 short field_count = this.realInputStream.readShort ();
187 dumpElementln (Short.toString(field_count));
188 ObjectStreamField[] fields = new ObjectStreamField[field_count];
189
190 ObjectStreamClass osc = new ObjectStreamClass (name, uid,
191 flags, fields);
192 assignNewHandle (osc);
193
194 for (int i=0; i < field_count; i++)
195 {
196 dumpElement (" TYPE CODE=");
197 char type_code = (char)this.realInputStream.readByte ();
198 dumpElement (type_code + "; FIELD NAME=");
199 String field_name = this.realInputStream.readUTF ();
200 dumpElementln (field_name);
201 String class_name;
202
203 if (type_code == 'L' || type_code == '[')
204 class_name = (String)readObject ();
205 else
206 class_name = String.valueOf (type_code);
207
208 fields[i] =
209 new ObjectStreamField (field_name,
210 TypeSignature.getClassForEncoding
211 (class_name));
212 }
213
214 Class cl = resolveClass (osc);
215 osc.setClass (cl);
216 setBlockDataMode (false);
217
218 if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
219 throw new IOException ("Data annotated to class was not consumed.");
220 dumpElementln ("ENDBLOCKDATA ");
221
222 osc.setSuperclass ((ObjectStreamClass)readObject ());
223 ret_val = osc;
224 break;
225 }
226
227 case TC_STRING:
228 {
229 dumpElement ("STRING=");
230 String s = this.realInputStream.readUTF ();
231 dumpElementln (s);
232 ret_val = processResolution (s, assignNewHandle (s));
233 break;
234 }
235
236 case TC_ARRAY:
237 {
238 dumpElementln ("ARRAY");
239 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
240 Class componentType = osc.forClass ().getComponentType ();
241 dumpElement ("ARRAY LENGTH=");
242 int length = this.realInputStream.readInt ();
243 dumpElementln (length + "; COMPONENT TYPE=" + componentType);
244 Object array = Array.newInstance (componentType, length);
245 int handle = assignNewHandle (array);
246 readArrayElements (array, componentType);
247 for (int i=0, len=Array.getLength(array); i < len; i++)
248 dumpElementln (" ELEMENT[" + i + "]=" + Array.get(array, i));
249 ret_val = processResolution (array, handle);
250 break;
251 }
252
253 case TC_OBJECT:
254 {
255 dumpElementln ("OBJECT");
256 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
257 Class clazz = osc.forClass ();
258
259 if (!Serializable.class.isAssignableFrom (clazz))
260 throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
261
262 if (Externalizable.class.isAssignableFrom (clazz))
263 {
264 Externalizable obj = null;
265
266 try
267 {
268 obj = (Externalizable)clazz.newInstance ();
269 }
270 catch (InstantiationException e)
271 {
272 throw new ClassNotFoundException ("Instance of " + clazz
273 + " could not be created");
274 }
275 catch (IllegalAccessException e)
276 {
277 throw new ClassNotFoundException ("Instance of " + clazz
278 + " could not be created because class or zero-argument constructor is not accessible");
279 }
280 catch (NoSuchMethodError e)
281 {
282 throw new ClassNotFoundException ("Instance of " + clazz
283 + " could not be created because zero-argument constructor is not defined");
284 }
285
286 int handle = assignNewHandle (obj);
287
288 boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
289
290 if (read_from_blocks)
291 setBlockDataMode (true);
292
293 obj.readExternal (this);
294
295 if (read_from_blocks)
296 setBlockDataMode (false);
297
298 ret_val = processResolution (obj, handle);
299 break;
300 } // end if (Externalizable.class.isAssignableFrom (clazz))
301
302 // find the first non-serializable, non-abstract
303 // class in clazz's inheritance hierarchy
304 Class first_nonserial = clazz.getSuperclass ();
305 while (Serializable.class.isAssignableFrom (first_nonserial)
306 || Modifier.isAbstract (first_nonserial.getModifiers ()))
307 first_nonserial = first_nonserial.getSuperclass ();
308
309 // DEBUGln ("Using " + first_nonserial
310 // + " as starting point for constructing " + clazz);
311
312 Object obj = null;
313 obj = newObject (clazz, first_nonserial);
314
315 if (obj == null)
316 throw new ClassNotFoundException ("Instance of " + clazz +
317 " could not be created");
318
319 int handle = assignNewHandle (obj);
320 this.currentObject = obj;
321 ObjectStreamClass[] hierarchy =
322 ObjectStreamClass.getObjectStreamClasses (clazz);
323
324 // DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
325
326 boolean has_read;
327 for (int i=0; i < hierarchy.length; i++)
328 {
329 this.currentObjectStreamClass = hierarchy[i];
330
331 dumpElementln ("Reading fields of "
332 + this.currentObjectStreamClass.getName ());
333
334 has_read = true;
335
336 try
337 {
338 this.currentObjectStreamClass.forClass ().
339 getDeclaredMethod ("readObject", readObjectParams);
340 }
341 catch (NoSuchMethodException e)
342 {
343 has_read = false;
344 }
345
346 // XXX: should initialize fields in classes in the hierarchy
347 // that aren't in the stream
348 // should skip over classes in the stream that aren't in the
349 // real classes hierarchy
350 readFields (obj, this.currentObjectStreamClass.fields,
351 has_read, this.currentObjectStreamClass);
352
353 if (has_read)
354 {
355 dumpElement ("ENDBLOCKDATA? ");
356 try
357 {
358 // FIXME: XXX: This try block is to catch EOF which is
359 // thrown for some objects. That indicates a bug in the logic.
360 if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
361 throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
362 dumpElementln ("yes");
363 }
364 catch (EOFException e)
365 {
366 dumpElementln ("no, got EOFException");
367 }
368 catch (IOException e)
369 {
370 dumpElementln ("no, got IOException");
371 }
372 }
373 }
374
375 this.currentObject = null;
376 this.currentObjectStreamClass = null;
377 ret_val = processResolution (obj, handle);
378 break;
379 }
380
381 case TC_RESET:
382 dumpElementln ("RESET");
383 clearHandles ();
384 ret_val = readObject ();
385 break;
386
387 case TC_EXCEPTION:
388 {
389 dumpElement ("EXCEPTION=");
390 Exception e = (Exception)readObject ();
391 dumpElementln (e.toString());
392 clearHandles ();
393 throw new WriteAbortedException ("Exception thrown during writing of stream", e);
394 }
395
396 default:
397 throw new IOException ("Unknown marker on stream");
398 }
399
400 this.isDeserializing = was_deserializing;
401
402 if (! was_deserializing)
403 {
404 setBlockDataMode (true);
405
406 if (validators.size () > 0)
407 invokeValidators ();
408 }
409
410 return ret_val;
411 }
412
413
414 /**
415 Reads the current objects non-transient, non-static fields from
416 the current class from the underlying output stream.
417
418 This method is intended to be called from within a object's
419 <code>private void readObject (ObjectInputStream)</code>
420 method.
421
422 @exception ClassNotFoundException The class that an object being
423 read in belongs to cannot be found.
424
425 @exception NotActiveException This method was called from a
426 context other than from the current object's and current class's
427 <code>private void readObject (ObjectInputStream)</code>
428 method.
429
430 @exception IOException Exception from underlying
431 <code>OutputStream</code>.
432 */
433 public void defaultReadObject ()
434 throws ClassNotFoundException, IOException, NotActiveException
435 {
436 if (this.currentObject == null || this.currentObjectStreamClass == null)
437 throw new NotActiveException ("defaultReadObject called by non-active class and/or object");
438
439 if (fieldsAlreadyRead)
440 throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
441
442 readFields (this.currentObject,
443 this.currentObjectStreamClass.fields,
444 false, this.currentObjectStreamClass);
445
446 fieldsAlreadyRead = true;
447 }
448
449
450 /**
451 Registers a <code>ObjectInputValidation</code> to be carried out
452 on the object graph currently being deserialized before it is
453 returned to the original caller of <code>readObject ()</code>.
454 The order of validation for multiple
455 <code>ObjectInputValidation</code>s can be controled using
456 <code>priority</code>. Validators with higher priorities are
457 called first.
458
459 @see java.io.ObjectInputValidation
460
461 @exception InvalidObjectException <code>validator</code> is
462 <code>null</code>
463
464 @exception NotActiveException an attempt was made to add a
465 validator outside of the <code>readObject</code> method of the
466 object currently being deserialized
467 */
468 public void registerValidation (ObjectInputValidation validator,
469 int priority)
470 throws InvalidObjectException, NotActiveException
471 {
472 if (this.currentObject == null || this.currentObjectStreamClass == null)
473 throw new NotActiveException ("registerValidation called by non-active class and/or object");
474
475 if (validator == null)
476 throw new InvalidObjectException ("attempt to add a null ObjectInputValidation object");
477
478 this.validators.addElement (new ValidatorAndPriority (validator,
479 priority));
480 }
481
482
483 /**
484 Called when a class is being deserialized. This is a hook to
485 allow subclasses to read in information written by the
486 <code>annotateClass (Class)</code> method of an
487 <code>ObjectOutputStream</code>.
488
489 This implementation looks up the active call stack for a
490 <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
491 it is used to load the class associated with <code>osc</code>,
492 otherwise, the default system <code>ClassLoader</code> is used.
493
494 @exception IOException Exception from underlying
495 <code>OutputStream</code>.
496
497 @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
498 */
499 protected Class resolveClass (ObjectStreamClass osc)
500 throws ClassNotFoundException, IOException
501 {
502 SecurityManager sm = System.getSecurityManager ();
503
504 // FIXME: currentClassLoader doesn't yet do anything useful. We need
505 // to call forName() with the classloader of the class which called
506 // readObject(). See SecurityManager.getClassContext().
507 ClassLoader cl = currentClassLoader (sm);
508
509 return Class.forName (osc.getName (), true, cl);
510 }
511
512 /**
513 Allows subclasses to resolve objects that are read from the
514 stream with other objects to be returned in their place. This
515 method is called the first time each object is encountered.
516
517 This method must be enabled before it will be called in the
518 serialization process.
519
520 @exception IOException Exception from underlying
521 <code>OutputStream</code>.
522
523 @see enableResolveObject (boolean)
524 */
525 protected Object resolveObject (Object obj) throws IOException
526 {
527 return obj;
528 }
529
530
531 protected Class resolveProxyClass (String[] intfs)
532 throws IOException, ClassNotFoundException
533 {
534 SecurityManager sm = System.getSecurityManager ();
535
536 if (sm == null)
537 sm = new SecurityManager () {};
538
539 ClassLoader cl = currentClassLoader (sm);
540
541 Class[] clss = new Class[intfs.length];
542 if(cl == null){
543 for (int i = 0; i < intfs.length; i++)
544 clss[i] = Class.forName(intfs[i]);
545 cl = ClassLoader.getSystemClassLoader();
546 }
547 else
548 for (int i = 0; i < intfs.length; i++)
549 clss[i] = cl.loadClass(intfs[i]);
550 try {
551 return Proxy.getProxyClass(cl, clss);
552 } catch (IllegalArgumentException e) {
553 throw new ClassNotFoundException(null, e);
554 }
555 }
556
557 /**
558 If <code>enable</code> is <code>true</code> and this object is
559 trusted, then <code>resolveObject (Object)</code> will be called
560 in subsequent calls to <code>readObject (Object)</code>.
561 Otherwise, <code>resolveObject (Object)</code> will not be called.
562
563 @exception SecurityException This class is not trusted.
564 */
565 protected boolean enableResolveObject (boolean enable)
566 throws SecurityException
567 {
568 if (enable)
569 {
570 SecurityManager sm = System.getSecurityManager ();
571 if (sm != null)
572 sm.checkPermission (new SerializablePermission ("enableSubtitution"));
573 }
574
575 boolean old_val = this.resolveEnabled;
576 this.resolveEnabled = enable;
577 return old_val;
578 }
579
580
581 /**
582 Reads stream magic and stream version information from the
583 underlying stream.
584
585 @exception IOException Exception from underlying stream.
586
587 @exception StreamCorruptedException An invalid stream magic
588 number or stream version was read from the stream.
589 */
590 protected void readStreamHeader ()
591 throws IOException, StreamCorruptedException
592 {
593 dumpElement ("STREAM MAGIC ");
594 if (this.realInputStream.readShort () != STREAM_MAGIC)
595 throw new StreamCorruptedException ("Invalid stream magic number");
596
597 dumpElementln ("STREAM VERSION ");
598 if (this.realInputStream.readShort () != STREAM_VERSION)
599 throw new StreamCorruptedException ("Invalid stream version number");
600 }
601
602
603 public int read () throws IOException
604 {
605 if (this.readDataFromBlock)
606 {
607 if (this.blockDataPosition >= this.blockDataBytes)
608 readNextBlock ();
609 return (this.blockData[this.blockDataPosition++] & 0xff);
610 }
611 else
612 return this.realInputStream.read ();
613 }
614
615 public int read (byte[] data, int offset, int length) throws IOException
616 {
617 if (this.readDataFromBlock)
618 {
619 if (this.blockDataPosition + length > this.blockDataBytes)
620 readNextBlock ();
621
622 System.arraycopy (this.blockData, this.blockDataPosition,
623 data, offset, length);
624 blockDataPosition += length;
625
626 return length;
627 }
628 else
629 return this.realInputStream.read (data, offset, length);
630 }
631
632 public int available () throws IOException
633 {
634 if (this.readDataFromBlock)
635 {
636 if (this.blockDataPosition >= this.blockDataBytes)
637 readNextBlock ();
638
639 return this.blockDataBytes - this.blockDataPosition;
640 }
641 else
642 return this.realInputStream.available ();
643 }
644
645 public void close () throws IOException
646 {
647 this.realInputStream.close ();
648 }
649
650 public boolean readBoolean () throws IOException
651 {
652 return this.dataInputStream.readBoolean ();
653 }
654
655 public byte readByte () throws IOException
656 {
657 return this.dataInputStream.readByte ();
658 }
659
660 public int readUnsignedByte () throws IOException
661 {
662 return this.dataInputStream.readUnsignedByte ();
663 }
664
665 public short readShort () throws IOException
666 {
667 return this.dataInputStream.readShort ();
668 }
669
670 public int readUnsignedShort () throws IOException
671 {
672 return this.dataInputStream.readUnsignedShort ();
673 }
674
675 public char readChar () throws IOException
676 {
677 return this.dataInputStream.readChar ();
678 }
679
680 public int readInt () throws IOException
681 {
682 return this.dataInputStream.readInt ();
683 }
684
685 public long readLong () throws IOException
686 {
687 return this.dataInputStream.readLong ();
688 }
689
690 public float readFloat () throws IOException
691 {
692 return this.dataInputStream.readFloat ();
693 }
694
695 public double readDouble () throws IOException
696 {
697 return this.dataInputStream.readDouble ();
698 }
699
700 public void readFully (byte data[]) throws IOException
701 {
702 this.dataInputStream.readFully (data);
703 }
704
705 public void readFully (byte data[], int offset, int size)
706 throws IOException
707 {
708 this.dataInputStream.readFully (data, offset, size);
709 }
710
711 public int skipBytes (int len) throws IOException
712 {
713 return this.dataInputStream.skipBytes (len);
714 }
715
716 /**
717 @deprecated
718 @see java.io.DataInputStream#readLine ()
719 */
720 public String readLine () throws IOException
721 {
722 return this.dataInputStream.readLine ();
723 }
724
725 public String readUTF () throws IOException
726 {
727 return this.dataInputStream.readUTF ();
728 }
729
730
731 /**
732 This class allows a class to specify exactly which fields should
733 be read, and what values should be read for these fields.
734
735 XXX: finish up comments
736 */
737 public static abstract class GetField
738 {
739 public abstract ObjectStreamClass getObjectStreamClass ();
740
741 public abstract boolean defaulted (String name)
742 throws IOException, IllegalArgumentException;
743
744 public abstract boolean get (String name, boolean defvalue)
745 throws IOException, IllegalArgumentException;
746
747 public abstract char get (String name, char defvalue)
748 throws IOException, IllegalArgumentException;
749
750 public abstract byte get (String name, byte defvalue)
751 throws IOException, IllegalArgumentException;
752
753 public abstract short get (String name, short defvalue)
754 throws IOException, IllegalArgumentException;
755
756 public abstract int get (String name, int defvalue)
757 throws IOException, IllegalArgumentException;
758
759 public abstract long get (String name, long defvalue)
760 throws IOException, IllegalArgumentException;
761
762 public abstract float get (String name, float defvalue)
763 throws IOException, IllegalArgumentException;
764
765 public abstract double get (String name, double defvalue)
766 throws IOException, IllegalArgumentException;
767
768 public abstract Object get (String name, Object defvalue)
769 throws IOException, IllegalArgumentException;
770 }
771
772 public GetField readFields ()
773 throws IOException, ClassNotFoundException, NotActiveException
774 {
775 if (this.currentObject == null || this.currentObjectStreamClass == null)
776 throw new NotActiveException ("readFields called by non-active class and/or object");
777
778 if (fieldsAlreadyRead)
779 throw new NotActiveException ("readFields called but fields already read from stream (by defaultReadObject or readFields)");
780
781 final ObjectStreamClass clazz = this.currentObjectStreamClass;
782 final byte[] prim_field_data = new byte[clazz.primFieldSize];
783 final Object[] objs = new Object[clazz.objectFieldCount];
784
785 // Apparently Block data is not used with GetField as per
786 // empirical evidence against JDK 1.2. Also see Mauve test
787 // java.io.ObjectInputOutput.Test.GetPutField.
788 setBlockDataMode (false);
789 readFully (prim_field_data);
790 for (int i = 0; i < objs.length; ++ i)
791 objs[i] = readObject ();
792 setBlockDataMode (true);
793
794 return new GetField ()
795 {
796 public ObjectStreamClass getObjectStreamClass ()
797 {
798 return clazz;
799 }
800
801 public boolean defaulted (String name)
802 throws IOException, IllegalArgumentException
803 {
804 return clazz.getField (name) == null;
805 }
806
807 public boolean get (String name, boolean defvalue)
808 throws IOException, IllegalArgumentException
809 {
810 ObjectStreamField field = getField (name, Boolean.TYPE);
811
812 if (field == null)
813 return defvalue;
814
815 return prim_field_data[field.getOffset ()] == 0 ? false : true;
816 }
817
818 public char get (String name, char defvalue)
819 throws IOException, IllegalArgumentException
820 {
821 ObjectStreamField field = getField (name, Character.TYPE);
822
823 if (field == null)
824 return defvalue;
825
826 int off = field.getOffset ();
827
828 return (char)(((prim_field_data[off++] & 0xFF) << 8)
829 | (prim_field_data[off] & 0xFF));
830 }
831
832 public byte get (String name, byte defvalue)
833 throws IOException, IllegalArgumentException
834 {
835 ObjectStreamField field = getField (name, Byte.TYPE);
836
837 if (field == null)
838 return defvalue;
839
840 return prim_field_data[field.getOffset ()];
841 }
842
843 public short get (String name, short defvalue)
844 throws IOException, IllegalArgumentException
845 {
846 ObjectStreamField field = getField (name, Short.TYPE);
847
848 if (field == null)
849 return defvalue;
850
851 int off = field.getOffset ();
852
853 return (short)(((prim_field_data[off++] & 0xFF) << 8)
854 | (prim_field_data[off] & 0xFF));
855 }
856
857 public int get (String name, int defvalue)
858 throws IOException, IllegalArgumentException
859 {
860 ObjectStreamField field = getField (name, Integer.TYPE);
861
862 if (field == null)
863 return defvalue;
864
865 int off = field.getOffset ();
866
867 return ((prim_field_data[off++] & 0xFF) << 24)
868 | ((prim_field_data[off++] & 0xFF) << 16)
869 | ((prim_field_data[off++] & 0xFF) << 8)
870 | (prim_field_data[off] & 0xFF);
871 }
872
873 public long get (String name, long defvalue)
874 throws IOException, IllegalArgumentException
875 {
876 ObjectStreamField field = getField (name, Long.TYPE);
877
878 if (field == null)
879 return defvalue;
880
881 int off = field.getOffset ();
882
883 return (long)(((prim_field_data[off++] & 0xFF) << 56)
884 | ((prim_field_data[off++] & 0xFF) << 48)
885 | ((prim_field_data[off++] & 0xFF) << 40)
886 | ((prim_field_data[off++] & 0xFF) << 32)
887 | ((prim_field_data[off++] & 0xFF) << 24)
888 | ((prim_field_data[off++] & 0xFF) << 16)
889 | ((prim_field_data[off++] & 0xFF) << 8)
890 | (prim_field_data[off] & 0xFF));
891 }
892
893 public float get (String name, float defvalue)
894 throws IOException, IllegalArgumentException
895 {
896 ObjectStreamField field = getField (name, Float.TYPE);
897
898 if (field == null)
899 return defvalue;
900
901 int off = field.getOffset ();
902
903 return Float.intBitsToFloat (((prim_field_data[off++] & 0xFF) << 24)
904 | ((prim_field_data[off++] & 0xFF) << 16)
905 | ((prim_field_data[off++] & 0xFF) << 8)
906 | (prim_field_data[off] & 0xFF));
907 }
908
909 public double get (String name, double defvalue)
910 throws IOException, IllegalArgumentException
911 {
912 ObjectStreamField field = getField (name, Double.TYPE);
913
914 if (field == null)
915 return defvalue;
916
917 int off = field.getOffset ();
918
919 return Double.longBitsToDouble (
920 (long)(((prim_field_data[off++] & 0xFF) << 56)
921 | ((prim_field_data[off++] & 0xFF) << 48)
922 | ((prim_field_data[off++] & 0xFF) << 40)
923 | ((prim_field_data[off++] & 0xFF) << 32)
924 | ((prim_field_data[off++] & 0xFF) << 24)
925 | ((prim_field_data[off++] & 0xFF) << 16)
926 | ((prim_field_data[off++] & 0xFF) << 8)
927 | (prim_field_data[off] & 0xFF)));
928 }
929
930 public Object get (String name, Object defvalue)
931 throws IOException, IllegalArgumentException
932 {
933 ObjectStreamField field =
934 getField (name, defvalue == null ? null : defvalue.getClass ());
935
936 if (field == null)
937 return defvalue;
938
939 return objs[field.getOffset ()];
940 }
941
942 private ObjectStreamField getField (String name, Class type)
943 throws IllegalArgumentException
944 {
945 ObjectStreamField field = clazz.getField (name);
946
947 if (field == null)
948 return null;
949
950 Class field_type = field.getType ();
951
952 if (type == field_type ||
953 (type == null && ! field_type.isPrimitive ()))
954 return field;
955
956 throw new IllegalArgumentException ("Field requested is of type "
957 + field_type.getName ()
958 + ", but requested type was "
959 + (type == null ?
960 "Object" : type.getName ()));
961 }
962 };
963
964 }
965
966
967 /**
968 Protected constructor that allows subclasses to override
969 deserialization. This constructor should be called by subclasses
970 that wish to override <code>readObject (Object)</code>. This
971 method does a security check <i>NOTE: currently not
972 implemented</i>, then sets a flag that informs
973 <code>readObject (Object)</code> to call the subclasses
974 <code>readObjectOverride (Object)</code> method.
975
976 @see readObjectOverride (Object)
977 */
978 protected ObjectInputStream ()
979 throws IOException, SecurityException
980 {
981 SecurityManager sec_man = System.getSecurityManager ();
982 if (sec_man != null)
983 sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
984 this.useSubclassMethod = true;
985 }
986
987
988 /**
989 This method allows subclasses to override the default
990 de serialization mechanism provided by
991 <code>ObjectInputStream</code>. To make this method be used for
992 writing objects, subclasses must invoke the 0-argument
993 constructor on this class from there constructor.
994
995 @see ObjectInputStream ()
996 */
997 protected Object readObjectOverride ()
998 throws ClassNotFoundException, IOException, OptionalDataException
999 {
1000 throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
1001 }
1002
1003
1004 // assigns the next availible handle to OBJ
1005 private int assignNewHandle (Object obj)
1006 {
1007 this.objectLookupTable.put (new Integer (this.nextOID),
1008 new ObjectIdentityWrapper (obj));
1009
1010 // try
1011 // {
1012 // DEBUG ("Assigning handle " + this.nextOID);
1013 // DEBUGln (" to " + obj);
1014 // }
1015 // catch (Throwable t) {}
1016
1017 return this.nextOID++;
1018 }
1019
1020
1021 private Object processResolution (Object obj, int handle)
1022 throws IOException
1023 {
1024 if (obj instanceof Serializable)
1025 {
1026 Method m = null;
1027 try
1028 {
1029 Class classArgs[] = {};
1030 m = obj.getClass ().getDeclaredMethod ("readResolve", classArgs);
1031 // m can't be null by definition since an exception would
1032 // have been thrown so a check for null is not needed.
1033 obj = m.invoke (obj, new Object[] {});
1034 }
1035 catch (NoSuchMethodException ignore)
1036 {
1037 }
1038 catch (IllegalAccessException ignore)
1039 {
1040 }
1041 catch (InvocationTargetException ignore)
1042 {
1043 }
1044 }
1045
1046 if (this.resolveEnabled)
1047 obj = resolveObject (obj);
1048
1049 this.objectLookupTable.put (new Integer (handle),
1050 new ObjectIdentityWrapper (obj));
1051
1052 return obj;
1053 }
1054
1055
1056 private void clearHandles ()
1057 {
1058 this.objectLookupTable.clear ();
1059 this.nextOID = baseWireHandle;
1060 }
1061
1062
1063 private void readNextBlock () throws IOException
1064 {
1065 // DEBUGln ("In readNextBlock ");
1066 readNextBlock (this.realInputStream.readByte ());
1067 }
1068
1069
1070 private void readNextBlock (byte marker) throws IOException
1071 {
1072 if (marker == TC_BLOCKDATA)
1073 {
1074 dumpElement ("BLOCK DATA SIZE=");
1075 this.blockDataBytes = this.realInputStream.readUnsignedByte ();
1076 dumpElementln (Integer.toString(this.blockDataBytes));
1077 }
1078 else if (marker == TC_BLOCKDATALONG)
1079 {
1080 dumpElement ("BLOCK DATA LONG SIZE=");
1081 this.blockDataBytes = this.realInputStream.readInt ();
1082 dumpElementln (Integer.toString(this.blockDataBytes));
1083 }
1084 else
1085 {
1086 throw new EOFException ("Attempt to read primitive data, but no data block is active.");
1087 }
1088
1089 if (this.blockData.length < this.blockDataBytes)
1090 this.blockData = new byte[this.blockDataBytes];
1091
1092 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1093 this.blockDataPosition = 0;
1094 }
1095
1096
1097 private void readArrayElements (Object array, Class clazz)
1098 throws ClassNotFoundException, IOException
1099 {
1100 if (clazz.isPrimitive ())
1101 {
1102 if (clazz == Boolean.TYPE)
1103 {
1104 boolean[] cast_array = (boolean[])array;
1105 for (int i=0; i < cast_array.length; i++)
1106 cast_array[i] = this.realInputStream.readBoolean ();
1107 return;
1108 }
1109 if (clazz == Byte.TYPE)
1110 {
1111 byte[] cast_array = (byte[])array;
1112 for (int i=0; i < cast_array.length; i++)
1113 cast_array[i] = this.realInputStream.readByte ();
1114 return;
1115 }
1116 if (clazz == Character.TYPE)
1117 {
1118 char[] cast_array = (char[])array;
1119 for (int i=0; i < cast_array.length; i++)
1120 cast_array[i] = this.realInputStream.readChar ();
1121 return;
1122 }
1123 if (clazz == Double.TYPE)
1124 {
1125 double[] cast_array = (double[])array;
1126 for (int i=0; i < cast_array.length; i++)
1127 cast_array[i] = this.realInputStream.readDouble ();
1128 return;
1129 }
1130 if (clazz == Float.TYPE)
1131 {
1132 float[] cast_array = (float[])array;
1133 for (int i=0; i < cast_array.length; i++)
1134 cast_array[i] = this.realInputStream.readFloat ();
1135 return;
1136 }
1137 if (clazz == Integer.TYPE)
1138 {
1139 int[] cast_array = (int[])array;
1140 for (int i=0; i < cast_array.length; i++)
1141 cast_array[i] = this.realInputStream.readInt ();
1142 return;
1143 }
1144 if (clazz == Long.TYPE)
1145 {
1146 long[] cast_array = (long[])array;
1147 for (int i=0; i < cast_array.length; i++)
1148 cast_array[i] = this.realInputStream.readLong ();
1149 return;
1150 }
1151 if (clazz == Short.TYPE)
1152 {
1153 short[] cast_array = (short[])array;
1154 for (int i=0; i < cast_array.length; i++)
1155 cast_array[i] = this.realInputStream.readShort ();
1156 return;
1157 }
1158 }
1159 else
1160 {
1161 Object[] cast_array = (Object[])array;
1162 for (int i=0; i < cast_array.length; i++)
1163 cast_array[i] = readObject ();
1164 }
1165 }
1166
1167
1168 private void readFields (Object obj, ObjectStreamField[] stream_fields,
1169 boolean call_read_method,
1170 ObjectStreamClass stream_osc)
1171 throws ClassNotFoundException, IOException
1172 {
1173 // DEBUGln ("In readFields");
1174 if (call_read_method)
1175 {
1176 // DEBUGln (" call_read_method is true");
1177 fieldsAlreadyRead = false;
1178 setBlockDataMode (true);
1179 callReadMethod (obj, stream_osc.forClass ());
1180 setBlockDataMode (false);
1181 return;
1182 }
1183
1184 ObjectStreamField[] real_fields =
1185 ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
1186
1187 boolean default_initialize, set_value;
1188 String field_name = null;
1189 Class type = null;
1190 ObjectStreamField stream_field = null;
1191 ObjectStreamField real_field = null;
1192 int stream_idx = 0;
1193 int real_idx = 0;
1194
1195 while (stream_idx < stream_fields.length
1196 && real_idx < real_fields.length)
1197 {
1198 default_initialize = false;
1199 set_value = true;
1200
1201 if (stream_idx == stream_fields.length)
1202 default_initialize = true;
1203 else
1204 {
1205 stream_field = stream_fields[stream_idx];
1206 type = stream_field.getType ();
1207 }
1208
1209 if (real_idx == real_fields.length)
1210 set_value = false;
1211 else
1212 {
1213 real_field = real_fields[real_idx];
1214 type = real_field.getType ();
1215 field_name = real_field.getName ();
1216 }
1217
1218 if (set_value && !default_initialize)
1219 {
1220 int comp_val =
1221 real_field.compareTo (stream_field);
1222
1223 if (comp_val < 0)
1224 {
1225 default_initialize = true;
1226 real_idx++;
1227 }
1228 else if (comp_val > 0)
1229 {
1230 set_value = false;
1231 stream_idx++;
1232 }
1233 else
1234 {
1235 real_idx++;
1236 stream_idx++;
1237 }
1238 }
1239
1240 if (type == Boolean.TYPE)
1241 {
1242 boolean value =
1243 default_initialize ? false : this.realInputStream.readBoolean ();
1244 if (!default_initialize && set_value)
1245 dumpElementln (" " + field_name + ": " + value);
1246 if (set_value)
1247 setBooleanField (obj, field_name, value);
1248 }
1249 else if (type == Byte.TYPE)
1250 {
1251 byte value =
1252 default_initialize ? 0 : this.realInputStream.readByte ();
1253 if (!default_initialize && set_value)
1254 dumpElementln (" " + field_name + ": " + value);
1255 if (set_value)
1256 setByteField (obj, field_name, value);
1257 }
1258 else if (type == Character.TYPE)
1259 {
1260 char value =
1261 default_initialize ? (char)0 : this.realInputStream.readChar ();
1262 if (!default_initialize && set_value)
1263 dumpElementln (" " + field_name + ": " + value);
1264 if (set_value)
1265 setCharField (obj, field_name, value);
1266 }
1267 else if (type == Double.TYPE)
1268 {
1269 double value =
1270 default_initialize ? 0 : this.realInputStream.readDouble ();
1271 if (!default_initialize && set_value)
1272 dumpElementln (" " + field_name + ": " + value);
1273 if (set_value)
1274 setDoubleField (obj, field_name, value);
1275 }
1276 else if (type == Float.TYPE)
1277 {
1278 float value =
1279 default_initialize ? 0 : this.realInputStream.readFloat ();
1280 if (!default_initialize && set_value)
1281 dumpElementln (" " + field_name + ": " + value);
1282 if (set_value)
1283 setFloatField (obj, field_name, value);
1284 }
1285 else if (type == Integer.TYPE)
1286 {
1287 int value =
1288 default_initialize ? 0 : this.realInputStream.readInt ();
1289 if (!default_initialize && set_value)
1290 dumpElementln (" " + field_name + ": " + value);
1291 if (set_value)
1292 setIntField (obj, field_name, value);
1293 }
1294 else if (type == Long.TYPE)
1295 {
1296 long value =
1297 default_initialize ? 0 : this.realInputStream.readLong ();
1298 if (!default_initialize && set_value)
1299 dumpElementln (" " + field_name + ": " + value);
1300 if (set_value)
1301 setLongField (obj, field_name, value);
1302 }
1303 else if (type == Short.TYPE)
1304 {
1305 short value =
1306 default_initialize ? (short)0 : this.realInputStream.readShort ();
1307 if (!default_initialize && set_value)
1308 dumpElementln (" " + field_name + ": " + value);
1309 if (set_value)
1310 setShortField (obj, field_name, value);
1311 }
1312 else
1313 {
1314 Object value =
1315 default_initialize ? null : readObject ();
1316 if (set_value)
1317 setObjectField (obj, field_name,
1318 real_field.getTypeString (), value);
1319 }
1320 }
1321 }
1322
1323
1324 // Toggles writing primitive data to block-data buffer.
1325 private void setBlockDataMode (boolean on)
1326 {
1327 // DEBUGln ("Setting block data mode to " + on);
1328
1329 this.readDataFromBlock = on;
1330
1331 if (on)
1332 this.dataInputStream = this.blockDataInput;
1333 else
1334 this.dataInputStream = this.realInputStream;
1335 }
1336
1337
1338 // returns a new instance of REAL_CLASS that has been constructed
1339 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1340 private Object newObject (Class real_class, Class constructor_class)
1341 {
1342 try
1343 {
1344 Object obj = allocateObject (real_class);
1345 callConstructor (constructor_class, obj);
1346 return obj;
1347 }
1348 catch (InstantiationException e)
1349 {
1350 return null;
1351 }
1352 }
1353
1354
1355 // runs all registered ObjectInputValidations in prioritized order
1356 // on OBJ
1357 private void invokeValidators () throws InvalidObjectException
1358 {
1359 Object[] validators = new Object[this.validators.size ()];
1360 this.validators.copyInto (validators);
1361 Arrays.sort (validators);
1362
1363 try
1364 {
1365 for (int i=0; i < validators.length; i++)
1366 ((ObjectInputValidation)validators[i]).validateObject ();
1367 }
1368 finally
1369 {
1370 this.validators.removeAllElements ();
1371 }
1372 }
1373
1374
1375 // this native method is used to get access to the protected method
1376 // of the same name in SecurityManger
1377 private static ClassLoader currentClassLoader (SecurityManager sm)
1378 {
1379 // FIXME: This is too simple.
1380 return ClassLoader.getSystemClassLoader ();
1381 }
1382
1383 private static native Field getField (Class klass, String name)
1384 throws java.lang.NoSuchFieldException;
1385
1386 private static native Method getMethod (Class klass, String name, Class args[])
1387 throws java.lang.NoSuchMethodException;
1388
1389 private void callReadMethod (Object obj, Class klass) throws IOException
1390 {
1391 try
1392 {
1393 Class classArgs[] = {ObjectInputStream.class};
1394 Method m = getMethod (klass, "readObject", classArgs);
1395 if (m == null)
1396 return;
1397 Object args[] = {this};
1398 m.invoke (obj, args);
1399 }
1400 catch (InvocationTargetException x)
1401 {
1402 /* Rethrow if possible. */
1403 Throwable exception = x.getTargetException();
1404 if (exception instanceof RuntimeException)
1405 throw (RuntimeException) exception;
1406 if (exception instanceof IOException)
1407 throw (IOException) exception;
1408
1409 throw new IOException ("Exception thrown from readObject() on " +
1410 klass + ": " + exception.getClass().getName());
1411 }
1412 catch (Exception x)
1413 {
1414 throw new IOException ("Failure invoking readObject() on " +
1415 klass + ": " + x.getClass().getName());
1416 }
1417 }
1418
1419 private native Object allocateObject (Class clazz)
1420 throws InstantiationException;
1421
1422 private native void callConstructor (Class clazz, Object obj);
1423
1424 private void setBooleanField (Object obj, String field_name,
1425 boolean val)
1426 {
1427 try
1428 {
1429 Class klass = obj.getClass ();
1430 Field f = getField (klass, field_name);
1431 f.setAccessible(true);
1432 f.setBoolean (obj, val);
1433 }
1434 catch (Exception _)
1435 {
1436 }
1437 }
1438
1439 private void setByteField (Object obj, String field_name,
1440 byte val)
1441 {
1442 try
1443 {
1444 Class klass = obj.getClass ();
1445 Field f = getField (klass, field_name);
1446 f.setAccessible(true);
1447 f.setByte (obj, val);
1448 }
1449 catch (Exception _)
1450 {
1451 }
1452 }
1453
1454 private void setCharField (Object obj, String field_name,
1455 char val)
1456 {
1457 try
1458 {
1459 Class klass = obj.getClass ();
1460 Field f = getField (klass, field_name);
1461 f.setAccessible(true);
1462 f.setChar (obj, val);
1463 }
1464 catch (Exception _)
1465 {
1466 }
1467 }
1468
1469 private void setDoubleField (Object obj, String field_name,
1470 double val)
1471 {
1472 try
1473 {
1474 Class klass = obj.getClass ();
1475 Field f = getField (klass, field_name);
1476 f.setAccessible(true);
1477 f.setDouble (obj, val);
1478 }
1479 catch (Exception _)
1480 {
1481 }
1482 }
1483
1484 private void setFloatField (Object obj, String field_name,
1485 float val)
1486 {
1487 try
1488 {
1489 Class klass = obj.getClass ();
1490 Field f = getField (klass, field_name);
1491 f.setAccessible(true);
1492 f.setFloat (obj, val);
1493 }
1494 catch (Exception _)
1495 {
1496 }
1497 }
1498
1499 private void setIntField (Object obj, String field_name,
1500 int val)
1501 {
1502 try
1503 {
1504 Class klass = obj.getClass ();
1505 Field f = getField (klass, field_name);
1506 f.setAccessible(true);
1507 f.setInt (obj, val);
1508 }
1509 catch (Exception _)
1510 {
1511 }
1512 }
1513
1514
1515 private void setLongField (Object obj, String field_name,
1516 long val)
1517 {
1518 try
1519 {
1520 Class klass = obj.getClass ();
1521 Field f = getField (klass, field_name);
1522 f.setAccessible(true);
1523 f.setLong (obj, val);
1524 }
1525 catch (Exception _)
1526 {
1527 }
1528 }
1529
1530
1531 private void setShortField (Object obj, String field_name,
1532 short val)
1533 {
1534 try
1535 {
1536 Class klass = obj.getClass ();
1537 Field f = getField (klass, field_name);
1538 f.setAccessible(true);
1539 f.setShort (obj, val);
1540 }
1541 catch (Exception _)
1542 {
1543 }
1544 }
1545
1546
1547 private void setObjectField (Object obj, String field_name, String type_code,
1548 Object val)
1549 {
1550 try
1551 {
1552 Class klass = obj.getClass ();
1553 Field f = getField (klass, field_name);
1554 f.setAccessible(true);
1555 // FIXME: We should check the type_code here
1556 f.set (obj, val);
1557 }
1558 catch (Exception _)
1559 {
1560 }
1561 }
1562
1563 private static final int BUFFER_SIZE = 1024;
1564 private static final Class[] readObjectParams = { ObjectInputStream.class };
1565
1566 private DataInputStream realInputStream;
1567 private DataInputStream dataInputStream;
1568 private DataInputStream blockDataInput;
1569 private int blockDataPosition;
1570 private int blockDataBytes;
1571 private byte[] blockData;
1572 private boolean useSubclassMethod;
1573 private int nextOID;
1574 private boolean resolveEnabled;
1575 private Hashtable objectLookupTable;
1576 private Object currentObject;
1577 private ObjectStreamClass currentObjectStreamClass;
1578 private boolean readDataFromBlock;
1579 private boolean isDeserializing;
1580 private boolean fieldsAlreadyRead;
1581 private Vector validators;
1582
1583 private static boolean dump;
1584
1585 private void dumpElement (String msg)
1586 {
1587 if (Configuration.DEBUG && dump)
1588 System.out.print(msg);
1589 }
1590
1591 private void dumpElementln (String msg)
1592 {
1593 if (Configuration.DEBUG && dump)
1594 System.out.println(msg);
1595 }
1596 }
1597
1598
1599 // used to keep a prioritized list of object validators
1600 class ValidatorAndPriority implements Comparable
1601 {
1602 int priority;
1603 ObjectInputValidation validator;
1604
1605 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1606 {
1607 this.priority = priority;
1608 this.validator = validator;
1609 }
1610
1611 public int compareTo (Object o)
1612 {
1613 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1614 return this.priority - vap.priority;
1615 }
1616 }
This page took 0.097267 seconds and 5 git commands to generate.