Source for java.io.ObjectInputStream

   1: /* ObjectInputStream.java -- Class used to read serialized objects
   2:    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008
   3:    Free Software Foundation, Inc.
   4: 
   5: This file is part of GNU Classpath.
   6: 
   7: GNU Classpath is free software; you can redistribute it and/or modify
   8: it under the terms of the GNU General Public License as published by
   9: the Free Software Foundation; either version 2, or (at your option)
  10: any later version.
  11: 
  12: GNU Classpath is distributed in the hope that it will be useful, but
  13: WITHOUT ANY WARRANTY; without even the implied warranty of
  14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15: General Public License for more details.
  16: 
  17: You should have received a copy of the GNU General Public License
  18: along with GNU Classpath; see the file COPYING.  If not, write to the
  19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20: 02110-1301 USA.
  21: 
  22: Linking this library statically or dynamically with other modules is
  23: making a combined work based on this library.  Thus, the terms and
  24: conditions of the GNU General Public License cover the whole
  25: combination.
  26: 
  27: As a special exception, the copyright holders of this library give you
  28: permission to link this library with independent modules to produce an
  29: executable, regardless of the license terms of these independent
  30: modules, and to copy and distribute the resulting executable under
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: 
  40: package java.io;
  41: 
  42: import gnu.classpath.Pair;
  43: import gnu.classpath.VMStackWalker;
  44: 
  45: import java.lang.reflect.Array;
  46: import java.lang.reflect.Constructor;
  47: import java.lang.reflect.Field;
  48: import java.lang.reflect.InvocationTargetException;
  49: import java.lang.reflect.Method;
  50: import java.lang.reflect.Modifier;
  51: import java.lang.reflect.Proxy;
  52: import java.security.AccessController;
  53: import java.security.PrivilegedAction;
  54: import java.util.HashMap;
  55: import java.util.Hashtable;
  56: import java.util.Iterator;
  57: import java.util.Map;
  58: import java.util.TreeSet;
  59: 
  60: /**
  61:  * @author Tom Tromey (tromey@redhat.com)
  62:  * @author Jeroen Frijters (jeroen@frijters.net)
  63:  * @author Guilhem Lavaux (guilhem@kaffe.org)
  64:  * @author Michael Koch (konqueror@gmx.de)
  65:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  66:  */
  67: public class ObjectInputStream extends InputStream
  68:   implements ObjectInput, ObjectStreamConstants
  69: {
  70:   /**
  71:    * Creates a new <code>ObjectInputStream</code> that will do all of
  72:    * its reading from <code>in</code>.  This method also checks
  73:    * the stream by reading the header information (stream magic number
  74:    * and stream version).
  75:    *
  76:    * @exception IOException Reading stream header from underlying
  77:    * stream cannot be completed.
  78:    *
  79:    * @exception StreamCorruptedException An invalid stream magic
  80:    * number or stream version was read from the stream.
  81:    *
  82:    * @see #readStreamHeader()
  83:    */
  84:   public ObjectInputStream(InputStream in)
  85:     throws IOException, StreamCorruptedException
  86:   {
  87:     if (DEBUG)
  88:       {
  89:     String val = System.getProperty("gcj.dumpobjects");
  90:     if (dump == false && val != null && !val.equals(""))
  91:       {
  92:         dump = true;
  93:         System.out.println ("Serialization debugging enabled");
  94:       }
  95:     else if (dump == true && (val == null || val.equals("")))
  96:       {
  97:         dump = false;
  98:         System.out.println ("Serialization debugging disabled");
  99:       }
 100:       }
 101: 
 102:     this.resolveEnabled = false;
 103:     this.blockDataPosition = 0;
 104:     this.blockDataBytes = 0;
 105:     this.blockData = new byte[BUFFER_SIZE];
 106:     this.blockDataInput = new DataInputStream(this);
 107:     this.realInputStream = new DataInputStream(in);
 108:     this.nextOID = baseWireHandle;
 109:     handles = new HashMap<Integer,Pair<Boolean,Object>>();
 110:     this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
 111:     setBlockDataMode(true);
 112:     readStreamHeader();
 113:   }
 114: 
 115: 
 116:   /**
 117:    * Returns the next deserialized object read from the underlying stream.
 118:    *
 119:    * This method can be overriden by a class by implementing
 120:    * <code>private void readObject (ObjectInputStream)</code>.
 121:    *
 122:    * If an exception is thrown from this method, the stream is left in
 123:    * an undefined state. This method can also throw Errors and 
 124:    * RuntimeExceptions if caused by existing readResolve() user code.
 125:    * 
 126:    * @return The object read from the underlying stream.
 127:    *
 128:    * @exception ClassNotFoundException The class that an object being
 129:    * read in belongs to cannot be found.
 130:    *
 131:    * @exception IOException Exception from underlying
 132:    * <code>InputStream</code>.
 133:    */
 134:   public final Object readObject()
 135:     throws ClassNotFoundException, IOException
 136:   {
 137:     return readObject(true);
 138:   }
 139: 
 140:   /**
 141:    * <p>
 142:    * Returns the next deserialized object read from the
 143:    * underlying stream in an unshared manner.  Any object
 144:    * returned by this method will not be returned by
 145:    * subsequent calls to either this method or {@link #readObject()}.
 146:    * </p>
 147:    * <p>
 148:    * This behaviour is achieved by:
 149:    * </p>
 150:    * <ul>
 151:    * <li>Marking the handles created by successful calls to this
 152:    * method, so that future calls to {@link #readObject()} or
 153:    * {@link #readUnshared()} will throw an {@link ObjectStreamException}
 154:    * rather than returning the same object reference.</li>
 155:    * <li>Throwing an {@link ObjectStreamException} if the next
 156:    * element in the stream is a reference to an earlier object.</li>
 157:    * </ul>
 158:    *
 159:    * @return a reference to the deserialized object.
 160:    * @throws ClassNotFoundException if the class of the object being
 161:    *                                deserialized can not be found.
 162:    * @throws StreamCorruptedException if information in the stream
 163:    *                                  is inconsistent.
 164:    * @throws ObjectStreamException if the next object has already been
 165:    *                               returned by an earlier call to this
 166:    *                               method or {@link #readObject()}.
 167:    * @throws OptionalDataException if primitive data occurs next in the stream.
 168:    * @throws IOException if an I/O error occurs from the stream.
 169:    * @since 1.4
 170:    * @see #readObject()
 171:    */
 172:   public Object readUnshared()
 173:     throws IOException, ClassNotFoundException
 174:   {
 175:     return readObject(false);
 176:   }
 177: 
 178:   /**
 179:    * Returns the next deserialized object read from the underlying stream.
 180:    *
 181:    * This method can be overriden by a class by implementing
 182:    * <code>private void readObject (ObjectInputStream)</code>.
 183:    *
 184:    * If an exception is thrown from this method, the stream is left in
 185:    * an undefined state. This method can also throw Errors and 
 186:    * RuntimeExceptions if caused by existing readResolve() user code.
 187:    * 
 188:    * @param shared true if handles created by this call should be shared
 189:    *               with later calls.
 190:    * @return The object read from the underlying stream.
 191:    *
 192:    * @exception ClassNotFoundException The class that an object being
 193:    * read in belongs to cannot be found.
 194:    *
 195:    * @exception IOException Exception from underlying
 196:    * <code>InputStream</code>.
 197:    */
 198:   private final Object readObject(boolean shared)
 199:     throws ClassNotFoundException, IOException
 200:   {
 201:     if (this.useSubclassMethod)
 202:       return readObjectOverride();
 203: 
 204:     Object ret_val;
 205:     boolean old_mode = setBlockDataMode(false);
 206:     byte marker = this.realInputStream.readByte();
 207: 
 208:     if (DEBUG)
 209:       depth += 2;
 210: 
 211:     if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
 212: 
 213:     try
 214:       {
 215:      ret_val = parseContent(marker, shared);
 216:       }
 217:     finally
 218:       {
 219:      setBlockDataMode(old_mode);
 220:      if (DEBUG)
 221:       depth -= 2;
 222:       }
 223:     
 224:     return ret_val;
 225:   }
 226: 
 227:    /**
 228:     * Handles a content block within the stream, which begins with a marker
 229:     * byte indicating its type.
 230:     *
 231:     * @param marker the byte marker.
 232:     * @param shared true if handles created by this call should be shared
 233:     *               with later calls.
 234:     * @return an object which represents the parsed content.
 235:     * @throws ClassNotFoundException if the class of an object being
 236:     *                                read in cannot be found.
 237:     * @throws IOException if invalid data occurs or one is thrown by the
 238:     *                     underlying <code>InputStream</code>.
 239:     */
 240:    private Object parseContent(byte marker, boolean shared)
 241:      throws ClassNotFoundException, IOException
 242:    {
 243:      Object ret_val;
 244:      boolean is_consumed = false;
 245: 
 246:      switch (marker)
 247:        {
 248:        case TC_ENDBLOCKDATA:
 249:      {
 250:        ret_val = null;
 251:        is_consumed = true;
 252:        break;
 253:      }
 254:      
 255:        case TC_BLOCKDATA:
 256:        case TC_BLOCKDATALONG:
 257:      {
 258:        if (marker == TC_BLOCKDATALONG)
 259:          { if(dump) dumpElementln("BLOCKDATALONG"); }
 260:        else
 261:          { if(dump) dumpElementln("BLOCKDATA"); }
 262:        readNextBlock(marker);
 263:      }
 264:      
 265:        case TC_NULL:
 266:      {
 267:        if(dump) dumpElementln("NULL");
 268:        ret_val = null;
 269:        break;
 270:      }
 271:      
 272:        case TC_REFERENCE:
 273:      {
 274:        if(dump) dumpElement("REFERENCE ");
 275:        int oid = realInputStream.readInt();
 276:        if(dump) dumpElementln(Integer.toHexString(oid));
 277:        ret_val = lookupHandle(oid);
 278:       if (!shared)
 279:         throw new
 280:           InvalidObjectException("References can not be read unshared.");
 281:        break;
 282:      }
 283:      
 284:        case TC_CLASS:
 285:      {
 286:        if(dump) dumpElementln("CLASS");
 287:        ObjectStreamClass osc = (ObjectStreamClass)readObject();
 288:        Class clazz = osc.forClass();
 289:        assignNewHandle(clazz,shared);
 290:        ret_val = clazz;
 291:        break;
 292:      }
 293:      
 294:        case TC_PROXYCLASSDESC:
 295:      {
 296:        if(dump) dumpElementln("PROXYCLASS");
 297: 
 298: /* GCJ LOCAL */
 299:       // The grammar at this point is
 300:       //   TC_PROXYCLASSDESC newHandle proxyClassDescInfo
 301:       // i.e. we have to assign the handle immediately after
 302:       // reading the marker.
 303:        int handle = assignNewHandle("Dummy proxy",shared);
 304: /* END GCJ LOCAL */
 305: 
 306:        int n_intf = this.realInputStream.readInt();
 307:        String[] intfs = new String[n_intf];
 308:        for (int i = 0; i < n_intf; i++)
 309:          {
 310:            intfs[i] = this.realInputStream.readUTF();
 311:          }
 312:        
 313:        boolean oldmode = setBlockDataMode(true);
 314:        Class cl = resolveProxyClass(intfs);
 315:        setBlockDataMode(oldmode);
 316:        
 317:        ObjectStreamClass osc = lookupClass(cl);
 318:           if (osc.firstNonSerializableParentConstructor == null)
 319:             {
 320:               osc.realClassIsSerializable = true;
 321:               osc.fields = osc.fieldMapping = new ObjectStreamField[0];
 322:               try
 323:                 {
 324:                   osc.firstNonSerializableParentConstructor =
 325:                     Object.class.getConstructor(new Class[0]);
 326:                 }
 327:               catch (NoSuchMethodException x)
 328:                 {
 329:                   throw (InternalError)
 330:                     new InternalError("Object ctor missing").initCause(x);
 331:                 }
 332:             }
 333: /* GCJ LOCAL */
 334:       rememberHandle(osc,shared,handle);
 335: /* END GCJ LOCAL */
 336:        
 337:        if (!is_consumed)
 338:          {
 339:            byte b = this.realInputStream.readByte();
 340:            if (b != TC_ENDBLOCKDATA)
 341:          throw new IOException("Data annotated to class was not consumed." + b);
 342:          }
 343:        else
 344:          is_consumed = false;
 345:        ObjectStreamClass superosc = (ObjectStreamClass)readObject();
 346:        osc.setSuperclass(superosc);
 347:        ret_val = osc;
 348:        break;
 349:      }
 350:      
 351:        case TC_CLASSDESC:
 352:      {
 353:        ObjectStreamClass osc = readClassDescriptor();
 354:        
 355:        if (!is_consumed)
 356:          {
 357:            byte b = this.realInputStream.readByte();
 358:            if (b != TC_ENDBLOCKDATA)
 359:          throw new IOException("Data annotated to class was not consumed." + b);
 360:          }
 361:        else
 362:          is_consumed = false;
 363:        
 364:        osc.setSuperclass ((ObjectStreamClass)readObject());
 365:        ret_val = osc;
 366:        break;
 367:      }
 368:      
 369:        case TC_STRING:
 370:      {
 371:        if(dump) dumpElement("STRING=");
 372:        String s = this.realInputStream.readUTF();
 373:        if(dump) dumpElementln(s);
 374:        ret_val = processResolution(null, s, assignNewHandle(s,shared),
 375:                       shared);
 376:        break;
 377:      }
 378:  
 379:        case TC_LONGSTRING:
 380:      {
 381:        if(dump) dumpElement("STRING=");
 382:        String s = this.realInputStream.readUTFLong();
 383:        if(dump) dumpElementln(s);
 384:        ret_val = processResolution(null, s, assignNewHandle(s,shared),
 385:                       shared);
 386:        break;
 387:      }
 388: 
 389:        case TC_ARRAY:
 390:      {
 391:        if(dump) dumpElementln("ARRAY");
 392:        ObjectStreamClass osc = (ObjectStreamClass)readObject();
 393:        Class componentType = osc.forClass().getComponentType();
 394:        if(dump) dumpElement("ARRAY LENGTH=");
 395:        int length = this.realInputStream.readInt();
 396:        if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
 397:        Object array = Array.newInstance(componentType, length);
 398:        int handle = assignNewHandle(array,shared);
 399:        readArrayElements(array, componentType);
 400:        if(dump)
 401:          for (int i = 0, len = Array.getLength(array); i < len; i++)
 402:            dumpElementln("  ELEMENT[" + i + "]=", Array.get(array, i));
 403:        ret_val = processResolution(null, array, handle, shared);
 404:        break;
 405:      }
 406:      
 407:        case TC_OBJECT:
 408:      {
 409:        if(dump) dumpElementln("OBJECT");
 410:        ObjectStreamClass osc = (ObjectStreamClass)readObject();
 411:        Class clazz = osc.forClass();
 412:        
 413:        if (!osc.realClassIsSerializable)
 414:          throw new NotSerializableException
 415:            (clazz + " is not Serializable, and thus cannot be deserialized.");
 416:        
 417:        if (osc.realClassIsExternalizable)
 418:         {
 419:            Externalizable obj = osc.newInstance();
 420:           
 421:            int handle = assignNewHandle(obj,shared);
 422:           
 423:            boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
 424:           
 425:            boolean oldmode = this.readDataFromBlock;
 426:            if (read_from_blocks)
 427:          setBlockDataMode(true);
 428:           
 429:            obj.readExternal(this);
 430:            
 431:            if (read_from_blocks)
 432:                 {
 433:            setBlockDataMode(oldmode);
 434:            if (!oldmode)
 435:              if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
 436:                throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
 437:         }
 438: 
 439:            ret_val = processResolution(osc, obj, handle,shared);
 440:               break;
 441:           
 442:          } // end if (osc.realClassIsExternalizable)
 443:        
 444:        Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
 445:        
 446:        int handle = assignNewHandle(obj,shared);
 447:        Object prevObject = this.currentObject;
 448:        ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
 449:       TreeSet<ValidatorAndPriority> prevObjectValidators =
 450:         this.currentObjectValidators;
 451:        
 452:        this.currentObject = obj;
 453:       this.currentObjectValidators = null;
 454:        ObjectStreamClass[] hierarchy = hierarchy(clazz);
 455:        
 456:        for (int i = 0; i < hierarchy.length; i++)      
 457:           {
 458:            this.currentObjectStreamClass = hierarchy[i];
 459:            if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
 460:             
 461:            // XXX: should initialize fields in classes in the hierarchy
 462:            // that aren't in the stream
 463:            // should skip over classes in the stream that aren't in the
 464:            // real classes hierarchy
 465:             
 466:            Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
 467:            if (readObjectMethod != null)
 468:          {
 469:            fieldsAlreadyRead = false;
 470:            boolean oldmode = setBlockDataMode(true);
 471:            callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
 472:            setBlockDataMode(oldmode);
 473:          }
 474:            else
 475:          {
 476:            readFields(obj, currentObjectStreamClass);
 477:          }
 478:             
 479:            if (this.currentObjectStreamClass.hasWriteMethod())
 480:           {
 481:            if(dump) dumpElement("ENDBLOCKDATA? ");
 482:            try
 483:               {
 484:                /* Read blocks until an end marker */
 485:                byte writeMarker = this.realInputStream.readByte();
 486:                while (writeMarker != TC_ENDBLOCKDATA)
 487:             {    
 488:                parseContent(writeMarker, shared);
 489:                writeMarker = this.realInputStream.readByte();
 490:             }
 491:                if(dump) dumpElementln("yes");
 492:              }
 493:            catch (EOFException e)
 494:              {
 495:                throw (IOException) new IOException
 496:              ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
 497:             }
 498:         }
 499:         }
 500:        
 501:        this.currentObject = prevObject;
 502:        this.currentObjectStreamClass = prevObjectStreamClass;
 503:        ret_val = processResolution(osc, obj, handle, shared);
 504:       if (currentObjectValidators != null)
 505:         invokeValidators();
 506:       this.currentObjectValidators = prevObjectValidators;
 507: 
 508:        break;
 509:      }
 510:     
 511:        case TC_RESET:
 512:      if(dump) dumpElementln("RESET");
 513:      clearHandles();
 514:      ret_val = readObject();
 515:      break;
 516:     
 517:        case TC_EXCEPTION:
 518:      {
 519:        if(dump) dumpElement("EXCEPTION=");
 520:        Exception e = (Exception)readObject();
 521:        if(dump) dumpElementln(e.toString());
 522:        clearHandles();
 523:        throw new WriteAbortedException("Exception thrown during writing of stream", e);
 524:      }
 525: 
 526:        case TC_ENUM:
 527:      {
 528:        /* TC_ENUM classDesc newHandle enumConstantName */
 529:        if (dump)
 530:          dumpElementln("ENUM=");
 531:        ObjectStreamClass osc = (ObjectStreamClass) readObject();
 532:        String constantName = (String) readObject();
 533:        if (dump)
 534:          dumpElementln("CONSTANT NAME = " + constantName);
 535:        Class clazz = osc.forClass();
 536:        Enum instance = Enum.valueOf(clazz, constantName);
 537:        assignNewHandle(instance,shared);
 538:        ret_val = instance;
 539:        break;
 540:      }
 541: 
 542:        default:
 543:      throw new IOException("Unknown marker on stream: " + marker);
 544:       }
 545:     return ret_val;
 546:   }
 547: 
 548:   /**
 549:    * This method makes a partial check of types for the fields
 550:    * contained given in arguments. It checks primitive types of
 551:    * fields1 against non primitive types of fields2. This method 
 552:    * assumes the two lists has already been sorted according to 
 553:    * the Java specification.
 554:    *
 555:    * @param name Name of the class owning the given fields.
 556:    * @param fields1 First list to check.
 557:    * @param fields2 Second list to check.
 558:    * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
 559:    * in the non primitive part in fields2.
 560:    */
 561:   private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
 562:     throws InvalidClassException
 563:   {
 564:     int nonPrimitive = 0;
 565:     
 566:     for (nonPrimitive = 0; 
 567:      nonPrimitive < fields1.length
 568:        && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
 569:       {
 570:       }
 571: 
 572:     if (nonPrimitive == fields1.length)
 573:       return;
 574:     
 575:     int i = 0;
 576:     ObjectStreamField f1;
 577:     ObjectStreamField f2;
 578:     
 579:     while (i < fields2.length
 580:        && nonPrimitive < fields1.length)
 581:       {
 582:     f1 = fields1[nonPrimitive];
 583:     f2 = fields2[i];
 584:     
 585:     if (!f2.isPrimitive())
 586:       break;
 587: 
 588:     int compVal = f1.getName().compareTo (f2.getName());
 589: 
 590:     if (compVal < 0)
 591:       {
 592:         nonPrimitive++;
 593:       }
 594:     else if (compVal > 0)
 595:       {
 596:         i++;
 597:       }
 598:     else
 599:       {
 600:         throw new InvalidClassException
 601:           ("invalid field type for " + f2.getName() +
 602:            " in class " + name);
 603:       }
 604:       }
 605:   }
 606: 
 607:   /**
 608:    * This method reads a class descriptor from the real input stream
 609:    * and use these data to create a new instance of ObjectStreamClass.
 610:    * Fields are sorted and ordered for the real read which occurs for
 611:    * each instance of the described class. Be aware that if you call that
 612:    * method you must ensure that the stream is synchronized, in the other
 613:    * case it may be completely desynchronized.
 614:    *
 615:    * @return A new instance of ObjectStreamClass containing the freshly
 616:    * created descriptor.
 617:    * @throws ClassNotFoundException if the required class to build the
 618:    * descriptor has not been found in the system.
 619:    * @throws IOException An input/output error occured.
 620:    * @throws InvalidClassException If there was a compatibility problem
 621:    * between the class present in the system and the serialized class.
 622:    */
 623:   protected ObjectStreamClass readClassDescriptor()
 624:     throws ClassNotFoundException, IOException
 625:   {
 626:     if(dump) dumpElement("CLASSDESC NAME=");
 627:     String name = this.realInputStream.readUTF();
 628:     if(dump) dumpElement(name + "; UID=");
 629:     long uid = this.realInputStream.readLong ();
 630:     if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
 631:     byte flags = this.realInputStream.readByte ();
 632:     if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
 633:     short field_count = this.realInputStream.readShort();
 634:     if(dump) dumpElementln(Short.toString(field_count));
 635:     ObjectStreamField[] fields = new ObjectStreamField[field_count];
 636:     ObjectStreamClass osc = new ObjectStreamClass(name, uid,
 637:                           flags, fields);
 638:     assignNewHandle(osc,true);
 639: 
 640:     for (int i = 0; i < field_count; i++)
 641:       {
 642:     if(dump) dumpElement("  TYPE CODE=");
 643:     char type_code = (char)this.realInputStream.readByte();
 644:     if(dump) dumpElement(type_code + "; FIELD NAME=");
 645:     String field_name = this.realInputStream.readUTF();
 646:     if(dump) dumpElementln(field_name);
 647:     String class_name;
 648:           
 649:     // If the type code is an array or an object we must
 650:     // decode a String here. In the other case we convert
 651:     // the type code and pass it to ObjectStreamField.
 652:     // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
 653:     if (type_code == 'L' || type_code == '[')
 654:       class_name = (String)readObject();
 655:     else
 656:       class_name = String.valueOf(type_code);
 657:           
 658:     fields[i] =
 659:       new ObjectStreamField(field_name, class_name);
 660:       }
 661:           
 662:     /* Now that fields have been read we may resolve the class
 663:      * (and read annotation if needed). */
 664:     Class clazz = resolveClass(osc);
 665:     ClassLoader loader = clazz.getClassLoader();
 666:     for (int i = 0; i < field_count; i++)
 667:       {
 668:         fields[i].resolveType(loader);
 669:       }
 670:     boolean oldmode = setBlockDataMode(true);
 671:     osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
 672:     classLookupTable.put(clazz, osc);
 673:     setBlockDataMode(oldmode);
 674: 
 675:     // find the first non-serializable class in clazz's inheritance hierarchy
 676:     Class first_nonserial = clazz.getSuperclass();
 677:     // Maybe it is a primitive class, those don't have a super class,
 678:     // or Object itself.  Otherwise we can keep getting the superclass
 679:     // till we hit the Object class, or some other non-serializable class.
 680: 
 681:     if (first_nonserial == null)
 682:       first_nonserial = clazz;
 683:     else
 684:       while (Serializable.class.isAssignableFrom(first_nonserial))
 685:         first_nonserial = first_nonserial.getSuperclass();
 686: 
 687:     final Class local_constructor_class = first_nonserial;
 688: 
 689:     osc.firstNonSerializableParentConstructor =
 690:         (Constructor)AccessController.doPrivileged(new PrivilegedAction()
 691:           {
 692:             public Object run()
 693:             {
 694:               try
 695:                 {
 696:                   Constructor c = local_constructor_class.
 697:                                     getDeclaredConstructor(new Class[0]);
 698:                   if (Modifier.isPrivate(c.getModifiers()))
 699:                     return null;
 700:                   return c;
 701:                 }
 702:               catch (NoSuchMethodException e)
 703:                 {
 704:                   // error will be reported later, in newObject()
 705:                   return null;
 706:                 }
 707:             }
 708:           });
 709: 
 710:     osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
 711:     osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
 712: 
 713:     ObjectStreamField[] stream_fields = osc.fields;
 714:     ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
 715:     ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
 716: 
 717:     int stream_idx = 0;
 718:     int real_idx = 0;
 719:     int map_idx = 0;
 720: 
 721:     /*
 722:      * Check that there is no type inconsistencies between the lists.
 723:      * A special checking must be done for the two groups: primitive types and
 724:      * not primitive types. 
 725:      */
 726:     checkTypeConsistency(name, real_fields, stream_fields);
 727:     checkTypeConsistency(name, stream_fields, real_fields);
 728: 
 729:     
 730:     while (stream_idx < stream_fields.length
 731:        || real_idx < real_fields.length)
 732:       {
 733:     ObjectStreamField stream_field = null;
 734:     ObjectStreamField real_field = null;
 735: 
 736:     if (stream_idx == stream_fields.length)
 737:       {
 738:         real_field = real_fields[real_idx++];
 739:       }
 740:     else if (real_idx == real_fields.length)
 741:       {
 742:         stream_field = stream_fields[stream_idx++];
 743:       }
 744:     else
 745:       {
 746:         int comp_val =
 747:           real_fields[real_idx].compareTo (stream_fields[stream_idx]);
 748: 
 749:         if (comp_val < 0)
 750:           {
 751:         real_field = real_fields[real_idx++];
 752:           }
 753:         else if (comp_val > 0)
 754:           {
 755:         stream_field = stream_fields[stream_idx++];
 756:           }
 757:         else
 758:           {
 759:         stream_field = stream_fields[stream_idx++];
 760:         real_field = real_fields[real_idx++];
 761:         if (stream_field.getType() != real_field.getType())
 762:           throw new InvalidClassException
 763:             ("invalid field type for " + real_field.getName() +
 764:              " in class " + name);
 765:           }
 766:       }
 767: 
 768:     /* If some of stream_fields does not correspond to any of real_fields,
 769:      * or the opposite, then fieldmapping will go short.
 770:      */
 771:     if (map_idx == fieldmapping.length)
 772:       {
 773:         ObjectStreamField[] newfieldmapping =
 774:           new ObjectStreamField[fieldmapping.length + 2];
 775:         System.arraycopy(fieldmapping, 0,
 776:                  newfieldmapping, 0, fieldmapping.length);
 777:         fieldmapping = newfieldmapping;
 778:       }
 779:     fieldmapping[map_idx++] = stream_field;
 780:     fieldmapping[map_idx++] = real_field;
 781:       }
 782:     osc.fieldMapping = fieldmapping;
 783: 
 784:     return osc;
 785:   }
 786: 
 787:   /**
 788:    * Reads the current objects non-transient, non-static fields from
 789:    * the current class from the underlying output stream.
 790:    *
 791:    * This method is intended to be called from within a object's
 792:    * <code>private void readObject (ObjectInputStream)</code>
 793:    * method.
 794:    *
 795:    * @exception ClassNotFoundException The class that an object being
 796:    * read in belongs to cannot be found.
 797:    *
 798:    * @exception NotActiveException This method was called from a
 799:    * context other than from the current object's and current class's
 800:    * <code>private void readObject (ObjectInputStream)</code>
 801:    * method.
 802:    *
 803:    * @exception IOException Exception from underlying
 804:    * <code>OutputStream</code>.
 805:    */
 806:   public void defaultReadObject()
 807:     throws ClassNotFoundException, IOException, NotActiveException
 808:   {
 809:     if (this.currentObject == null || this.currentObjectStreamClass == null)
 810:       throw new NotActiveException("defaultReadObject called by non-active"
 811:                    + " class and/or object");
 812: 
 813:     if (fieldsAlreadyRead)
 814:       throw new NotActiveException("defaultReadObject called but fields "
 815:                    + "already read from stream (by "
 816:                    + "defaultReadObject or readFields)");
 817: 
 818:     boolean oldmode = setBlockDataMode(false);
 819:     readFields(this.currentObject, this.currentObjectStreamClass);
 820:     setBlockDataMode(oldmode);
 821: 
 822:     fieldsAlreadyRead = true;
 823:   }
 824: 
 825: 
 826:   /**
 827:    * Registers a <code>ObjectInputValidation</code> to be carried out
 828:    * on the object graph currently being deserialized before it is
 829:    * returned to the original caller of <code>readObject ()</code>.
 830:    * The order of validation for multiple
 831:    * <code>ObjectInputValidation</code>s can be controled using
 832:    * <code>priority</code>.  Validators with higher priorities are
 833:    * called first.
 834:    *
 835:    * @see java.io.ObjectInputValidation
 836:    *
 837:    * @exception InvalidObjectException <code>validator</code> is
 838:    * <code>null</code>
 839:    *
 840:    * @exception NotActiveException an attempt was made to add a
 841:    * validator outside of the <code>readObject</code> method of the
 842:    * object currently being deserialized
 843:    */
 844:   public void registerValidation(ObjectInputValidation validator,
 845:                  int priority)
 846:     throws InvalidObjectException, NotActiveException
 847:   {
 848:     if (this.currentObject == null || this.currentObjectStreamClass == null)
 849:       throw new NotActiveException("registerValidation called by non-active "
 850:                    + "class and/or object");
 851: 
 852:     if (validator == null)
 853:       throw new InvalidObjectException("attempt to add a null "
 854:                        + "ObjectInputValidation object");
 855: 
 856:     if (currentObjectValidators == null)
 857:       currentObjectValidators = new TreeSet<ValidatorAndPriority>();
 858:     
 859:     currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
 860:   }
 861: 
 862: 
 863:   /**
 864:    * Called when a class is being deserialized.  This is a hook to
 865:    * allow subclasses to read in information written by the
 866:    * <code>annotateClass (Class)</code> method of an
 867:    * <code>ObjectOutputStream</code>.
 868:    *
 869:    * This implementation looks up the active call stack for a
 870:    * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
 871:    * it is used to load the class associated with <code>osc</code>,
 872:    * otherwise, the default system <code>ClassLoader</code> is used.
 873:    *
 874:    * @exception IOException Exception from underlying
 875:    * <code>OutputStream</code>.
 876:    *
 877:    * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
 878:    */
 879:   protected Class<?> resolveClass(ObjectStreamClass osc)
 880:     throws ClassNotFoundException, IOException
 881:   {
 882:     String name = osc.getName();
 883:     try
 884:       {
 885:         return Class.forName(name, true, currentLoader());
 886:       }
 887:     catch(ClassNotFoundException x)
 888:       {
 889:         if (name.equals("void"))
 890:           return Void.TYPE;
 891:         else if (name.equals("boolean"))
 892:           return Boolean.TYPE;
 893:         else if (name.equals("byte"))
 894:           return Byte.TYPE;
 895:         else if (name.equals("char"))
 896:           return Character.TYPE;
 897:         else if (name.equals("short"))
 898:           return Short.TYPE;
 899:         else if (name.equals("int"))
 900:           return Integer.TYPE;
 901:         else if (name.equals("long"))
 902:           return Long.TYPE;
 903:         else if (name.equals("float"))
 904:           return Float.TYPE;
 905:         else if (name.equals("double"))
 906:           return Double.TYPE;
 907:         else
 908:           throw x;
 909:       }
 910:   }
 911: 
 912:   /**
 913:    * Returns the most recent user defined ClassLoader on the execution stack
 914:    * or null if none is found.
 915:    */
 916:   private ClassLoader currentLoader()
 917:   {
 918:     return VMStackWalker.firstNonNullClassLoader();
 919:   }
 920: 
 921:   /**
 922:    * Lookup a class stored in the local hashtable. If it is not
 923:    * use the global lookup function in ObjectStreamClass to build
 924:    * the ObjectStreamClass. This method is requested according to
 925:    * the behaviour detected in the JDK by Kaffe's team.
 926:    *
 927:    * @param clazz Class to lookup in the hash table or for which
 928:    * we must build a descriptor.
 929:    * @return A valid instance of ObjectStreamClass corresponding
 930:    * to the specified class.
 931:    */
 932:   private ObjectStreamClass lookupClass(Class clazz)
 933:   {
 934:     if (clazz == null)
 935:       return null;
 936: 
 937:     ObjectStreamClass oclazz;
 938:     oclazz = classLookupTable.get(clazz);
 939:     if (oclazz == null)
 940:       return ObjectStreamClass.lookup(clazz);
 941:     else
 942:       return oclazz;
 943:   }
 944: 
 945:   /**
 946:    * Reconstruct class hierarchy the same way {@link
 947:    * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
 948:    * instead of ObjectStreamClass.lookup.
 949:    *
 950:    * @param clazz This is the class for which we want the hierarchy.
 951:    *
 952:    * @return An array of valid {@link java.io.ObjectStreamClass} instances which
 953:    * represent the class hierarchy for clazz.
 954:    */
 955:   private ObjectStreamClass[] hierarchy(Class clazz)
 956:   { 
 957:     ObjectStreamClass osc = lookupClass(clazz);
 958: 
 959:     return osc == null ? new ObjectStreamClass[0] : osc.hierarchy(); 
 960:   }
 961: 
 962:   /**
 963:    * Allows subclasses to resolve objects that are read from the
 964:    * stream with other objects to be returned in their place.  This
 965:    * method is called the first time each object is encountered.
 966:    *
 967:    * This method must be enabled before it will be called in the
 968:    * serialization process.
 969:    *
 970:    * @exception IOException Exception from underlying
 971:    * <code>OutputStream</code>.
 972:    *
 973:    * @see #enableResolveObject(boolean)
 974:    */
 975:   protected Object resolveObject(Object obj) throws IOException
 976:   {
 977:     return obj;
 978:   }
 979: 
 980: 
 981:   protected Class<?> resolveProxyClass(String[] intfs)
 982:     throws IOException, ClassNotFoundException
 983:   {
 984:     ClassLoader cl = currentLoader();
 985:     
 986:     Class<?>[] clss = new Class<?>[intfs.length];
 987:     if(cl == null)
 988:       {
 989:     for (int i = 0; i < intfs.length; i++)
 990:       clss[i] = Class.forName(intfs[i]);
 991:     cl = ClassLoader.getSystemClassLoader();
 992:       }
 993:     else
 994:       for (int i = 0; i < intfs.length; i++)
 995:     clss[i] = Class.forName(intfs[i], false, cl);
 996:     try 
 997:       {
 998:     return Proxy.getProxyClass(cl, clss);
 999:       } 
1000:     catch (IllegalArgumentException e) 
1001:       {
1002:     throw new ClassNotFoundException(null, e);
1003:       }
1004:   }
1005:   
1006:   /**
1007:    * If <code>enable</code> is <code>true</code> and this object is
1008:    * trusted, then <code>resolveObject (Object)</code> will be called
1009:    * in subsequent calls to <code>readObject (Object)</code>.
1010:    * Otherwise, <code>resolveObject (Object)</code> will not be called.
1011:    *
1012:    * @exception SecurityException This class is not trusted.
1013:    */
1014:   protected boolean enableResolveObject (boolean enable)
1015:     throws SecurityException
1016:   {
1017:     if (enable)
1018:       {
1019:     SecurityManager sm = System.getSecurityManager();
1020:     if (sm != null)
1021:       sm.checkPermission(new SerializablePermission("enableSubstitution"));
1022:       }
1023: 
1024:     boolean old_val = this.resolveEnabled;
1025:     this.resolveEnabled = enable;
1026:     return old_val;
1027:   }
1028: 
1029:   /**
1030:    * Reads stream magic and stream version information from the
1031:    * underlying stream.
1032:    *
1033:    * @exception IOException Exception from underlying stream.
1034:    *
1035:    * @exception StreamCorruptedException An invalid stream magic
1036:    * number or stream version was read from the stream.
1037:    */
1038:   protected void readStreamHeader()
1039:     throws IOException, StreamCorruptedException
1040:   {
1041:     if(dump) dumpElement("STREAM MAGIC ");
1042:     if (this.realInputStream.readShort() != STREAM_MAGIC)
1043:       throw new StreamCorruptedException("Invalid stream magic number");
1044: 
1045:     if(dump) dumpElementln("STREAM VERSION ");
1046:     if (this.realInputStream.readShort() != STREAM_VERSION)
1047:       throw new StreamCorruptedException("Invalid stream version number");
1048:   }
1049: 
1050:   public int read() throws IOException
1051:   {
1052:     if (this.readDataFromBlock)
1053:       {
1054:     if (this.blockDataPosition >= this.blockDataBytes)
1055:       readNextBlock();
1056:     return (this.blockData[this.blockDataPosition++] & 0xff);
1057:       }
1058:     else
1059:       return this.realInputStream.read();
1060:   }
1061: 
1062:   public int read(byte[] data, int offset, int length) throws IOException
1063:   {
1064:     if (this.readDataFromBlock)
1065:       {
1066:         int remain = this.blockDataBytes - this.blockDataPosition;
1067:         if (remain == 0)
1068:           {
1069:             readNextBlock();
1070:             remain = this.blockDataBytes - this.blockDataPosition;
1071:           }
1072:         length = Math.min(length, remain);
1073:     System.arraycopy(this.blockData, this.blockDataPosition,
1074:              data, offset, length);
1075:     this.blockDataPosition += length;
1076: 
1077:     return length;
1078:       }
1079:     else
1080:       return this.realInputStream.read(data, offset, length);
1081:   }
1082: 
1083:   public int available() throws IOException
1084:   {
1085:     if (this.readDataFromBlock)
1086:       {
1087:     if (this.blockDataPosition >= this.blockDataBytes)
1088:       readNextBlock ();
1089: 
1090:     return this.blockDataBytes - this.blockDataPosition;
1091:       }
1092:     else
1093:       return this.realInputStream.available();
1094:   }
1095: 
1096:   public void close() throws IOException
1097:   {
1098:     this.realInputStream.close();
1099:   }
1100: 
1101:   public boolean readBoolean() throws IOException
1102:   {
1103:     boolean switchmode = true;
1104:     boolean oldmode = this.readDataFromBlock;
1105:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1106:       switchmode = false;
1107:     if (switchmode)
1108:       oldmode = setBlockDataMode (true);
1109:     boolean value = this.dataInputStream.readBoolean ();
1110:     if (switchmode)
1111:       setBlockDataMode (oldmode);
1112:     return value;
1113:   }
1114: 
1115:   public byte readByte() throws IOException
1116:   {
1117:     boolean switchmode = true;
1118:     boolean oldmode = this.readDataFromBlock;
1119:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1120:       switchmode = false;
1121:     if (switchmode)
1122:       oldmode = setBlockDataMode(true);
1123:     byte value = this.dataInputStream.readByte();
1124:     if (switchmode)
1125:       setBlockDataMode(oldmode);
1126:     return value;
1127:   }
1128: 
1129:   public int readUnsignedByte() throws IOException
1130:   {
1131:     boolean switchmode = true;
1132:     boolean oldmode = this.readDataFromBlock;
1133:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1134:       switchmode = false;
1135:     if (switchmode)
1136:       oldmode = setBlockDataMode(true);
1137:     int value = this.dataInputStream.readUnsignedByte();
1138:     if (switchmode)
1139:       setBlockDataMode(oldmode);
1140:     return value;
1141:   }
1142: 
1143:   public short readShort() throws IOException
1144:   {
1145:     boolean switchmode = true;
1146:     boolean oldmode = this.readDataFromBlock;
1147:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1148:       switchmode = false;
1149:     if (switchmode)
1150:       oldmode = setBlockDataMode(true);
1151:     short value = this.dataInputStream.readShort();
1152:     if (switchmode)
1153:       setBlockDataMode(oldmode);
1154:     return value;
1155:   }
1156: 
1157:   public int readUnsignedShort() throws IOException
1158:   {
1159:     boolean switchmode = true;
1160:     boolean oldmode = this.readDataFromBlock;
1161:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1162:       switchmode = false;
1163:     if (switchmode)
1164:       oldmode = setBlockDataMode(true);
1165:     int value = this.dataInputStream.readUnsignedShort();
1166:     if (switchmode)
1167:       setBlockDataMode(oldmode);
1168:     return value;
1169:   }
1170: 
1171:   public char readChar() throws IOException
1172:   {
1173:     boolean switchmode = true;
1174:     boolean oldmode = this.readDataFromBlock;
1175:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1176:       switchmode = false;
1177:     if (switchmode)
1178:       oldmode = setBlockDataMode(true);
1179:     char value = this.dataInputStream.readChar();
1180:     if (switchmode)
1181:       setBlockDataMode(oldmode);
1182:     return value;
1183:   }
1184: 
1185:   public int readInt() throws IOException
1186:   {
1187:     boolean switchmode = true;
1188:     boolean oldmode = this.readDataFromBlock;
1189:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1190:       switchmode = false;
1191:     if (switchmode)
1192:       oldmode = setBlockDataMode(true);
1193:     int value = this.dataInputStream.readInt();
1194:     if (switchmode)
1195:       setBlockDataMode(oldmode);
1196:     return value;
1197:   }
1198: 
1199:   public long readLong() throws IOException
1200:   {
1201:     boolean switchmode = true;
1202:     boolean oldmode = this.readDataFromBlock;
1203:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1204:       switchmode = false;
1205:     if (switchmode)
1206:       oldmode = setBlockDataMode(true);
1207:     long value = this.dataInputStream.readLong();
1208:     if (switchmode)
1209:       setBlockDataMode(oldmode);
1210:     return value;
1211:   }
1212: 
1213:   public float readFloat() throws IOException
1214:   {
1215:     boolean switchmode = true;
1216:     boolean oldmode = this.readDataFromBlock;
1217:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1218:       switchmode = false;
1219:     if (switchmode)
1220:       oldmode = setBlockDataMode(true);
1221:     float value = this.dataInputStream.readFloat();
1222:     if (switchmode)
1223:       setBlockDataMode(oldmode);
1224:     return value;
1225:   }
1226: 
1227:   public double readDouble() throws IOException
1228:   {
1229:     boolean switchmode = true;
1230:     boolean oldmode = this.readDataFromBlock;
1231:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1232:       switchmode = false;
1233:     if (switchmode)
1234:       oldmode = setBlockDataMode(true);
1235:     double value = this.dataInputStream.readDouble();
1236:     if (switchmode)
1237:       setBlockDataMode(oldmode);
1238:     return value;
1239:   }
1240: 
1241:   public void readFully(byte data[]) throws IOException
1242:   {
1243:     this.dataInputStream.readFully(data);
1244:   }
1245: 
1246:   public void readFully(byte data[], int offset, int size)
1247:     throws IOException
1248:   {
1249:     this.dataInputStream.readFully(data, offset, size);
1250:   }
1251: 
1252:   public int skipBytes(int len) throws IOException
1253:   {
1254:     return this.dataInputStream.skipBytes(len);
1255:   }
1256: 
1257:   /**
1258:    * @deprecated
1259:    * @see java.io.DataInputStream#readLine ()
1260:    */
1261:   public String readLine() throws IOException
1262:   {
1263:     return this.dataInputStream.readLine();
1264:   }
1265: 
1266:   public String readUTF() throws IOException
1267:   {
1268:     return this.dataInputStream.readUTF();
1269:   }
1270: 
1271:   /**
1272:    * This class allows a class to specify exactly which fields should
1273:    * be read, and what values should be read for these fields.
1274:    *
1275:    * XXX: finish up comments
1276:    */
1277:   public abstract static class GetField
1278:   {
1279:     public abstract ObjectStreamClass getObjectStreamClass();
1280: 
1281:     public abstract boolean defaulted(String name)
1282:       throws IOException, IllegalArgumentException;
1283: 
1284:     public abstract boolean get(String name, boolean defvalue)
1285:       throws IOException, IllegalArgumentException;
1286: 
1287:     public abstract char get(String name, char defvalue)
1288:       throws IOException, IllegalArgumentException;
1289: 
1290:     public abstract byte get(String name, byte defvalue)
1291:       throws IOException, IllegalArgumentException;
1292: 
1293:     public abstract short get(String name, short defvalue)
1294:       throws IOException, IllegalArgumentException;
1295: 
1296:     public abstract int get(String name, int defvalue)
1297:       throws IOException, IllegalArgumentException;
1298: 
1299:     public abstract long get(String name, long defvalue)
1300:       throws IOException, IllegalArgumentException;
1301: 
1302:     public abstract float get(String name, float defvalue)
1303:       throws IOException, IllegalArgumentException;
1304: 
1305:     public abstract double get(String name, double defvalue)
1306:       throws IOException, IllegalArgumentException;
1307: 
1308:     public abstract Object get(String name, Object defvalue)
1309:       throws IOException, IllegalArgumentException;
1310:   }
1311: 
1312:   /**
1313:    * This method should be called by a method called 'readObject' in the
1314:    * deserializing class (if present). It cannot (and should not)be called
1315:    * outside of it. Its goal is to read all fields in the real input stream
1316:    * and keep them accessible through the {@link GetField} class. Calling
1317:    * this method will not alter the deserializing object.
1318:    *
1319:    * @return A valid freshly created 'GetField' instance to get access to
1320:    * the deserialized stream.
1321:    * @throws IOException An input/output exception occured. 
1322:    * @throws ClassNotFoundException 
1323:    * @throws NotActiveException
1324:    */
1325:   public GetField readFields()
1326:     throws IOException, ClassNotFoundException, NotActiveException
1327:   {
1328:     if (this.currentObject == null || this.currentObjectStreamClass == null)
1329:       throw new NotActiveException("readFields called by non-active class and/or object");
1330: 
1331:     if (prereadFields != null)
1332:       return prereadFields;
1333: 
1334:     if (fieldsAlreadyRead)
1335:       throw new NotActiveException("readFields called but fields already read from"
1336:                    + " stream (by defaultReadObject or readFields)");
1337: 
1338:     final ObjectStreamClass clazz = this.currentObjectStreamClass;
1339:     final byte[] prim_field_data = new byte[clazz.primFieldSize];
1340:     final Object[] objs = new Object[clazz.objectFieldCount];
1341: 
1342:     // Apparently Block data is not used with GetField as per
1343:     // empirical evidence against JDK 1.2.  Also see Mauve test
1344:     // java.io.ObjectInputOutput.Test.GetPutField.
1345:     boolean oldmode = setBlockDataMode(false);
1346:     readFully(prim_field_data);
1347:     for (int i = 0; i < objs.length; ++ i)
1348:       objs[i] = readObject();
1349:     setBlockDataMode(oldmode);
1350: 
1351:     prereadFields = new GetField()
1352:       {
1353:     public ObjectStreamClass getObjectStreamClass()
1354:     {
1355:       return clazz;
1356:     }
1357: 
1358:     public boolean defaulted(String name)
1359:       throws IOException, IllegalArgumentException
1360:     {
1361:       ObjectStreamField f = clazz.getField(name);
1362:       
1363:       /* First if we have a serialized field use the descriptor */
1364:       if (f != null)
1365:         {
1366:           /* It is in serialPersistentFields but setClass tells us
1367:            * it should not be set. This value is defaulted.
1368:            */
1369:           if (f.isPersistent() && !f.isToSet())
1370:         return true;
1371:           
1372:           return false;
1373:         }
1374: 
1375:       /* This is not a serialized field. There should be
1376:        * a default value only if the field really exists.
1377:        */
1378:       try
1379:         {
1380:           return (clazz.forClass().getDeclaredField (name) != null);
1381:         }
1382:       catch (NoSuchFieldException e)
1383:         {
1384:           throw new IllegalArgumentException(e);
1385:         }
1386:     }
1387: 
1388:     public boolean get(String name, boolean defvalue)
1389:       throws IOException, IllegalArgumentException
1390:     {
1391:       ObjectStreamField field = getField(name, Boolean.TYPE);
1392: 
1393:       if (field == null)
1394:         return defvalue;
1395: 
1396:       return prim_field_data[field.getOffset()] == 0 ? false : true;
1397:     }
1398: 
1399:     public char get(String name, char defvalue)
1400:       throws IOException, IllegalArgumentException
1401:     {
1402:       ObjectStreamField field = getField(name, Character.TYPE);
1403: 
1404:       if (field == null)
1405:         return defvalue;
1406: 
1407:       int off = field.getOffset();
1408: 
1409:       return (char)(((prim_field_data[off++] & 0xFF) << 8)
1410:             | (prim_field_data[off] & 0xFF));
1411:     }
1412: 
1413:     public byte get(String name, byte defvalue)
1414:       throws IOException, IllegalArgumentException
1415:     {
1416:       ObjectStreamField field = getField(name, Byte.TYPE);
1417: 
1418:       if (field == null)
1419:         return defvalue;
1420: 
1421:       return prim_field_data[field.getOffset()];
1422:     }
1423: 
1424:     public short get(String name, short defvalue)
1425:       throws IOException, IllegalArgumentException
1426:     {
1427:       ObjectStreamField field = getField(name, Short.TYPE);
1428: 
1429:       if (field == null)
1430:         return defvalue;
1431: 
1432:       int off = field.getOffset();
1433: 
1434:       return (short)(((prim_field_data[off++] & 0xFF) << 8)
1435:              | (prim_field_data[off] & 0xFF));
1436:     }
1437: 
1438:     public int get(String name, int defvalue)
1439:       throws IOException, IllegalArgumentException
1440:     {
1441:       ObjectStreamField field = getField(name, Integer.TYPE);
1442: 
1443:       if (field == null)
1444:         return defvalue;
1445: 
1446:       int off = field.getOffset();
1447: 
1448:       return ((prim_field_data[off++] & 0xFF) << 24)
1449:         | ((prim_field_data[off++] & 0xFF) << 16)
1450:         | ((prim_field_data[off++] & 0xFF) << 8)
1451:         | (prim_field_data[off] & 0xFF);
1452:     }
1453: 
1454:     public long get(String name, long defvalue)
1455:       throws IOException, IllegalArgumentException
1456:     {
1457:       ObjectStreamField field = getField(name, Long.TYPE);
1458: 
1459:       if (field == null)
1460:         return defvalue;
1461: 
1462:       int off = field.getOffset();
1463: 
1464:       return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1465:             | ((prim_field_data[off++] & 0xFFL) << 48)
1466:             | ((prim_field_data[off++] & 0xFFL) << 40)
1467:             | ((prim_field_data[off++] & 0xFFL) << 32)
1468:             | ((prim_field_data[off++] & 0xFF) << 24)
1469:             | ((prim_field_data[off++] & 0xFF) << 16)
1470:             | ((prim_field_data[off++] & 0xFF) << 8)
1471:             | (prim_field_data[off] & 0xFF));
1472:     }
1473: 
1474:     public float get(String name, float defvalue)
1475:       throws IOException, IllegalArgumentException
1476:     {
1477:       ObjectStreamField field = getField(name, Float.TYPE);
1478: 
1479:       if (field == null)
1480:         return defvalue;
1481: 
1482:       int off = field.getOffset();
1483: 
1484:       return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1485:                       | ((prim_field_data[off++] & 0xFF) << 16)
1486:                       | ((prim_field_data[off++] & 0xFF) << 8)
1487:                       | (prim_field_data[off] & 0xFF));
1488:     }
1489: 
1490:     public double get(String name, double defvalue)
1491:       throws IOException, IllegalArgumentException
1492:     {
1493:       ObjectStreamField field = getField(name, Double.TYPE);
1494: 
1495:       if (field == null)
1496:         return defvalue;
1497: 
1498:       int off = field.getOffset();
1499: 
1500:       return Double.longBitsToDouble
1501:         ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1502:               | ((prim_field_data[off++] & 0xFFL) << 48)
1503:               | ((prim_field_data[off++] & 0xFFL) << 40)
1504:               | ((prim_field_data[off++] & 0xFFL) << 32)
1505:               | ((prim_field_data[off++] & 0xFF) << 24)
1506:               | ((prim_field_data[off++] & 0xFF) << 16)
1507:               | ((prim_field_data[off++] & 0xFF) << 8)
1508:               | (prim_field_data[off] & 0xFF)));
1509:     }
1510: 
1511:     public Object get(String name, Object defvalue)
1512:       throws IOException, IllegalArgumentException
1513:     {
1514:       ObjectStreamField field =
1515:         getField(name, defvalue == null ? null : defvalue.getClass ());
1516: 
1517:       if (field == null)
1518:         return defvalue;
1519: 
1520:       return objs[field.getOffset()];
1521:     }
1522: 
1523:     private ObjectStreamField getField(String name, Class type)
1524:       throws IllegalArgumentException
1525:     {
1526:       ObjectStreamField field = clazz.getField(name);
1527:       boolean illegal = false;
1528: 
1529:           // XXX This code is horrible and needs to be rewritten!
1530:       try
1531:         {
1532:           try
1533:         {
1534:           Class field_type = field.getType();
1535:           
1536:           if (type == field_type ||
1537:               (type == null && !field_type.isPrimitive()))
1538:             {
1539:               /* See defaulted */
1540:               return field;
1541:             }
1542:      
1543:           illegal = true;
1544:           throw new IllegalArgumentException
1545:             ("Field requested is of type "
1546:              + field_type.getName()
1547:              + ", but requested type was "
1548:              + (type == null ?  "Object" : type.getName()));
1549:         }
1550:           catch (NullPointerException _)
1551:         {
1552:           /* Here we catch NullPointerException, because it may
1553:              only come from the call 'field.getType()'. If field
1554:              is null, we have to return null and classpath ethic
1555:              say we must try to avoid 'if (xxx == null)'.
1556:           */
1557:         }
1558:           catch (IllegalArgumentException e)
1559:         {
1560:           throw e;
1561:         }
1562:           
1563:           return null;
1564:         }
1565:       finally
1566:         {
1567:           /* If this is an unassigned field we should return
1568:            * the default value.
1569:            */
1570:           if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1571:         return null;
1572: 
1573:           /* We do not want to modify transient fields. They should
1574:            * be left to 0.
1575:            */
1576:           try
1577:         {
1578:           Field f = clazz.forClass().getDeclaredField(name);
1579:           if (Modifier.isTransient(f.getModifiers()))
1580:             throw new IllegalArgumentException
1581:               ("no such field (non transient) " + name);
1582:           if (field == null && f.getType() != type)
1583:             throw new IllegalArgumentException
1584:               ("Invalid requested type for field " + name);
1585:         }
1586:           catch (NoSuchFieldException e)
1587:         {
1588:           if (field == null)
1589:             throw new IllegalArgumentException(e);
1590:         }
1591:            
1592:         }
1593:     }
1594:       };
1595: 
1596:     fieldsAlreadyRead = true;
1597:     return prereadFields;
1598:   }
1599: 
1600:   /**
1601:    * Protected constructor that allows subclasses to override
1602:    * deserialization.  This constructor should be called by subclasses
1603:    * that wish to override <code>readObject (Object)</code>.  This
1604:    * method does a security check <i>NOTE: currently not
1605:    * implemented</i>, then sets a flag that informs
1606:    * <code>readObject (Object)</code> to call the subclasses
1607:    * <code>readObjectOverride (Object)</code> method.
1608:    *
1609:    * @see #readObjectOverride()
1610:    */
1611:   protected ObjectInputStream()
1612:     throws IOException, SecurityException
1613:   {
1614:     SecurityManager sec_man = System.getSecurityManager();
1615:     if (sec_man != null)
1616:       sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1617:     this.useSubclassMethod = true;
1618:   }
1619: 
1620:   /**
1621:    * This method allows subclasses to override the default
1622:    * de serialization mechanism provided by
1623:    * <code>ObjectInputStream</code>.  To make this method be used for
1624:    * writing objects, subclasses must invoke the 0-argument
1625:    * constructor on this class from their constructor.
1626:    *
1627:    * @see #ObjectInputStream()
1628:    */
1629:   protected Object readObjectOverride()
1630:     throws ClassNotFoundException, IOException, OptionalDataException
1631:   {
1632:     throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1633:   }
1634: 
1635:   /**
1636:    * Assigns the next available handle to <code>obj</code>.
1637:    *
1638:    * @param obj The object for which we want a new handle.
1639:    * @param shared True if the handle should be shared
1640:    *               with later calls.
1641:    * @return A valid handle for the specified object.
1642:    */
1643:   private int assignNewHandle(Object obj, boolean shared)
1644:   {
1645:     int handle = this.nextOID;
1646:     this.nextOID = handle + 1;
1647:     rememberHandle(obj,shared,handle);
1648:     return handle;
1649:   }
1650: 
1651:   /**
1652:    * Remember the object associated with the given handle.
1653:    *
1654:    * @param obj an object
1655:    * @param shared true if the reference should be shared
1656:    *               with later calls.
1657:    * @param handle a handle, must be >= baseWireHandle
1658:    *
1659:    * @see #lookupHandle
1660:    */
1661:   private void rememberHandle(Object obj, boolean shared,
1662:                   int handle)
1663:   {
1664:     handles.put(handle, new Pair<Boolean,Object>(shared, obj));
1665:   }
1666:   
1667:   /**
1668:    * Look up the object associated with a given handle.
1669:    *
1670:    * @param handle a handle, must be >= baseWireHandle
1671:    * @return the object remembered for handle or null if none.
1672:    * @throws StreamCorruptedException if the handle is invalid.
1673:    * @throws InvalidObjectException if the reference is not shared.
1674:    * @see #rememberHandle
1675:    */
1676:   private Object lookupHandle(int handle)
1677:     throws ObjectStreamException
1678:   {
1679:     Pair<Boolean,Object> result = handles.get(handle);
1680:     if (result == null)
1681:       throw new StreamCorruptedException("The handle, " + 
1682:                      Integer.toHexString(handle) +
1683:                      ", is invalid.");
1684:     if (!result.getLeft())
1685:       throw new InvalidObjectException("The handle, " + 
1686:                        Integer.toHexString(handle) +
1687:                        ", is not shared.");
1688:     return result.getRight();
1689:   }
1690: 
1691:   private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
1692:                    boolean shared)
1693:     throws IOException
1694:   {
1695:     if (osc != null && obj instanceof Serializable)
1696:       {
1697:     try
1698:       {
1699:         Method m = osc.readResolveMethod; 
1700:         if(m != null)
1701:         {
1702:         obj = m.invoke(obj, new Object[] {});
1703:         }
1704:       }
1705:     catch (IllegalAccessException ignore)
1706:       {
1707:       }
1708:     catch (InvocationTargetException exception)
1709:       {
1710:         Throwable cause = exception.getCause();
1711:         if (cause instanceof ObjectStreamException)
1712:           throw (ObjectStreamException) cause;
1713:         else if (cause instanceof RuntimeException)
1714:           throw (RuntimeException) cause;
1715:         else if (cause instanceof Error)
1716:           throw (Error) cause;
1717:       }
1718:       }
1719: 
1720:     if (this.resolveEnabled)
1721:       obj = resolveObject(obj);
1722: 
1723:     rememberHandle(obj, shared, handle);
1724:     if (!shared)
1725:       {
1726:     if (obj instanceof byte[])
1727:       return ((byte[]) obj).clone();
1728:     if (obj instanceof short[])
1729:       return ((short[]) obj).clone();
1730:     if (obj instanceof int[])
1731:       return ((int[]) obj).clone();
1732:     if (obj instanceof long[])
1733:       return ((long[]) obj).clone();
1734:     if (obj instanceof char[])
1735:       return ((char[]) obj).clone();
1736:     if (obj instanceof boolean[])
1737:       return ((boolean[]) obj).clone();
1738:     if (obj instanceof float[])
1739:       return ((float[]) obj).clone();
1740:     if (obj instanceof double[])
1741:       return ((double[]) obj).clone();
1742:     if (obj instanceof Object[])
1743:       return ((Object[]) obj).clone();
1744:       }
1745:     return obj;
1746:   }
1747: 
1748:   private void clearHandles()
1749:   {
1750:     handles.clear();
1751:     this.nextOID = baseWireHandle;
1752:   }
1753: 
1754:   private void readNextBlock() throws IOException
1755:   {
1756:     byte marker = this.realInputStream.readByte();
1757:     while (marker == TC_RESET)
1758:       {
1759:         if(dump) dumpElementln("RESET");
1760:         clearHandles();
1761:         marker = this.realInputStream.readByte();
1762:       }
1763:     readNextBlock(marker);
1764:   }
1765: 
1766:   private void readNextBlock(byte marker) throws IOException
1767:   {
1768:     if (marker == TC_BLOCKDATA)
1769:       {
1770:     if(dump) dumpElement("BLOCK DATA SIZE=");
1771:     this.blockDataBytes = this.realInputStream.readUnsignedByte();
1772:     if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1773:       }
1774:     else if (marker == TC_BLOCKDATALONG)
1775:       {
1776:     if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1777:     this.blockDataBytes = this.realInputStream.readInt();
1778:     if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1779:       }
1780:     else
1781:       {
1782:     throw new EOFException("Attempt to read primitive data, but no data block is active.");
1783:       }
1784: 
1785:     if (this.blockData.length < this.blockDataBytes)
1786:       this.blockData = new byte[this.blockDataBytes];
1787: 
1788:     this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1789:     this.blockDataPosition = 0;
1790:   }
1791: 
1792:   private void readArrayElements (Object array, Class clazz)
1793:     throws ClassNotFoundException, IOException
1794:   {
1795:     if (clazz.isPrimitive())
1796:       {
1797:     if (clazz == Boolean.TYPE)
1798:       {
1799:         boolean[] cast_array = (boolean[])array;
1800:         for (int i=0; i < cast_array.length; i++)
1801:           cast_array[i] = this.realInputStream.readBoolean();
1802:         return;
1803:       }
1804:     if (clazz == Byte.TYPE)
1805:       {
1806:         byte[] cast_array = (byte[])array;
1807:         for (int i=0; i < cast_array.length; i++)
1808:           cast_array[i] = this.realInputStream.readByte();
1809:         return;
1810:       }
1811:     if (clazz == Character.TYPE)
1812:       {
1813:         char[] cast_array = (char[])array;
1814:         for (int i=0; i < cast_array.length; i++)
1815:           cast_array[i] = this.realInputStream.readChar();
1816:         return;
1817:       }
1818:     if (clazz == Double.TYPE)
1819:       {
1820:         double[] cast_array = (double[])array;
1821:         for (int i=0; i < cast_array.length; i++)
1822:           cast_array[i] = this.realInputStream.readDouble();
1823:         return;
1824:       }
1825:     if (clazz == Float.TYPE)
1826:       {
1827:         float[] cast_array = (float[])array;
1828:         for (int i=0; i < cast_array.length; i++)
1829:           cast_array[i] = this.realInputStream.readFloat();
1830:         return;
1831:       }
1832:     if (clazz == Integer.TYPE)
1833:       {
1834:         int[] cast_array = (int[])array;
1835:         for (int i=0; i < cast_array.length; i++)
1836:           cast_array[i] = this.realInputStream.readInt();
1837:         return;
1838:       }
1839:     if (clazz == Long.TYPE)
1840:       {
1841:         long[] cast_array = (long[])array;
1842:         for (int i=0; i < cast_array.length; i++)
1843:           cast_array[i] = this.realInputStream.readLong();
1844:         return;
1845:       }
1846:     if (clazz == Short.TYPE)
1847:       {
1848:         short[] cast_array = (short[])array;
1849:         for (int i=0; i < cast_array.length; i++)
1850:           cast_array[i] = this.realInputStream.readShort();
1851:         return;
1852:       }
1853:       }
1854:     else
1855:       {
1856:     Object[] cast_array = (Object[])array;
1857:     for (int i=0; i < cast_array.length; i++)
1858:        cast_array[i] = readObject();
1859:       }
1860:   }
1861: 
1862:   private void readFields (Object obj, ObjectStreamClass stream_osc)
1863:     throws ClassNotFoundException, IOException
1864:   {
1865:     ObjectStreamField[] fields = stream_osc.fieldMapping;
1866: 
1867:     for (int i = 0; i < fields.length; i += 2)
1868:       {
1869:     ObjectStreamField stream_field = fields[i];
1870:     ObjectStreamField real_field = fields[i + 1];
1871:     boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1872:     boolean set_value = (real_field != null && real_field.isToSet());
1873:     String field_name;
1874:     char type;
1875: 
1876:     if (stream_field != null)
1877:       {
1878:         field_name = stream_field.getName();
1879:         type = stream_field.getTypeCode();
1880:       }
1881:     else
1882:       {
1883:         field_name = real_field.getName();
1884:         type = real_field.getTypeCode();
1885:       }
1886:     
1887:     switch(type)
1888:       {
1889:       case 'Z':
1890:         {
1891:           boolean value =
1892:         read_value ? this.realInputStream.readBoolean() : false;
1893:           if (dump && read_value && set_value)
1894:         dumpElementln("  " + field_name + ": " + value);
1895:           if (set_value)
1896:         real_field.setBooleanField(obj, value);
1897:           break;
1898:         }
1899:       case 'B':
1900:         {
1901:           byte value =
1902:         read_value ? this.realInputStream.readByte() : 0;
1903:           if (dump && read_value && set_value)
1904:         dumpElementln("  " + field_name + ": " + value);
1905:           if (set_value)
1906:         real_field.setByteField(obj, value);
1907:           break;
1908:         }
1909:       case 'C':
1910:         {
1911:           char value =
1912:         read_value ? this.realInputStream.readChar(): 0;
1913:           if (dump && read_value && set_value)
1914:         dumpElementln("  " + field_name + ": " + value);
1915:           if (set_value)
1916:         real_field.setCharField(obj, value);
1917:           break;
1918:         }
1919:       case 'D':
1920:         {
1921:           double value =
1922:         read_value ? this.realInputStream.readDouble() : 0;
1923:           if (dump && read_value && set_value)
1924:         dumpElementln("  " + field_name + ": " + value);
1925:           if (set_value)
1926:         real_field.setDoubleField(obj, value);
1927:           break;
1928:         }
1929:       case 'F':
1930:         {
1931:           float value =
1932:         read_value ? this.realInputStream.readFloat() : 0;
1933:           if (dump && read_value && set_value)
1934:         dumpElementln("  " + field_name + ": " + value);
1935:           if (set_value)
1936:         real_field.setFloatField(obj, value);
1937:           break;
1938:         }
1939:       case 'I':
1940:         {
1941:           int value =
1942:         read_value ? this.realInputStream.readInt() : 0;
1943:           if (dump && read_value && set_value)
1944:         dumpElementln("  " + field_name + ": " + value);
1945:           if (set_value)
1946:         real_field.setIntField(obj, value);
1947:           break;
1948:         }
1949:       case 'J':
1950:         {
1951:           long value =
1952:         read_value ? this.realInputStream.readLong() : 0;
1953:           if (dump && read_value && set_value)
1954:         dumpElementln("  " + field_name + ": " + value);
1955:           if (set_value)
1956:         real_field.setLongField(obj, value);
1957:           break;
1958:         }
1959:       case 'S':
1960:         {
1961:           short value =
1962:         read_value ? this.realInputStream.readShort() : 0;
1963:           if (dump && read_value && set_value)
1964:         dumpElementln("  " + field_name + ": " + value);
1965:           if (set_value)
1966:         real_field.setShortField(obj, value);
1967:           break;
1968:         }
1969:       case 'L':
1970:       case '[':
1971:         {
1972:           Object value =
1973:         read_value ? readObject() : null;
1974:           if (set_value)
1975:         real_field.setObjectField(obj, value);
1976:           break;
1977:         }
1978:       default:
1979:         throw new InternalError("Invalid type code: " + type);
1980:       }
1981:       }
1982:   }
1983:   
1984:   // Toggles writing primitive data to block-data buffer.
1985:   private boolean setBlockDataMode (boolean on)
1986:   {
1987:     boolean oldmode = this.readDataFromBlock;
1988:     this.readDataFromBlock = on;
1989: 
1990:     if (on)
1991:       this.dataInputStream = this.blockDataInput;
1992:     else
1993:       this.dataInputStream = this.realInputStream;
1994:     return oldmode;
1995:   }
1996: 
1997:   // returns a new instance of REAL_CLASS that has been constructed
1998:   // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1999:   private Object newObject (Class real_class, Constructor constructor)
2000:     throws ClassNotFoundException, IOException
2001:   {
2002:     if (constructor == null)
2003:         throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName()); 
2004:     try
2005:       {
2006:     return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
2007:       }
2008:     catch (InstantiationException e)
2009:       {
2010:         throw (ClassNotFoundException) new ClassNotFoundException
2011:           ("Instance of " + real_class + " could not be created").initCause(e);
2012:       }
2013:   }
2014: 
2015:   // runs all registered ObjectInputValidations in prioritized order
2016:   // on OBJ
2017:   private void invokeValidators() throws InvalidObjectException
2018:   {
2019:     try
2020:       {
2021:     Iterator<ValidatorAndPriority> it = currentObjectValidators.iterator();
2022:     while(it.hasNext())
2023:       {
2024:         ValidatorAndPriority vap = it.next();
2025:         ObjectInputValidation validator = vap.validator;
2026:         validator.validateObject();
2027:       }
2028:       }
2029:     finally
2030:       {
2031:     currentObjectValidators = null;
2032:       }
2033:   }
2034: 
2035:   private void callReadMethod (Method readObject, Class klass, Object obj)
2036:     throws ClassNotFoundException, IOException
2037:   {
2038:     try
2039:       {
2040:     readObject.invoke(obj, new Object[] { this });
2041:       }
2042:     catch (InvocationTargetException x)
2043:       {
2044:         /* Rethrow if possible. */
2045:     Throwable exception = x.getTargetException();
2046:     if (exception instanceof RuntimeException)
2047:       throw (RuntimeException) exception;
2048:     if (exception instanceof IOException)
2049:       throw (IOException) exception;
2050:         if (exception instanceof ClassNotFoundException)
2051:           throw (ClassNotFoundException) exception;
2052: 
2053:     throw (IOException) new IOException(
2054:       "Exception thrown from readObject() on " + klass).initCause(x);
2055:       }
2056:     catch (Exception x)
2057:       {
2058:     throw (IOException) new IOException(
2059:       "Failure invoking readObject() on " + klass).initCause(x);
2060:       }
2061: 
2062:     // Invalidate fields which has been read through readFields.
2063:     prereadFields = null;
2064:   }
2065:     
2066:   private static final int BUFFER_SIZE = 1024;
2067: 
2068:   private DataInputStream realInputStream;
2069:   private DataInputStream dataInputStream;
2070:   private DataInputStream blockDataInput;
2071:   private int blockDataPosition;
2072:   private int blockDataBytes;
2073:   private byte[] blockData;
2074:   private boolean useSubclassMethod;
2075:   private int nextOID;
2076:   private boolean resolveEnabled;
2077:   private Map<Integer,Pair<Boolean,Object>> handles;
2078:   private Object currentObject;
2079:   private ObjectStreamClass currentObjectStreamClass;
2080:   private TreeSet<ValidatorAndPriority> currentObjectValidators;
2081:   private boolean readDataFromBlock;
2082:   private boolean fieldsAlreadyRead;
2083:   private Hashtable<Class,ObjectStreamClass> classLookupTable;
2084:   private GetField prereadFields;
2085: 
2086:   private static boolean dump;
2087: 
2088:   // The nesting depth for debugging output
2089:   private int depth = 0;
2090: 
2091:   private static final boolean DEBUG = false;
2092: 
2093:   private void dumpElement (String msg)
2094:   {
2095:     System.out.print(msg);
2096:   }
2097:   
2098:   private void dumpElementln (String msg)
2099:   {
2100:     System.out.println(msg);
2101:     for (int i = 0; i < depth; i++)
2102:       System.out.print (" ");
2103:     System.out.print (Thread.currentThread() + ": ");
2104:   }
2105: 
2106:   private void dumpElementln (String msg, Object obj)
2107:   {
2108:     try
2109:       {
2110:     System.out.print(msg);
2111:     if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
2112:       System.out.println(obj.getClass());
2113:     else
2114:     System.out.println(obj);
2115:       }
2116:     catch (Exception _)
2117:       {
2118:       }
2119:     for (int i = 0; i < depth; i++)
2120:       System.out.print (" ");
2121:     System.out.print (Thread.currentThread() + ": ");
2122:   }
2123: 
2124:   // used to keep a prioritized list of object validators
2125:   private static final class ValidatorAndPriority implements Comparable
2126:   {
2127:     int priority;
2128:     ObjectInputValidation validator;
2129: 
2130:     ValidatorAndPriority (ObjectInputValidation validator, int priority)
2131:     {
2132:       this.priority = priority;
2133:       this.validator = validator;
2134:     }
2135: 
2136:     public int compareTo (Object o)
2137:     {
2138:       ValidatorAndPriority vap = (ValidatorAndPriority)o;
2139:       return this.priority - vap.priority;
2140:     }
2141:   }
2142: }