Source for java.io.ObjectOutputStream

   1: /* ObjectOutputStream.java -- Class used to write serialized objects
   2:    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 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.java.io.ObjectIdentityMap2Int;
  43: import gnu.java.lang.reflect.TypeSignature;
  44: import gnu.java.security.action.SetAccessibleAction;
  45: 
  46: import java.lang.reflect.Array;
  47: import java.lang.reflect.Field;
  48: import java.lang.reflect.InvocationTargetException;
  49: import java.lang.reflect.Method;
  50: 
  51: 
  52: /**
  53:  * An <code>ObjectOutputStream</code> can be used to write objects
  54:  * as well as primitive data in a platform-independent manner to an
  55:  * <code>OutputStream</code>.
  56:  *
  57:  * The data produced by an <code>ObjectOutputStream</code> can be read
  58:  * and reconstituted by an <code>ObjectInputStream</code>.
  59:  *
  60:  * <code>writeObject (Object)</code> is used to write Objects, the
  61:  * <code>write&lt;type&gt;</code> methods are used to write primitive
  62:  * data (as in <code>DataOutputStream</code>). Strings can be written
  63:  * as objects or as primitive data.
  64:  *
  65:  * Not all objects can be written out using an
  66:  * <code>ObjectOutputStream</code>.  Only those objects that are an
  67:  * instance of <code>java.io.Serializable</code> can be written.
  68:  *
  69:  * Using default serialization, information about the class of an
  70:  * object is written, all of the non-transient, non-static fields of
  71:  * the object are written, if any of these fields are objects, they are
  72:  * written out in the same manner.
  73:  *
  74:  * An object is only written out the first time it is encountered.  If
  75:  * the object is encountered later, a reference to it is written to
  76:  * the underlying stream.  Thus writing circular object graphs
  77:  * does not present a problem, nor are relationships between objects
  78:  * in a graph lost.
  79:  *
  80:  * Example usage:
  81:  * <pre>
  82:  * Hashtable map = new Hashtable ();
  83:  * map.put ("one", new Integer (1));
  84:  * map.put ("two", new Integer (2));
  85:  *
  86:  * ObjectOutputStream oos =
  87:  * new ObjectOutputStream (new FileOutputStream ("numbers"));
  88:  * oos.writeObject (map);
  89:  * oos.close ();
  90:  *
  91:  * ObjectInputStream ois =
  92:  * new ObjectInputStream (new FileInputStream ("numbers"));
  93:  * Hashtable newmap = (Hashtable)ois.readObject ();
  94:  *
  95:  * System.out.println (newmap);
  96:  * </pre>
  97:  *
  98:  * The default serialization can be overriden in two ways.
  99:  *
 100:  * By defining a method <code>private void
 101:  * writeObject (ObjectOutputStream)</code>, a class can dictate exactly
 102:  * how information about itself is written.
 103:  * <code>defaultWriteObject ()</code> may be called from this method to
 104:  * carry out default serialization.  This method is not
 105:  * responsible for dealing with fields of super-classes or subclasses.
 106:  *
 107:  * By implementing <code>java.io.Externalizable</code>.  This gives
 108:  * the class complete control over the way it is written to the
 109:  * stream.  If this approach is used the burden of writing superclass
 110:  * and subclass data is transfered to the class implementing
 111:  * <code>java.io.Externalizable</code>.
 112:  *
 113:  * @see java.io.DataOutputStream
 114:  * @see java.io.Externalizable
 115:  * @see java.io.ObjectInputStream
 116:  * @see java.io.Serializable
 117:  * @author Tom Tromey (tromey@redhat.com)
 118:  * @author Jeroen Frijters (jeroen@frijters.net)
 119:  * @author Guilhem Lavaux (guilhem@kaffe.org)
 120:  * @author Michael Koch (konqueror@gmx.de)
 121:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 122:  */
 123: public class ObjectOutputStream extends OutputStream
 124:   implements ObjectOutput, ObjectStreamConstants
 125: {
 126:   /**
 127:    * Creates a new <code>ObjectOutputStream</code> that will do all of
 128:    * its writing onto <code>out</code>.  This method also initializes
 129:    * the stream by writing the header information (stream magic number
 130:    * and stream version).
 131:    *
 132:    * @exception IOException Writing stream header to underlying
 133:    * stream cannot be completed.
 134:    *
 135:    * @see #writeStreamHeader()
 136:    */
 137:   public ObjectOutputStream (OutputStream out) throws IOException
 138:   {
 139:     realOutput = new DataOutputStream(out);
 140:     blockData = new byte[ BUFFER_SIZE ];
 141:     blockDataCount = 0;
 142:     blockDataOutput = new DataOutputStream(this);
 143:     setBlockDataMode(true);
 144:     replacementEnabled = false;
 145:     isSerializing = false;
 146:     nextOID = baseWireHandle;
 147:     OIDLookupTable = new ObjectIdentityMap2Int();
 148:     protocolVersion = defaultProtocolVersion;
 149:     useSubclassMethod = false;
 150:     writeStreamHeader();
 151: 
 152:     if (DEBUG)
 153:       {
 154:         String val = System.getProperty("gcj.dumpobjects");
 155:         if (val != null && !val.equals(""))
 156:           dump = true;
 157:       }
 158:   }
 159: 
 160:   /**
 161:    * Writes a representation of <code>obj</code> to the underlying
 162:    * output stream by writing out information about its class, then
 163:    * writing out each of the objects non-transient, non-static
 164:    * fields.  If any of these fields are other objects,
 165:    * they are written out in the same manner.
 166:    *
 167:    * This method can be overriden by a class by implementing
 168:    * <code>private void writeObject (ObjectOutputStream)</code>.
 169:    *
 170:    * If an exception is thrown from this method, the stream is left in
 171:    * an undefined state.
 172:    *
 173:    * @param obj the object to serialize.
 174:    * @exception NotSerializableException An attempt was made to
 175:    * serialize an <code>Object</code> that is not serializable.
 176:    *
 177:    * @exception InvalidClassException Somebody tried to serialize
 178:    * an object which is wrongly formatted.
 179:    *
 180:    * @exception IOException Exception from underlying
 181:    * <code>OutputStream</code>.
 182:    * @see #writeUnshared(Object)
 183:    */
 184:   public final void writeObject(Object obj) throws IOException
 185:   {
 186:     writeObject(obj, true);
 187:   }
 188: 
 189:   /**
 190:    * Writes an object to the stream in the same manner as
 191:    * {@link #writeObject(Object)}, but without the use of
 192:    * references.  As a result, the object is always written
 193:    * to the stream in full.  Likewise, if an object is written
 194:    * by this method and is then later written again by
 195:    * {@link #writeObject(Object)}, both calls will write out
 196:    * the object in full, as the later call to
 197:    * {@link #writeObject(Object)} will know nothing of the
 198:    * earlier use of {@link #writeUnshared(Object)}.
 199:    *
 200:    * @param obj the object to serialize.
 201:    * @throws NotSerializableException if the object being
 202:    *                                  serialized does not implement
 203:    *                                  {@link Serializable}.
 204:    * @throws InvalidClassException if a problem occurs with
 205:    *                               the class of the object being
 206:    *                               serialized.
 207:    * @throws IOException if an I/O error occurs on the underlying
 208:    *                     <code>OutputStream</code>.
 209:    * @since 1.4
 210:    * @see #writeObject(Object)
 211:    */
 212:   public void writeUnshared(Object obj)
 213:     throws IOException
 214:   {
 215:     writeObject(obj, false);
 216:   }
 217: 
 218:   /**
 219:    * Writes a representation of <code>obj</code> to the underlying
 220:    * output stream by writing out information about its class, then
 221:    * writing out each of the objects non-transient, non-static
 222:    * fields.  If any of these fields are other objects,
 223:    * they are written out in the same manner.
 224:    *
 225:    * This method can be overriden by a class by implementing
 226:    * <code>private void writeObject (ObjectOutputStream)</code>.
 227:    *
 228:    * If an exception is thrown from this method, the stream is left in
 229:    * an undefined state.
 230:    *
 231:    * @param obj the object to serialize.
 232:    * @param shared true if the serialized object should be
 233:    *               shared with later calls.
 234:    * @exception NotSerializableException An attempt was made to
 235:    * serialize an <code>Object</code> that is not serializable.
 236:    *
 237:    * @exception InvalidClassException Somebody tried to serialize
 238:    * an object which is wrongly formatted.
 239:    *
 240:    * @exception IOException Exception from underlying
 241:    * <code>OutputStream</code>.
 242:    * @see #writeUnshared(Object)
 243:    */
 244:   private final void writeObject(Object obj, boolean shared)
 245:     throws IOException
 246:   {
 247:     if (useSubclassMethod)
 248:       {
 249:         if (dump)
 250:           dumpElementln ("WRITE OVERRIDE: " + obj);
 251: 
 252:         writeObjectOverride(obj);
 253:         return;
 254:       }
 255: 
 256:     if (dump)
 257:       dumpElementln ("WRITE: ", obj);
 258: 
 259:     depth += 2;
 260: 
 261:     boolean was_serializing = isSerializing;
 262:     boolean old_mode = setBlockDataMode(false);
 263:     try
 264:       {
 265:         isSerializing = true;
 266:         boolean replaceDone = false;
 267:         Object replacedObject = null;
 268: 
 269:         while (true)
 270:           {
 271:             if (obj == null)
 272:               {
 273:                 realOutput.writeByte(TC_NULL);
 274:                 break;
 275:               }
 276: 
 277:             int handle = findHandle(obj);
 278:             if (handle >= 0 && shared)
 279:               {
 280:                 realOutput.writeByte(TC_REFERENCE);
 281:                 realOutput.writeInt(handle);
 282:                 break;
 283:               }
 284: 
 285:             if (obj instanceof Class)
 286:               {
 287:                 Class cl = (Class)obj;
 288:                 ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
 289:                 realOutput.writeByte(TC_CLASS);
 290:                 if (!osc.isProxyClass)
 291:                   {
 292:                     writeObject (osc);
 293:                   }
 294:                 else
 295:                   {System.err.println("1");
 296:                     realOutput.writeByte(TC_PROXYCLASSDESC);
 297:                     Class[] intfs = cl.getInterfaces();
 298:                     realOutput.writeInt(intfs.length);
 299:                     for (int i = 0; i < intfs.length; i++)
 300:                       realOutput.writeUTF(intfs[i].getName());
 301: 
 302:                     boolean oldmode = setBlockDataMode(true);
 303:                     annotateProxyClass(cl);
 304:                     setBlockDataMode(oldmode);
 305:                     realOutput.writeByte(TC_ENDBLOCKDATA);
 306: 
 307:                     writeObject(osc.getSuper());
 308:                   }
 309:                 if (shared)
 310:                   assignNewHandle(obj);
 311:                 break;
 312:               }
 313: 
 314:             if (obj instanceof ObjectStreamClass)
 315:               {
 316:                 writeClassDescriptor((ObjectStreamClass) obj);
 317:                 break;
 318:               }
 319: 
 320:             Class clazz = obj.getClass();
 321:             ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
 322:             if (osc == null)
 323:               throw new NotSerializableException(clazz.getName());
 324: 
 325:             if (osc.isEnum())
 326:               {
 327:                 /* TC_ENUM classDesc newHandle enumConstantName */
 328:                 realOutput.writeByte(TC_ENUM);
 329:                 writeObject(osc);
 330:                 if (shared)
 331:                   assignNewHandle(obj);
 332:                 writeObject(((Enum) obj).name());
 333:                 break;
 334:               }
 335: 
 336:             if ((replacementEnabled || obj instanceof Serializable)
 337:                 && ! replaceDone)
 338:               {
 339:                 replacedObject = obj;
 340: 
 341:                 if (obj instanceof Serializable)
 342:                   {
 343:                     try
 344:                       {
 345:                         Method m = osc.writeReplaceMethod;
 346:                         if (m != null)
 347:                             obj = m.invoke(obj, new Object[0]);
 348:                       }
 349:                     catch (IllegalAccessException ignore)
 350:                       {
 351:                       }
 352:                     catch (InvocationTargetException ignore)
 353:                       {
 354:                       }
 355:                   }
 356: 
 357:                 if (replacementEnabled)
 358:                   obj = replaceObject(obj);
 359: 
 360:                 replaceDone = true;
 361:                 continue;
 362:               }
 363: 
 364:             if (obj instanceof String)
 365:               {
 366:                 String s = (String)obj;
 367:                 long l = realOutput.getUTFlength(s, 0, 0);
 368:                 if (l <= 65535)
 369:                   {
 370:                     realOutput.writeByte(TC_STRING);
 371:                     if (shared)
 372:                       assignNewHandle(obj);
 373:                     realOutput.writeUTFShort(s, (int)l);
 374:                   }
 375:                 else
 376:                   {
 377:                     realOutput.writeByte(TC_LONGSTRING);
 378:                     if (shared)
 379:                       assignNewHandle(obj);
 380:                     realOutput.writeUTFLong(s, l);
 381:                   }
 382:                 break;
 383:               }
 384: 
 385:             if (clazz.isArray ())
 386:               {
 387:                 realOutput.writeByte(TC_ARRAY);
 388:                 writeObject(osc);
 389:                 if (shared)
 390:                   assignNewHandle(obj);
 391:                 writeArraySizeAndElements(obj, clazz.getComponentType());
 392:                 break;
 393:               }
 394: 
 395:             realOutput.writeByte(TC_OBJECT);
 396:             writeObject(osc);
 397: 
 398:             if (shared)
 399:               if (replaceDone)
 400:                 assignNewHandle(replacedObject);
 401:               else
 402:                 assignNewHandle(obj);
 403: 
 404:             if (obj instanceof Externalizable)
 405:               {
 406:                 if (protocolVersion == PROTOCOL_VERSION_2)
 407:                   setBlockDataMode(true);
 408: 
 409:                 ((Externalizable)obj).writeExternal(this);
 410: 
 411:                 if (protocolVersion == PROTOCOL_VERSION_2)
 412:                   {
 413:                     setBlockDataMode(false);
 414:                     realOutput.writeByte(TC_ENDBLOCKDATA);
 415:                   }
 416: 
 417:                 break;
 418:               }
 419: 
 420:             if (obj instanceof Serializable)
 421:               {
 422:                 Object prevObject = this.currentObject;
 423:                 ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
 424:                 currentObject = obj;
 425:                 ObjectStreamClass[] hierarchy = osc.hierarchy();
 426: 
 427:                 for (int i = 0; i < hierarchy.length; i++)
 428:                   {
 429:                     currentObjectStreamClass = hierarchy[i];
 430: 
 431:                     fieldsAlreadyWritten = false;
 432:                     if (currentObjectStreamClass.hasWriteMethod())
 433:                       {
 434:                         if (dump)
 435:                           dumpElementln ("WRITE METHOD CALLED FOR: ", obj);
 436:                         setBlockDataMode(true);
 437:                         callWriteMethod(obj, currentObjectStreamClass);
 438:                         setBlockDataMode(false);
 439:                         realOutput.writeByte(TC_ENDBLOCKDATA);
 440:                         if (dump)
 441:                           dumpElementln ("WRITE ENDBLOCKDATA FOR: ", obj);
 442:                       }
 443:                     else
 444:                       {
 445:                         if (dump)
 446:                           dumpElementln ("WRITE FIELDS CALLED FOR: ", obj);
 447:                         writeFields(obj, currentObjectStreamClass);
 448:                       }
 449:                   }
 450: 
 451:                 this.currentObject = prevObject;
 452:                 this.currentObjectStreamClass = prevObjectStreamClass;
 453:                 currentPutField = null;
 454:                 break;
 455:               }
 456: 
 457:             throw new NotSerializableException(clazz.getName()
 458:                                                + " in "
 459:                                                + obj.getClass());
 460:           } // end pseudo-loop
 461:       }
 462:     catch (ObjectStreamException ose)
 463:       {
 464:         // Rethrow these are fatal.
 465:         throw ose;
 466:       }
 467:     catch (IOException e)
 468:       {
 469:         realOutput.writeByte(TC_EXCEPTION);
 470:         reset(true);
 471: 
 472:         setBlockDataMode(false);
 473:         try
 474:           {
 475:             if (DEBUG)
 476:               {
 477:                 e.printStackTrace(System.out);
 478:               }
 479:             writeObject(e);
 480:           }
 481:         catch (IOException ioe)
 482:           {
 483:             StreamCorruptedException ex =
 484:               new StreamCorruptedException
 485:               (ioe + " thrown while exception was being written to stream.");
 486:             if (DEBUG)
 487:               {
 488:                 ex.printStackTrace(System.out);
 489:               }
 490:             throw ex;
 491:           }
 492: 
 493:         reset (true);
 494: 
 495:       }
 496:     finally
 497:       {
 498:         isSerializing = was_serializing;
 499:         setBlockDataMode(old_mode);
 500:         depth -= 2;
 501: 
 502:         if (dump)
 503:           dumpElementln ("END: ", obj);
 504:       }
 505:   }
 506: 
 507:   protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException
 508:   {
 509:     if (osc.isProxyClass)
 510:       {
 511:         realOutput.writeByte(TC_PROXYCLASSDESC);
 512:         Class[] intfs = osc.forClass().getInterfaces();
 513:         realOutput.writeInt(intfs.length);
 514:         for (int i = 0; i < intfs.length; i++)
 515:           realOutput.writeUTF(intfs[i].getName());
 516: 
 517:         assignNewHandle(osc);
 518: 
 519:         boolean oldmode = setBlockDataMode(true);
 520:         annotateProxyClass(osc.forClass());
 521:         setBlockDataMode(oldmode);
 522:         realOutput.writeByte(TC_ENDBLOCKDATA);
 523:       }
 524:     else
 525:       {
 526:         realOutput.writeByte(TC_CLASSDESC);
 527:         realOutput.writeUTF(osc.getName());
 528:         if (osc.isEnum())
 529:           realOutput.writeLong(0L);
 530:         else
 531:           realOutput.writeLong(osc.getSerialVersionUID());
 532:         assignNewHandle(osc);
 533: 
 534:         int flags = osc.getFlags();
 535: 
 536:         if (protocolVersion == PROTOCOL_VERSION_2
 537:             && osc.isExternalizable())
 538:         flags |= SC_BLOCK_DATA;
 539: 
 540:         realOutput.writeByte(flags);
 541: 
 542:         ObjectStreamField[] fields = osc.fields;
 543: 
 544:         if (fields == ObjectStreamClass.INVALID_FIELDS)
 545:           throw new InvalidClassException
 546:                   (osc.getName(), "serialPersistentFields is invalid");
 547: 
 548:         realOutput.writeShort(fields.length);
 549: 
 550:         ObjectStreamField field;
 551:         for (int i = 0; i < fields.length; i++)
 552:           {
 553:             field = fields[i];
 554:             realOutput.writeByte(field.getTypeCode ());
 555:             realOutput.writeUTF(field.getName ());
 556: 
 557:             if (! field.isPrimitive())
 558:               writeObject(field.getTypeString());
 559:           }
 560: 
 561:         boolean oldmode = setBlockDataMode(true);
 562:         annotateClass(osc.forClass());
 563:         setBlockDataMode(oldmode);
 564:         realOutput.writeByte(TC_ENDBLOCKDATA);
 565:       }
 566: 
 567:     if (osc.isSerializable() || osc.isExternalizable())
 568:       writeObject(osc.getSuper());
 569:     else
 570:       writeObject(null);
 571:   }
 572: 
 573:   /**
 574:    * Writes the current objects non-transient, non-static fields from
 575:    * the current class to the underlying output stream.
 576:    *
 577:    * This method is intended to be called from within a object's
 578:    * <code>private void writeObject (ObjectOutputStream)</code>
 579:    * method.
 580:    *
 581:    * @exception NotActiveException This method was called from a
 582:    * context other than from the current object's and current class's
 583:    * <code>private void writeObject (ObjectOutputStream)</code>
 584:    * method.
 585:    *
 586:    * @exception IOException Exception from underlying
 587:    * <code>OutputStream</code>.
 588:    */
 589:   public void defaultWriteObject()
 590:     throws IOException, NotActiveException
 591:   {
 592:     markFieldsWritten();
 593:     writeFields(currentObject, currentObjectStreamClass);
 594:   }
 595: 
 596: 
 597:   private void markFieldsWritten() throws IOException
 598:   {
 599:     if (currentObject == null || currentObjectStreamClass == null)
 600:       throw new NotActiveException
 601:         ("defaultWriteObject called by non-active class and/or object");
 602: 
 603:     if (fieldsAlreadyWritten)
 604:       throw new IOException
 605:         ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once");
 606: 
 607:     fieldsAlreadyWritten = true;
 608:   }
 609: 
 610:   /**
 611:    * Resets stream to state equivalent to the state just after it was
 612:    * constructed.
 613:    *
 614:    * Causes all objects previously written to the stream to be
 615:    * forgotten.  A notification of this reset is also written to the
 616:    * underlying stream.
 617:    *
 618:    * @exception IOException Exception from underlying
 619:    * <code>OutputStream</code> or reset called while serialization is
 620:    * in progress.
 621:    */
 622:   public void reset() throws IOException
 623:   {
 624:     reset(false);
 625:   }
 626: 
 627: 
 628:   private void reset(boolean internal) throws IOException
 629:   {
 630:     if (!internal)
 631:       {
 632:         if (isSerializing)
 633:           throw new IOException("Reset called while serialization in progress");
 634: 
 635:         realOutput.writeByte(TC_RESET);
 636:       }
 637: 
 638:     clearHandles();
 639:   }
 640: 
 641: 
 642:   /**
 643:    * Informs this <code>ObjectOutputStream</code> to write data
 644:    * according to the specified protocol.  There are currently two
 645:    * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
 646:    * and <code>PROTOCOL_VERSION_2</code>.  This implementation writes
 647:    * data using <code>PROTOCOL_VERSION_2</code> by default, as is done
 648:    * since the JDK 1.2.
 649:    * <p>
 650:    * For an explanation of the differences between the two protocols
 651:    * see the Java Object Serialization Specification.
 652:    * </p>
 653:    *
 654:    * @param version the version to use.
 655:    *
 656:    * @throws IllegalArgumentException if <code>version</code> is not a valid
 657:    * protocol.
 658:    * @throws IllegalStateException if called after the first the first object
 659:    * was serialized.
 660:    * @throws IOException if an I/O error occurs.
 661:    *
 662:    * @see ObjectStreamConstants#PROTOCOL_VERSION_1
 663:    * @see ObjectStreamConstants#PROTOCOL_VERSION_2
 664:    *
 665:    * @since 1.2
 666:    */
 667:   public void useProtocolVersion(int version) throws IOException
 668:   {
 669:     if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
 670:       throw new IllegalArgumentException("Invalid protocol version requested.");
 671: 
 672:     if (nextOID != baseWireHandle)
 673:       throw new IllegalStateException("Protocol version cannot be changed "
 674:                                       + "after serialization started.");
 675: 
 676:     protocolVersion = version;
 677:   }
 678: 
 679:   /**
 680:    * An empty hook that allows subclasses to write extra information
 681:    * about classes to the stream.  This method is called the first
 682:    * time each class is seen, and after all of the standard
 683:    * information about the class has been written.
 684:    *
 685:    * @exception IOException Exception from underlying
 686:    * <code>OutputStream</code>.
 687:    *
 688:    * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
 689:    */
 690:   protected void annotateClass(Class<?> cl) throws IOException
 691:   {
 692:   }
 693: 
 694:   protected void annotateProxyClass(Class<?> cl) throws IOException
 695:   {
 696:   }
 697: 
 698:   /**
 699:    * Allows subclasses to replace objects that are written to the
 700:    * stream with other objects to be written in their place.  This
 701:    * method is called the first time each object is encountered
 702:    * (modulo reseting of the stream).
 703:    *
 704:    * This method must be enabled before it will be called in the
 705:    * serialization process.
 706:    *
 707:    * @exception IOException Exception from underlying
 708:    * <code>OutputStream</code>.
 709:    *
 710:    * @see #enableReplaceObject(boolean)
 711:    */
 712:   protected Object replaceObject(Object obj) throws IOException
 713:   {
 714:     return obj;
 715:   }
 716: 
 717: 
 718:   /**
 719:    * If <code>enable</code> is <code>true</code> and this object is
 720:    * trusted, then <code>replaceObject (Object)</code> will be called
 721:    * in subsequent calls to <code>writeObject (Object)</code>.
 722:    * Otherwise, <code>replaceObject (Object)</code> will not be called.
 723:    *
 724:    * @exception SecurityException This class is not trusted.
 725:    */
 726:   protected boolean enableReplaceObject(boolean enable)
 727:     throws SecurityException
 728:   {
 729:     if (enable)
 730:       {
 731:         SecurityManager sm = System.getSecurityManager();
 732:         if (sm != null)
 733:           sm.checkPermission(new SerializablePermission("enableSubstitution"));
 734:       }
 735: 
 736:     boolean old_val = replacementEnabled;
 737:     replacementEnabled = enable;
 738:     return old_val;
 739:   }
 740: 
 741: 
 742:   /**
 743:    * Writes stream magic and stream version information to the
 744:    * underlying stream.
 745:    *
 746:    * @exception IOException Exception from underlying
 747:    * <code>OutputStream</code>.
 748:    */
 749:   protected void writeStreamHeader() throws IOException
 750:   {
 751:     realOutput.writeShort(STREAM_MAGIC);
 752:     realOutput.writeShort(STREAM_VERSION);
 753:   }
 754: 
 755:   /**
 756:    * Protected constructor that allows subclasses to override
 757:    * serialization.  This constructor should be called by subclasses
 758:    * that wish to override <code>writeObject (Object)</code>.  This
 759:    * method does a security check <i>NOTE: currently not
 760:    * implemented</i>, then sets a flag that informs
 761:    * <code>writeObject (Object)</code> to call the subclasses
 762:    * <code>writeObjectOverride (Object)</code> method.
 763:    *
 764:    * @see #writeObjectOverride(Object)
 765:    */
 766:   protected ObjectOutputStream() throws IOException, SecurityException
 767:   {
 768:     SecurityManager sec_man = System.getSecurityManager ();
 769:     if (sec_man != null)
 770:       sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
 771:     useSubclassMethod = true;
 772:   }
 773: 
 774: 
 775:   /**
 776:    * This method allows subclasses to override the default
 777:    * serialization mechanism provided by
 778:    * <code>ObjectOutputStream</code>.  To make this method be used for
 779:    * writing objects, subclasses must invoke the 0-argument
 780:    * constructor on this class from there constructor.
 781:    *
 782:    * @see #ObjectOutputStream()
 783:    *
 784:    * @exception NotActiveException Subclass has arranged for this
 785:    * method to be called, but did not implement this method.
 786:    */
 787:   protected void writeObjectOverride(Object obj) throws NotActiveException,
 788:     IOException
 789:   {
 790:     throw new NotActiveException
 791:       ("Subclass of ObjectOutputStream must implement writeObjectOverride");
 792:   }
 793: 
 794: 
 795:   /**
 796:    * @see DataOutputStream#write(int)
 797:    */
 798:   public void write (int data) throws IOException
 799:   {
 800:     if (writeDataAsBlocks)
 801:       {
 802:         if (blockDataCount == BUFFER_SIZE)
 803:           drain();
 804: 
 805:         blockData[ blockDataCount++ ] = (byte)data;
 806:       }
 807:     else
 808:       realOutput.write(data);
 809:   }
 810: 
 811: 
 812:   /**
 813:    * @see DataOutputStream#write(byte[])
 814:    */
 815:   public void write(byte[] b) throws IOException
 816:   {
 817:     write(b, 0, b.length);
 818:   }
 819: 
 820: 
 821:   /**
 822:    * @see DataOutputStream#write(byte[],int,int)
 823:    */
 824:   public void write(byte[] b, int off, int len) throws IOException
 825:   {
 826:     if (writeDataAsBlocks)
 827:       {
 828:         if (len < 0)
 829:           throw new IndexOutOfBoundsException();
 830: 
 831:         if (blockDataCount + len < BUFFER_SIZE)
 832:           {
 833:             System.arraycopy(b, off, blockData, blockDataCount, len);
 834:             blockDataCount += len;
 835:           }
 836:         else
 837:           {
 838:             drain();
 839:             writeBlockDataHeader(len);
 840:             realOutput.write(b, off, len);
 841:           }
 842:       }
 843:     else
 844:       realOutput.write(b, off, len);
 845:   }
 846: 
 847: 
 848:   /**
 849:    * @see DataOutputStream#flush()
 850:    */
 851:   public void flush () throws IOException
 852:   {
 853:     drain();
 854:     realOutput.flush();
 855:   }
 856: 
 857: 
 858:   /**
 859:    * Causes the block-data buffer to be written to the underlying
 860:    * stream, but does not flush underlying stream.
 861:    *
 862:    * @exception IOException Exception from underlying
 863:    * <code>OutputStream</code>.
 864:    */
 865:   protected void drain() throws IOException
 866:   {
 867:     if (blockDataCount == 0)
 868:       return;
 869: 
 870:     if (writeDataAsBlocks)
 871:       writeBlockDataHeader(blockDataCount);
 872:     realOutput.write(blockData, 0, blockDataCount);
 873:     blockDataCount = 0;
 874:   }
 875: 
 876: 
 877:   /**
 878:    * @see java.io.DataOutputStream#close ()
 879:    */
 880:   public void close() throws IOException
 881:   {
 882:     flush();
 883:     realOutput.close();
 884:   }
 885: 
 886: 
 887:   /**
 888:    * @see java.io.DataOutputStream#writeBoolean (boolean)
 889:    */
 890:   public void writeBoolean(boolean data) throws IOException
 891:   {
 892:     blockDataOutput.writeBoolean(data);
 893:   }
 894: 
 895: 
 896:   /**
 897:    * @see java.io.DataOutputStream#writeByte (int)
 898:    */
 899:   public void writeByte(int data) throws IOException
 900:   {
 901:     blockDataOutput.writeByte(data);
 902:   }
 903: 
 904: 
 905:   /**
 906:    * @see java.io.DataOutputStream#writeShort (int)
 907:    */
 908:   public void writeShort (int data) throws IOException
 909:   {
 910:     blockDataOutput.writeShort(data);
 911:   }
 912: 
 913: 
 914:   /**
 915:    * @see java.io.DataOutputStream#writeChar (int)
 916:    */
 917:   public void writeChar(int data) throws IOException
 918:   {
 919:     blockDataOutput.writeChar(data);
 920:   }
 921: 
 922: 
 923:   /**
 924:    * @see java.io.DataOutputStream#writeInt (int)
 925:    */
 926:   public void writeInt(int data) throws IOException
 927:   {
 928:     blockDataOutput.writeInt(data);
 929:   }
 930: 
 931: 
 932:   /**
 933:    * @see java.io.DataOutputStream#writeLong (long)
 934:    */
 935:   public void writeLong(long data) throws IOException
 936:   {
 937:     blockDataOutput.writeLong(data);
 938:   }
 939: 
 940: 
 941:   /**
 942:    * @see java.io.DataOutputStream#writeFloat (float)
 943:    */
 944:   public void writeFloat(float data) throws IOException
 945:   {
 946:     blockDataOutput.writeFloat(data);
 947:   }
 948: 
 949: 
 950:   /**
 951:    * @see java.io.DataOutputStream#writeDouble (double)
 952:    */
 953:   public void writeDouble(double data) throws IOException
 954:   {
 955:     blockDataOutput.writeDouble(data);
 956:   }
 957: 
 958: 
 959:   /**
 960:    * @see java.io.DataOutputStream#writeBytes (java.lang.String)
 961:    */
 962:   public void writeBytes(String data) throws IOException
 963:   {
 964:     blockDataOutput.writeBytes(data);
 965:   }
 966: 
 967: 
 968:   /**
 969:    * @see java.io.DataOutputStream#writeChars (java.lang.String)
 970:    */
 971:   public void writeChars(String data) throws IOException
 972:   {
 973:     dataOutput.writeChars(data);
 974:   }
 975: 
 976: 
 977:   /**
 978:    * @see java.io.DataOutputStream#writeUTF (java.lang.String)
 979:    */
 980:   public void writeUTF(String data) throws IOException
 981:   {
 982:     dataOutput.writeUTF(data);
 983:   }
 984: 
 985: 
 986:   /**
 987:    * This class allows a class to specify exactly which fields should
 988:    * be written, and what values should be written for these fields.
 989:    *
 990:    * XXX: finish up comments
 991:    */
 992:   public abstract static class PutField
 993:   {
 994:     public abstract void put (String name, boolean value);
 995:     public abstract void put (String name, byte value);
 996:     public abstract void put (String name, char value);
 997:     public abstract void put (String name, double value);
 998:     public abstract void put (String name, float value);
 999:     public abstract void put (String name, int value);
1000:     public abstract void put (String name, long value);
1001:     public abstract void put (String name, short value);
1002:     public abstract void put (String name, Object value);
1003: 
1004:     /**
1005:      * @deprecated
1006:      */
1007:     public abstract void write (ObjectOutput out) throws IOException;
1008:   }
1009: 
1010:   public PutField putFields() throws IOException
1011:   {
1012:     if (currentPutField != null)
1013:       return currentPutField;
1014: 
1015:     currentPutField = new PutField()
1016:       {
1017:         private byte[] prim_field_data
1018:           = new byte[currentObjectStreamClass.primFieldSize];
1019:         private Object[] objs
1020:           = new Object[currentObjectStreamClass.objectFieldCount];
1021: 
1022:         private ObjectStreamField getField (String name)
1023:         {
1024:           ObjectStreamField field
1025:             = currentObjectStreamClass.getField(name);
1026: 
1027:           if (field == null)
1028:             throw new IllegalArgumentException("no such serializable field " + name);
1029: 
1030:           return field;
1031:         }
1032: 
1033:         public void put(String name, boolean value)
1034:         {
1035:           ObjectStreamField field = getField(name);
1036: 
1037:           checkType(field, 'Z');
1038:           prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
1039:         }
1040: 
1041:         public void put(String name, byte value)
1042:         {
1043:           ObjectStreamField field = getField(name);
1044: 
1045:           checkType(field, 'B');
1046:           prim_field_data[field.getOffset()] = value;
1047:         }
1048: 
1049:         public void put(String name, char value)
1050:         {
1051:           ObjectStreamField field = getField(name);
1052: 
1053:           checkType(field, 'C');
1054:           int off = field.getOffset();
1055:           prim_field_data[off++] = (byte)(value >>> 8);
1056:           prim_field_data[off] = (byte)value;
1057:         }
1058: 
1059:         public void put(String name, double value)
1060:         {
1061:           ObjectStreamField field = getField (name);
1062: 
1063:           checkType(field, 'D');
1064:           int off = field.getOffset();
1065:           long l_value = Double.doubleToLongBits (value);
1066:           prim_field_data[off++] = (byte)(l_value >>> 52);
1067:           prim_field_data[off++] = (byte)(l_value >>> 48);
1068:           prim_field_data[off++] = (byte)(l_value >>> 40);
1069:           prim_field_data[off++] = (byte)(l_value >>> 32);
1070:           prim_field_data[off++] = (byte)(l_value >>> 24);
1071:           prim_field_data[off++] = (byte)(l_value >>> 16);
1072:           prim_field_data[off++] = (byte)(l_value >>> 8);
1073:           prim_field_data[off] = (byte)l_value;
1074:         }
1075: 
1076:         public void put(String name, float value)
1077:         {
1078:           ObjectStreamField field = getField(name);
1079: 
1080:           checkType(field, 'F');
1081:           int off = field.getOffset();
1082:           int i_value = Float.floatToIntBits(value);
1083:           prim_field_data[off++] = (byte)(i_value >>> 24);
1084:           prim_field_data[off++] = (byte)(i_value >>> 16);
1085:           prim_field_data[off++] = (byte)(i_value >>> 8);
1086:           prim_field_data[off] = (byte)i_value;
1087:         }
1088: 
1089:         public void put(String name, int value)
1090:         {
1091:           ObjectStreamField field = getField(name);
1092:           checkType(field, 'I');
1093:           int off = field.getOffset();
1094:           prim_field_data[off++] = (byte)(value >>> 24);
1095:           prim_field_data[off++] = (byte)(value >>> 16);
1096:           prim_field_data[off++] = (byte)(value >>> 8);
1097:           prim_field_data[off] = (byte)value;
1098:         }
1099: 
1100:         public void put(String name, long value)
1101:         {
1102:           ObjectStreamField field = getField(name);
1103:           checkType(field, 'J');
1104:           int off = field.getOffset();
1105:           prim_field_data[off++] = (byte)(value >>> 52);
1106:           prim_field_data[off++] = (byte)(value >>> 48);
1107:           prim_field_data[off++] = (byte)(value >>> 40);
1108:           prim_field_data[off++] = (byte)(value >>> 32);
1109:           prim_field_data[off++] = (byte)(value >>> 24);
1110:           prim_field_data[off++] = (byte)(value >>> 16);
1111:           prim_field_data[off++] = (byte)(value >>> 8);
1112:           prim_field_data[off] = (byte)value;
1113:         }
1114: 
1115:         public void put(String name, short value)
1116:         {
1117:           ObjectStreamField field = getField(name);
1118:           checkType(field, 'S');
1119:           int off = field.getOffset();
1120:           prim_field_data[off++] = (byte)(value >>> 8);
1121:           prim_field_data[off] = (byte)value;
1122:         }
1123: 
1124:         public void put(String name, Object value)
1125:         {
1126:           ObjectStreamField field = getField(name);
1127: 
1128:           if (value != null &&
1129:               ! field.getType().isAssignableFrom(value.getClass ()))
1130:             throw new IllegalArgumentException("Class " + value.getClass() +
1131:                                                " cannot be cast to " + field.getType());
1132:           objs[field.getOffset()] = value;
1133:         }
1134: 
1135:         public void write(ObjectOutput out) throws IOException
1136:         {
1137:           // Apparently Block data is not used with PutField as per
1138:           // empirical evidence against JDK 1.2.  Also see Mauve test
1139:           // java.io.ObjectInputOutput.Test.GetPutField.
1140:           boolean oldmode = setBlockDataMode(false);
1141:           out.write(prim_field_data);
1142:           for (int i = 0; i < objs.length; ++ i)
1143:             out.writeObject(objs[i]);
1144:           setBlockDataMode(oldmode);
1145:         }
1146: 
1147:         private void checkType(ObjectStreamField field, char type)
1148:           throws IllegalArgumentException
1149:         {
1150:           if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0)
1151:               != type)
1152:             throw new IllegalArgumentException();
1153:         }
1154:       };
1155:     // end PutFieldImpl
1156: 
1157:     return currentPutField;
1158:   }
1159: 
1160: 
1161:   public void writeFields() throws IOException
1162:   {
1163:     if (currentPutField == null)
1164:       throw new NotActiveException("writeFields can only be called after putFields has been called");
1165: 
1166:     markFieldsWritten();
1167:     currentPutField.write(this);
1168:   }
1169: 
1170: 
1171:   // write out the block-data buffer, picking the correct header
1172:   // depending on the size of the buffer
1173:   private void writeBlockDataHeader(int size) throws IOException
1174:   {
1175:     if (size < 256)
1176:       {
1177:         realOutput.writeByte(TC_BLOCKDATA);
1178:         realOutput.write(size);
1179:       }
1180:     else
1181:       {
1182:         realOutput.writeByte(TC_BLOCKDATALONG);
1183:         realOutput.writeInt(size);
1184:       }
1185:   }
1186: 
1187: 
1188:   // lookup the handle for OBJ, return null if OBJ doesn't have a
1189:   // handle yet
1190:   private int findHandle(Object obj)
1191:   {
1192:     return OIDLookupTable.get(obj);
1193:   }
1194: 
1195: 
1196:   // assigns the next availible handle to OBJ
1197:   private int assignNewHandle(Object obj)
1198:   {
1199:     OIDLookupTable.put(obj, nextOID);
1200:     return nextOID++;
1201:   }
1202: 
1203: 
1204:   // resets mapping from objects to handles
1205:   private void clearHandles()
1206:   {
1207:     nextOID = baseWireHandle;
1208:     OIDLookupTable.clear();
1209:   }
1210: 
1211: 
1212:   // write out array size followed by each element of the array
1213:   private void writeArraySizeAndElements(Object array, Class clazz)
1214:     throws IOException
1215:   {
1216:     int length = Array.getLength(array);
1217: 
1218:     if (clazz.isPrimitive())
1219:       {
1220:         if (clazz == Boolean.TYPE)
1221:           {
1222:             boolean[] cast_array = (boolean[])array;
1223:             realOutput.writeInt (length);
1224:             for (int i = 0; i < length; i++)
1225:               realOutput.writeBoolean(cast_array[i]);
1226:             return;
1227:           }
1228:         if (clazz == Byte.TYPE)
1229:           {
1230:             byte[] cast_array = (byte[])array;
1231:             realOutput.writeInt(length);
1232:             realOutput.write(cast_array, 0, length);
1233:             return;
1234:           }
1235:         if (clazz == Character.TYPE)
1236:           {
1237:             char[] cast_array = (char[])array;
1238:             realOutput.writeInt(length);
1239:             for (int i = 0; i < length; i++)
1240:               realOutput.writeChar(cast_array[i]);
1241:             return;
1242:           }
1243:         if (clazz == Double.TYPE)
1244:           {
1245:             double[] cast_array = (double[])array;
1246:             realOutput.writeInt(length);
1247:             for (int i = 0; i < length; i++)
1248:               realOutput.writeDouble(cast_array[i]);
1249:             return;
1250:           }
1251:         if (clazz == Float.TYPE)
1252:           {
1253:             float[] cast_array = (float[])array;
1254:             realOutput.writeInt(length);
1255:             for (int i = 0; i < length; i++)
1256:               realOutput.writeFloat(cast_array[i]);
1257:             return;
1258:           }
1259:         if (clazz == Integer.TYPE)
1260:           {
1261:             int[] cast_array = (int[])array;
1262:             realOutput.writeInt(length);
1263:             for (int i = 0; i < length; i++)
1264:               realOutput.writeInt(cast_array[i]);
1265:             return;
1266:           }
1267:         if (clazz == Long.TYPE)
1268:           {
1269:             long[] cast_array = (long[])array;
1270:             realOutput.writeInt (length);
1271:             for (int i = 0; i < length; i++)
1272:               realOutput.writeLong(cast_array[i]);
1273:             return;
1274:           }
1275:         if (clazz == Short.TYPE)
1276:           {
1277:             short[] cast_array = (short[])array;
1278:             realOutput.writeInt (length);
1279:             for (int i = 0; i < length; i++)
1280:               realOutput.writeShort(cast_array[i]);
1281:             return;
1282:           }
1283:       }
1284:     else
1285:       {
1286:         Object[] cast_array = (Object[])array;
1287:         realOutput.writeInt(length);
1288:         for (int i = 0; i < length; i++)
1289:           writeObject(cast_array[i]);
1290:       }
1291:   }
1292: 
1293: 
1294: /* GCJ LOCAL */
1295:   // writes out FIELDS of OBJECT for the specified ObjectStreamClass.
1296:   // FIELDS are already supposed already to be in canonical order, but
1297:   // under some circumstances (to do with Proxies) this isn't the
1298:   // case, so we call ensureFieldsSet().
1299:   private void writeFields(Object obj, ObjectStreamClass osc)
1300:     throws IOException
1301:   {
1302:     osc.ensureFieldsSet(osc.forClass());
1303: /* END GCJ LOCAL */
1304: 
1305:     ObjectStreamField[] fields = osc.fields;
1306:     boolean oldmode = setBlockDataMode(false);
1307: 
1308:     try
1309:       {
1310:         writeFields(obj,fields);
1311:       }
1312:     catch (IllegalArgumentException _)
1313:       {
1314:         InvalidClassException e = new InvalidClassException
1315:           ("writing fields of class " + osc.forClass().getName());
1316:         e.initCause(_);
1317:         throw e;
1318:       }
1319:     catch (IOException e)
1320:       {
1321:         throw e;
1322:       }
1323:     catch (Exception _)
1324:       {
1325:         IOException e = new IOException("Unexpected exception " + _);
1326:         e.initCause(_);
1327:         throw(e);
1328:       }
1329: 
1330:     setBlockDataMode(oldmode);
1331:   }
1332: 
1333: 
1334:   /**
1335:    * Helper function for writeFields(Object,ObjectStreamClass): write
1336:    * fields from given fields array.  Pass exception on.
1337:    *
1338:    * @param obj the object to be written
1339:    *
1340:    * @param fields the fields of obj to be written.
1341:    */
1342:   private void writeFields(Object obj, ObjectStreamField[] fields)
1343:     throws
1344:       IllegalArgumentException, IllegalAccessException, IOException
1345:   {
1346:     for (int i = 0; i < fields.length; i++)
1347:       {
1348:         ObjectStreamField osf = fields[i];
1349:         Field field = osf.field;
1350: 
1351:         if (DEBUG && dump)
1352:           dumpElementln ("WRITE FIELD: " + osf.getName() + " type=" + osf.getType());
1353: 
1354:         switch (osf.getTypeCode())
1355:           {
1356:           case 'Z': realOutput.writeBoolean(field.getBoolean(obj)); break;
1357:           case 'B': realOutput.writeByte   (field.getByte   (obj)); break;
1358:           case 'S': realOutput.writeShort  (field.getShort  (obj)); break;
1359:           case 'C': realOutput.writeChar   (field.getChar   (obj)); break;
1360:           case 'I': realOutput.writeInt    (field.getInt    (obj)); break;
1361:           case 'F': realOutput.writeFloat  (field.getFloat  (obj)); break;
1362:           case 'J': realOutput.writeLong   (field.getLong   (obj)); break;
1363:           case 'D': realOutput.writeDouble (field.getDouble (obj)); break;
1364:           case 'L':
1365:           case '[':            writeObject (field.get       (obj)); break;
1366:           default:
1367:             throw new IOException("Unexpected type code " + osf.getTypeCode());
1368:           }
1369:       }
1370:   }
1371: 
1372: 
1373:   // Toggles writing primitive data to block-data buffer.
1374:   // Package-private to avoid a trampoline constructor.
1375:   boolean setBlockDataMode(boolean on) throws IOException
1376:   {
1377:     if (on == writeDataAsBlocks)
1378:       return on;
1379: 
1380:     drain();
1381:     boolean oldmode = writeDataAsBlocks;
1382:     writeDataAsBlocks = on;
1383: 
1384:     if (on)
1385:       dataOutput = blockDataOutput;
1386:     else
1387:       dataOutput = realOutput;
1388: 
1389:     return oldmode;
1390:   }
1391: 
1392: 
1393:   private void callWriteMethod(Object obj, ObjectStreamClass osc)
1394:     throws IOException
1395:   {
1396:     currentPutField = null;
1397:     try
1398:       {
1399:         Object args[] = {this};
1400:         osc.writeObjectMethod.invoke(obj, args);
1401:       }
1402:     catch (InvocationTargetException x)
1403:       {
1404:         /* Rethrow if possible. */
1405:         Throwable exception = x.getTargetException();
1406:         if (exception instanceof RuntimeException)
1407:           throw (RuntimeException) exception;
1408:         if (exception instanceof IOException)
1409:           throw (IOException) exception;
1410: 
1411:         IOException ioe
1412:           = new IOException("Exception thrown from writeObject() on " +
1413:                             osc.forClass().getName() + ": " +
1414:                             exception.getClass().getName());
1415:         ioe.initCause(exception);
1416:         throw ioe;
1417:       }
1418:     catch (Exception x)
1419:       {
1420:         IOException ioe
1421:           = new IOException("Failure invoking writeObject() on " +
1422:                             osc.forClass().getName() + ": " +
1423:                             x.getClass().getName());
1424:         ioe.initCause(x);
1425:         throw ioe;
1426:       }
1427:   }
1428: 
1429:   private void dumpElementln (String msg, Object obj)
1430:   {
1431:     try
1432:       {
1433:         for (int i = 0; i < depth; i++)
1434:           System.out.print (" ");
1435:         System.out.print (Thread.currentThread() + ": ");
1436:         System.out.print (msg);
1437:         if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
1438:           System.out.print (obj.getClass());
1439:         else
1440:           System.out.print (obj);
1441:       }
1442:     catch (Exception _)
1443:       {
1444:       }
1445:     finally
1446:       {
1447:         System.out.println ();
1448:       }
1449:   }
1450: 
1451:   private void dumpElementln (String msg)
1452:   {
1453:     for (int i = 0; i < depth; i++)
1454:       System.out.print (" ");
1455:     System.out.print (Thread.currentThread() + ": ");
1456:     System.out.println(msg);
1457:   }
1458: 
1459:   // this value comes from 1.2 spec, but is used in 1.1 as well
1460:   private static final int BUFFER_SIZE = 1024;
1461: 
1462:   private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
1463: 
1464:   private DataOutputStream dataOutput;
1465:   private boolean writeDataAsBlocks;
1466:   private DataOutputStream realOutput;
1467:   private DataOutputStream blockDataOutput;
1468:   private byte[] blockData;
1469:   private int blockDataCount;
1470:   private Object currentObject;
1471:   // Package-private to avoid a trampoline.
1472:   ObjectStreamClass currentObjectStreamClass;
1473:   private PutField currentPutField;
1474:   private boolean fieldsAlreadyWritten;
1475:   private boolean replacementEnabled;
1476:   private boolean isSerializing;
1477:   private int nextOID;
1478:   private ObjectIdentityMap2Int OIDLookupTable;
1479:   private int protocolVersion;
1480:   private boolean useSubclassMethod;
1481:   private SetAccessibleAction setAccessible = new SetAccessibleAction();
1482: 
1483:   // The nesting depth for debugging output
1484:   private int depth = 0;
1485: 
1486:   // Set if we're generating debugging dumps
1487:   private boolean dump = false;
1488: 
1489:   private static final boolean DEBUG = false;
1490: }