KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > io > ObjectOutputStream


1 /*
2  * @(#)ObjectOutputStream.java 1.147 06/07/26
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.io;
9
10 import java.io.ObjectStreamClass.WeakClassKey JavaDoc;
11 import java.lang.ref.ReferenceQueue JavaDoc;
12 import java.security.AccessController JavaDoc;
13 import java.security.PrivilegedAction JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.concurrent.ConcurrentHashMap JavaDoc;
16 import java.util.concurrent.ConcurrentMap JavaDoc;
17 import static java.io.ObjectStreamClass.processQueue JavaDoc;
18
19 /**
20  * An ObjectOutputStream writes primitive data types and graphs of Java objects
21  * to an OutputStream. The objects can be read (reconstituted) using an
22  * ObjectInputStream. Persistent storage of objects can be accomplished by
23  * using a file for the stream. If the stream is a network socket stream, the
24  * objects can be reconstituted on another host or in another process.
25  *
26  * <p>Only objects that support the java.io.Serializable interface can be
27  * written to streams. The class of each serializable object is encoded
28  * including the class name and signature of the class, the values of the
29  * object's fields and arrays, and the closure of any other objects referenced
30  * from the initial objects.
31  *
32  * <p>The method writeObject is used to write an object to the stream. Any
33  * object, including Strings and arrays, is written with writeObject. Multiple
34  * objects or primitives can be written to the stream. The objects must be
35  * read back from the corresponding ObjectInputstream with the same types and
36  * in the same order as they were written.
37  *
38  * <p>Primitive data types can also be written to the stream using the
39  * appropriate methods from DataOutput. Strings can also be written using the
40  * writeUTF method.
41  *
42  * <p>The default serialization mechanism for an object writes the class of the
43  * object, the class signature, and the values of all non-transient and
44  * non-static fields. References to other objects (except in transient or
45  * static fields) cause those objects to be written also. Multiple references
46  * to a single object are encoded using a reference sharing mechanism so that
47  * graphs of objects can be restored to the same shape as when the original was
48  * written.
49  *
50  * <p>For example to write an object that can be read by the example in
51  * ObjectInputStream:
52  * <br>
53  * <pre>
54  * FileOutputStream fos = new FileOutputStream("t.tmp");
55  * ObjectOutputStream oos = new ObjectOutputStream(fos);
56  *
57  * oos.writeInt(12345);
58  * oos.writeObject("Today");
59  * oos.writeObject(new Date());
60  *
61  * oos.close();
62  * </pre>
63  *
64  * <p>Classes that require special handling during the serialization and
65  * deserialization process must implement special methods with these exact
66  * signatures:
67  * <br>
68  * <pre>
69  * private void readObject(java.io.ObjectInputStream stream)
70  * throws IOException, ClassNotFoundException;
71  * private void writeObject(java.io.ObjectOutputStream stream)
72  * throws IOException
73  * </pre>
74  *
75  * <p>The writeObject method is responsible for writing the state of the object
76  * for its particular class so that the corresponding readObject method can
77  * restore it. The method does not need to concern itself with the state
78  * belonging to the object's superclasses or subclasses. State is saved by
79  * writing the individual fields to the ObjectOutputStream using the
80  * writeObject method or by using the methods for primitive data types
81  * supported by DataOutput.
82  *
83  * <p>Serialization does not write out the fields of any object that does not
84  * implement the java.io.Serializable interface. Subclasses of Objects that
85  * are not serializable can be serializable. In this case the non-serializable
86  * class must have a no-arg constructor to allow its fields to be initialized.
87  * In this case it is the responsibility of the subclass to save and restore
88  * the state of the non-serializable class. It is frequently the case that the
89  * fields of that class are accessible (public, package, or protected) or that
90  * there are get and set methods that can be used to restore the state.
91  *
92  * <p>Serialization of an object can be prevented by implementing writeObject
93  * and readObject methods that throw the NotSerializableException. The
94  * exception will be caught by the ObjectOutputStream and abort the
95  * serialization process.
96  *
97  * <p>Implementing the Externalizable interface allows the object to assume
98  * complete control over the contents and format of the object's serialized
99  * form. The methods of the Externalizable interface, writeExternal and
100  * readExternal, are called to save and restore the objects state. When
101  * implemented by a class they can write and read their own state using all of
102  * the methods of ObjectOutput and ObjectInput. It is the responsibility of
103  * the objects to handle any versioning that occurs.
104  *
105  * <p>Enum constants are serialized differently than ordinary serializable or
106  * externalizable objects. The serialized form of an enum constant consists
107  * solely of its name; field values of the constant are not transmitted. To
108  * serialize an enum constant, ObjectOutputStream writes the string returned by
109  * the constant's name method. Like other serializable or externalizable
110  * objects, enum constants can function as the targets of back references
111  * appearing subsequently in the serialization stream. The process by which
112  * enum constants are serialized cannot be customized; any class-specific
113  * writeObject and writeReplace methods defined by enum types are ignored
114  * during serialization. Similarly, any serialPersistentFields or
115  * serialVersionUID field declarations are also ignored--all enum types have a
116  * fixed serialVersionUID of 0L.
117  *
118  * <p>Primitive data, excluding serializable fields and externalizable data, is
119  * written to the ObjectOutputStream in block-data records. A block data record
120  * is composed of a header and data. The block data header consists of a marker
121  * and the number of bytes to follow the header. Consecutive primitive data
122  * writes are merged into one block-data record. The blocking factor used for
123  * a block-data record will be 1024 bytes. Each block-data record will be
124  * filled up to 1024 bytes, or be written whenever there is a termination of
125  * block-data mode. Calls to the ObjectOutputStream methods writeObject,
126  * defaultWriteObject and writeFields initially terminate any existing
127  * block-data record.
128  *
129  * @author Mike Warres
130  * @author Roger Riggs
131  * @version 1.147, 06/07/26
132  * @see java.io.DataOutput
133  * @see java.io.ObjectInputStream
134  * @see java.io.Serializable
135  * @see java.io.Externalizable
136  * @see <a HREF="../../../guide/serialization/spec/output.doc.html">Object Serialization Specification, Section 2, Object Output Classes</a>
137  * @since JDK1.1
138  */

139 public class ObjectOutputStream
140     extends OutputStream JavaDoc implements ObjectOutput JavaDoc, ObjectStreamConstants JavaDoc
141 {
142     private static class Caches {
143     /** cache of subclass security audit results */
144     static final ConcurrentMap JavaDoc<WeakClassKey,Boolean JavaDoc> subclassAudits =
145         new ConcurrentHashMap JavaDoc<WeakClassKey,Boolean JavaDoc>();
146
147     /** queue for WeakReferences to audited subclasses */
148     static final ReferenceQueue JavaDoc<Class JavaDoc<?>> subclassAuditsQueue =
149         new ReferenceQueue JavaDoc<Class JavaDoc<?>>();
150     }
151
152     /** filter stream for handling block data conversion */
153     private final BlockDataOutputStream bout;
154     /** obj -> wire handle map */
155     private final HandleTable handles;
156     /** obj -> replacement obj map */
157     private final ReplaceTable subs;
158     /** stream protocol version */
159     private int protocol = PROTOCOL_VERSION_2;
160     /** recursion depth */
161     private int depth;
162
163     /** buffer for writing primitive field values */
164     private byte[] primVals;
165
166     /** if true, invoke writeObjectOverride() instead of writeObject() */
167     private final boolean enableOverride;
168     /** if true, invoke replaceObject() */
169     private boolean enableReplace;
170
171     // values below valid only during upcalls to writeObject()/writeExternal()
172
/** object currently being serialized */
173     private Object JavaDoc curObj;
174     /** descriptor for current class (null if in writeExternal()) */
175     private ObjectStreamClass JavaDoc curDesc;
176     /** current PutField object */
177     private PutFieldImpl curPut;
178
179     /**
180      * Creates an ObjectOutputStream that writes to the specified OutputStream.
181      * This constructor writes the serialization stream header to the
182      * underlying stream; callers may wish to flush the stream immediately to
183      * ensure that constructors for receiving ObjectInputStreams will not block
184      * when reading the header.
185      *
186      * <p>If a security manager is installed, this constructor will check for
187      * the "enableSubclassImplementation" SerializablePermission when invoked
188      * directly or indirectly by the constructor of a subclass which overrides
189      * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
190      * methods.
191      *
192      * @param out output stream to write to
193      * @throws IOException if an I/O error occurs while writing stream header
194      * @throws SecurityException if untrusted subclass illegally overrides
195      * security-sensitive methods
196      * @throws NullPointerException if <code>out</code> is <code>null</code>
197      * @see ObjectOutputStream#ObjectOutputStream()
198      * @see ObjectOutputStream#putFields()
199      * @see ObjectInputStream#ObjectInputStream(InputStream)
200      */

201     public ObjectOutputStream(OutputStream JavaDoc out) throws IOException JavaDoc {
202     verifySubclass();
203     bout = new BlockDataOutputStream(out);
204     handles = new HandleTable(10, (float) 3.00);
205     subs = new ReplaceTable(10, (float) 3.00);
206     enableOverride = false;
207     writeStreamHeader();
208     bout.setBlockDataMode(true);
209     }
210
211     /**
212      * Provide a way for subclasses that are completely reimplementing
213      * ObjectOutputStream to not have to allocate private data just used by
214      * this implementation of ObjectOutputStream.
215      *
216      * <p>If there is a security manager installed, this method first calls the
217      * security manager's <code>checkPermission</code> method with a
218      * <code>SerializablePermission("enableSubclassImplementation")</code>
219      * permission to ensure it's ok to enable subclassing.
220      *
221      * @throws SecurityException if a security manager exists and its
222      * <code>checkPermission</code> method denies enabling
223      * subclassing.
224      * @see SecurityManager#checkPermission
225      * @see java.io.SerializablePermission
226      */

227     protected ObjectOutputStream() throws IOException JavaDoc, SecurityException JavaDoc {
228     SecurityManager JavaDoc sm = System.getSecurityManager();
229     if (sm != null) {
230         sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
231     }
232     bout = null;
233     handles = null;
234     subs = null;
235     enableOverride = true;
236     }
237
238     /**
239      * Specify stream protocol version to use when writing the stream.
240      *
241      * <p>This routine provides a hook to enable the current version of
242      * Serialization to write in a format that is backwards compatible to a
243      * previous version of the stream format.
244      *
245      * <p>Every effort will be made to avoid introducing additional
246      * backwards incompatibilities; however, sometimes there is no
247      * other alternative.
248      *
249      * @param version use ProtocolVersion from java.io.ObjectStreamConstants.
250      * @throws IllegalStateException if called after any objects
251      * have been serialized.
252      * @throws IllegalArgumentException if invalid version is passed in.
253      * @throws IOException if I/O errors occur
254      * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
255      * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
256      * @since 1.2
257      */

258     public void useProtocolVersion(int version) throws IOException JavaDoc {
259     if (handles.size() != 0) {
260         // REMIND: implement better check for pristine stream?
261
throw new IllegalStateException JavaDoc("stream non-empty");
262     }
263     switch (version) {
264         case PROTOCOL_VERSION_1:
265         case PROTOCOL_VERSION_2:
266         protocol = version;
267         break;
268         
269         default:
270         throw new IllegalArgumentException JavaDoc(
271             "unknown version: " + version);
272     }
273     }
274
275     /**
276      * Write the specified object to the ObjectOutputStream. The class of the
277      * object, the signature of the class, and the values of the non-transient
278      * and non-static fields of the class and all of its supertypes are
279      * written. Default serialization for a class can be overridden using the
280      * writeObject and the readObject methods. Objects referenced by this
281      * object are written transitively so that a complete equivalent graph of
282      * objects can be reconstructed by an ObjectInputStream.
283      *
284      * <p>Exceptions are thrown for problems with the OutputStream and for
285      * classes that should not be serialized. All exceptions are fatal to the
286      * OutputStream, which is left in an indeterminate state, and it is up to
287      * the caller to ignore or recover the stream state.
288      *
289      * @throws InvalidClassException Something is wrong with a class used by
290      * serialization.
291      * @throws NotSerializableException Some object to be serialized does not
292      * implement the java.io.Serializable interface.
293      * @throws IOException Any exception thrown by the underlying
294      * OutputStream.
295      */

296     public final void writeObject(Object JavaDoc obj) throws IOException JavaDoc {
297     if (enableOverride) {
298         writeObjectOverride(obj);
299         return;
300     }
301     try {
302         writeObject0(obj, false);
303     } catch (IOException JavaDoc ex) {
304         if (depth == 0) {
305         writeFatalException(ex);
306         }
307         throw ex;
308     }
309     }
310
311     /**
312      * Method used by subclasses to override the default writeObject method.
313      * This method is called by trusted subclasses of ObjectInputStream that
314      * constructed ObjectInputStream using the protected no-arg constructor.
315      * The subclass is expected to provide an override method with the modifier
316      * "final".
317      *
318      * @param obj object to be written to the underlying stream
319      * @throws IOException if there are I/O errors while writing to the
320      * underlying stream
321      * @see #ObjectOutputStream()
322      * @see #writeObject(Object)
323      * @since 1.2
324      */

325     protected void writeObjectOverride(Object JavaDoc obj) throws IOException JavaDoc {
326     }
327
328     /**
329      * Writes an "unshared" object to the ObjectOutputStream. This method is
330      * identical to writeObject, except that it always writes the given object
331      * as a new, unique object in the stream (as opposed to a back-reference
332      * pointing to a previously serialized instance). Specifically:
333      * <ul>
334      * <li>An object written via writeUnshared is always serialized in the
335      * same manner as a newly appearing object (an object that has not
336      * been written to the stream yet), regardless of whether or not the
337      * object has been written previously.
338      *
339      * <li>If writeObject is used to write an object that has been previously
340      * written with writeUnshared, the previous writeUnshared operation
341      * is treated as if it were a write of a separate object. In other
342      * words, ObjectOutputStream will never generate back-references to
343      * object data written by calls to writeUnshared.
344      * </ul>
345      * While writing an object via writeUnshared does not in itself guarantee a
346      * unique reference to the object when it is deserialized, it allows a
347      * single object to be defined multiple times in a stream, so that multiple
348      * calls to readUnshared by the receiver will not conflict. Note that the
349      * rules described above only apply to the base-level object written with
350      * writeUnshared, and not to any transitively referenced sub-objects in the
351      * object graph to be serialized.
352      *
353      * <p>ObjectOutputStream subclasses which override this method can only be
354      * constructed in security contexts possessing the
355      * "enableSubclassImplementation" SerializablePermission; any attempt to
356      * instantiate such a subclass without this permission will cause a
357      * SecurityException to be thrown.
358      *
359      * @param obj object to write to stream
360      * @throws NotSerializableException if an object in the graph to be
361      * serialized does not implement the Serializable interface
362      * @throws InvalidClassException if a problem exists with the class of an
363      * object to be serialized
364      * @throws IOException if an I/O error occurs during serialization
365      */

366     public void writeUnshared(Object JavaDoc obj) throws IOException JavaDoc {
367     try {
368         writeObject0(obj, true);
369     } catch (IOException JavaDoc ex) {
370         if (depth == 0) {
371         writeFatalException(ex);
372         }
373         throw ex;
374     }
375     }
376
377     /**
378      * Write the non-static and non-transient fields of the current class to
379      * this stream. This may only be called from the writeObject method of the
380      * class being serialized. It will throw the NotActiveException if it is
381      * called otherwise.
382      *
383      * @throws IOException if I/O errors occur while writing to the underlying
384      * <code>OutputStream</code>
385      */

386     public void defaultWriteObject() throws IOException JavaDoc {
387     if (curObj == null || curDesc == null) {
388         throw new NotActiveException JavaDoc("not in call to writeObject");
389     }
390     bout.setBlockDataMode(false);
391     defaultWriteFields(curObj, curDesc);
392     bout.setBlockDataMode(true);
393     }
394     
395     /**
396      * Retrieve the object used to buffer persistent fields to be written to
397      * the stream. The fields will be written to the stream when writeFields
398      * method is called.
399      *
400      * @return an instance of the class Putfield that holds the serializable
401      * fields
402      * @throws IOException if I/O errors occur
403      * @since 1.2
404      */

405     public ObjectOutputStream.PutField JavaDoc putFields() throws IOException JavaDoc {
406     if (curPut == null) {
407         if (curObj == null || curDesc == null) {
408         throw new NotActiveException JavaDoc("not in call to writeObject");
409         }
410         curPut = new PutFieldImpl(curDesc);
411     }
412     return curPut;
413     }
414
415     /**
416      * Write the buffered fields to the stream.
417      *
418      * @throws IOException if I/O errors occur while writing to the underlying
419      * stream
420      * @throws NotActiveException Called when a classes writeObject method was
421      * not called to write the state of the object.
422      * @since 1.2
423      */

424     public void writeFields() throws IOException JavaDoc {
425     if (curPut == null) {
426         throw new NotActiveException JavaDoc("no current PutField object");
427     }
428     bout.setBlockDataMode(false);
429     curPut.writeFields();
430     bout.setBlockDataMode(true);
431     }
432
433     /**
434      * Reset will disregard the state of any objects already written to the
435      * stream. The state is reset to be the same as a new ObjectOutputStream.
436      * The current point in the stream is marked as reset so the corresponding
437      * ObjectInputStream will be reset at the same point. Objects previously
438      * written to the stream will not be refered to as already being in the
439      * stream. They will be written to the stream again.
440      *
441      * @throws IOException if reset() is invoked while serializing an object.
442      */

443     public void reset() throws IOException JavaDoc {
444     if (depth != 0) {
445         throw new IOException JavaDoc("stream active");
446     }
447     bout.setBlockDataMode(false);
448     bout.writeByte(TC_RESET);
449     clear();
450     bout.setBlockDataMode(true);
451     }
452
453     /**
454      * Subclasses may implement this method to allow class data to be stored in
455      * the stream. By default this method does nothing. The corresponding
456      * method in ObjectInputStream is resolveClass. This method is called
457      * exactly once for each unique class in the stream. The class name and
458      * signature will have already been written to the stream. This method may
459      * make free use of the ObjectOutputStream to save any representation of
460      * the class it deems suitable (for example, the bytes of the class file).
461      * The resolveClass method in the corresponding subclass of
462      * ObjectInputStream must read and use any data or objects written by
463      * annotateClass.
464      *
465      * @param cl the class to annotate custom data for
466      * @throws IOException Any exception thrown by the underlying
467      * OutputStream.
468      */

469     protected void annotateClass(Class JavaDoc<?> cl) throws IOException JavaDoc {
470     }
471
472     /**
473      * Subclasses may implement this method to store custom data in the stream
474      * along with descriptors for dynamic proxy classes.
475      *
476      * <p>This method is called exactly once for each unique proxy class
477      * descriptor in the stream. The default implementation of this method in
478      * <code>ObjectOutputStream</code> does nothing.
479      *
480      * <p>The corresponding method in <code>ObjectInputStream</code> is
481      * <code>resolveProxyClass</code>. For a given subclass of
482      * <code>ObjectOutputStream</code> that overrides this method, the
483      * <code>resolveProxyClass</code> method in the corresponding subclass of
484      * <code>ObjectInputStream</code> must read any data or objects written by
485      * <code>annotateProxyClass</code>.
486      *
487      * @param cl the proxy class to annotate custom data for
488      * @throws IOException any exception thrown by the underlying
489      * <code>OutputStream</code>
490      * @see ObjectInputStream#resolveProxyClass(String[])
491      * @since 1.3
492      */

493     protected void annotateProxyClass(Class JavaDoc<?> cl) throws IOException JavaDoc {
494     }
495
496     /**
497      * This method will allow trusted subclasses of ObjectOutputStream to
498      * substitute one object for another during serialization. Replacing
499      * objects is disabled until enableReplaceObject is called. The
500      * enableReplaceObject method checks that the stream requesting to do
501      * replacement can be trusted. The first occurrence of each object written
502      * into the serialization stream is passed to replaceObject. Subsequent
503      * references to the object are replaced by the object returned by the
504      * original call to replaceObject. To ensure that the private state of
505      * objects is not unintentionally exposed, only trusted streams may use
506      * replaceObject.
507      *
508      * <p>The ObjectOutputStream.writeObject method takes a parameter of type
509      * Object (as opposed to type Serializable) to allow for cases where
510      * non-serializable objects are replaced by serializable ones.
511      *
512      * <p>When a subclass is replacing objects it must insure that either a
513      * complementary substitution must be made during deserialization or that
514      * the substituted object is compatible with every field where the
515      * reference will be stored. Objects whose type is not a subclass of the
516      * type of the field or array element abort the serialization by raising an
517      * exception and the object is not be stored.
518      *
519      * <p>This method is called only once when each object is first
520      * encountered. All subsequent references to the object will be redirected
521      * to the new object. This method should return the object to be
522      * substituted or the original object.
523      *
524      * <p>Null can be returned as the object to be substituted, but may cause
525      * NullReferenceException in classes that contain references to the
526      * original object since they may be expecting an object instead of
527      * null.
528      *
529      * @param obj the object to be replaced
530      * @return the alternate object that replaced the specified one
531      * @throws IOException Any exception thrown by the underlying
532      * OutputStream.
533      */

534     protected Object JavaDoc replaceObject(Object JavaDoc obj) throws IOException JavaDoc {
535     return obj;
536     }
537
538     /**
539      * Enable the stream to do replacement of objects in the stream. When
540      * enabled, the replaceObject method is called for every object being
541      * serialized.
542      *
543      * <p>If <code>enable</code> is true, and there is a security manager
544      * installed, this method first calls the security manager's
545      * <code>checkPermission</code> method with a
546      * <code>SerializablePermission("enableSubstitution")</code> permission to
547      * ensure it's ok to enable the stream to do replacement of objects in the
548      * stream.
549      *
550      * @param enable boolean parameter to enable replacement of objects
551      * @return the previous setting before this method was invoked
552      * @throws SecurityException if a security manager exists and its
553      * <code>checkPermission</code> method denies enabling the stream
554      * to do replacement of objects in the stream.
555      * @see SecurityManager#checkPermission
556      * @see java.io.SerializablePermission
557      */

558     protected boolean enableReplaceObject(boolean enable)
559     throws SecurityException JavaDoc
560     {
561     if (enable == enableReplace) {
562         return enable;
563     }
564     if (enable) {
565         SecurityManager JavaDoc sm = System.getSecurityManager();
566         if (sm != null) {
567         sm.checkPermission(SUBSTITUTION_PERMISSION);
568         }
569     }
570     enableReplace = enable;
571     return !enableReplace;
572     }
573
574     /**
575      * The writeStreamHeader method is provided so subclasses can append or
576      * prepend their own header to the stream. It writes the magic number and
577      * version to the stream.
578      *
579      * @throws IOException if I/O errors occur while writing to the underlying
580      * stream
581      */

582     protected void writeStreamHeader() throws IOException JavaDoc {
583     bout.writeShort(STREAM_MAGIC);
584     bout.writeShort(STREAM_VERSION);
585     }
586
587     /**
588      * Write the specified class descriptor to the ObjectOutputStream. Class
589      * descriptors are used to identify the classes of objects written to the
590      * stream. Subclasses of ObjectOutputStream may override this method to
591      * customize the way in which class descriptors are written to the
592      * serialization stream. The corresponding method in ObjectInputStream,
593      * <code>readClassDescriptor</code>, should then be overridden to
594      * reconstitute the class descriptor from its custom stream representation.
595      * By default, this method writes class descriptors according to the format
596      * defined in the Object Serialization specification.
597      *
598      * <p>Note that this method will only be called if the ObjectOutputStream
599      * is not using the old serialization stream format (set by calling
600      * ObjectOutputStream's <code>useProtocolVersion</code> method). If this
601      * serialization stream is using the old format
602      * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written
603      * internally in a manner that cannot be overridden or customized.
604      *
605      * @param desc class descriptor to write to the stream
606      * @throws IOException If an I/O error has occurred.
607      * @see java.io.ObjectInputStream#readClassDescriptor()
608      * @see #useProtocolVersion(int)
609      * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
610      * @since 1.3
611      */

612     protected void writeClassDescriptor(ObjectStreamClass JavaDoc desc)
613     throws IOException JavaDoc
614     {
615     desc.writeNonProxy(this);
616     }
617
618     /**
619      * Writes a byte. This method will block until the byte is actually
620      * written.
621      *
622      * @param val the byte to be written to the stream
623      * @throws IOException If an I/O error has occurred.
624      */

625     public void write(int val) throws IOException JavaDoc {
626     bout.write(val);
627     }
628
629     /**
630      * Writes an array of bytes. This method will block until the bytes are
631      * actually written.
632      *
633      * @param buf the data to be written
634      * @throws IOException If an I/O error has occurred.
635      */

636     public void write(byte[] buf) throws IOException JavaDoc {
637     bout.write(buf, 0, buf.length, false);
638     }
639
640     /**
641      * Writes a sub array of bytes.
642      *
643      * @param buf the data to be written
644      * @param off the start offset in the data
645      * @param len the number of bytes that are written
646      * @throws IOException If an I/O error has occurred.
647      */

648     public void write(byte[] buf, int off, int len) throws IOException JavaDoc {
649     if (buf == null) {
650         throw new NullPointerException JavaDoc();
651     }
652     int endoff = off + len;
653     if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
654         throw new IndexOutOfBoundsException JavaDoc();
655     }
656     bout.write(buf, off, len, false);
657     }
658
659     /**
660      * Flushes the stream. This will write any buffered output bytes and flush
661      * through to the underlying stream.
662      *
663      * @throws IOException If an I/O error has occurred.
664      */

665     public void flush() throws IOException JavaDoc {
666     bout.flush();
667     }
668
669     /**
670      * Drain any buffered data in ObjectOutputStream. Similar to flush but
671      * does not propagate the flush to the underlying stream.
672      *
673      * @throws IOException if I/O errors occur while writing to the underlying
674      * stream
675      */

676     protected void drain() throws IOException JavaDoc {
677     bout.drain();
678     }
679
680     /**
681      * Closes the stream. This method must be called to release any resources
682      * associated with the stream.
683      *
684      * @throws IOException If an I/O error has occurred.
685      */

686     public void close() throws IOException JavaDoc {
687     flush();
688     clear();
689     bout.close();
690     }
691
692     /**
693      * Writes a boolean.
694      *
695      * @param val the boolean to be written
696      * @throws IOException if I/O errors occur while writing to the underlying
697      * stream
698      */

699     public void writeBoolean(boolean val) throws IOException JavaDoc {
700     bout.writeBoolean(val);
701     }
702
703     /**
704      * Writes an 8 bit byte.
705      *
706      * @param val the byte value to be written
707      * @throws IOException if I/O errors occur while writing to the underlying
708      * stream
709      */

710     public void writeByte(int val) throws IOException JavaDoc {
711     bout.writeByte(val);
712     }
713
714     /**
715      * Writes a 16 bit short.
716      *
717      * @param val the short value to be written
718      * @throws IOException if I/O errors occur while writing to the underlying
719      * stream
720      */

721     public void writeShort(int val) throws IOException JavaDoc {
722     bout.writeShort(val);
723     }
724
725     /**
726      * Writes a 16 bit char.
727      *
728      * @param val the char value to be written
729      * @throws IOException if I/O errors occur while writing to the underlying
730      * stream
731      */

732     public void writeChar(int val) throws IOException JavaDoc {
733     bout.writeChar(val);
734     }
735
736     /**
737      * Writes a 32 bit int.
738      *
739      * @param val the integer value to be written
740      * @throws IOException if I/O errors occur while writing to the underlying
741      * stream
742      */

743     public void writeInt(int val) throws IOException JavaDoc {
744     bout.writeInt(val);
745     }
746
747     /**
748      * Writes a 64 bit long.
749      *
750      * @param val the long value to be written
751      * @throws IOException if I/O errors occur while writing to the underlying
752      * stream
753      */

754     public void writeLong(long val) throws IOException JavaDoc {
755     bout.writeLong(val);
756     }
757
758     /**
759      * Writes a 32 bit float.
760      *
761      * @param val the float value to be written
762      * @throws IOException if I/O errors occur while writing to the underlying
763      * stream
764      */

765     public void writeFloat(float val) throws IOException JavaDoc {
766     bout.writeFloat(val);
767     }
768
769     /**
770      * Writes a 64 bit double.
771      *
772      * @param val the double value to be written
773      * @throws IOException if I/O errors occur while writing to the underlying
774      * stream
775      */

776     public void writeDouble(double val) throws IOException JavaDoc {
777     bout.writeDouble(val);
778     }
779
780     /**
781      * Writes a String as a sequence of bytes.
782      *
783      * @param str the String of bytes to be written
784      * @throws IOException if I/O errors occur while writing to the underlying
785      * stream
786      */

787     public void writeBytes(String JavaDoc str) throws IOException JavaDoc {
788     bout.writeBytes(str);
789     }
790
791     /**
792      * Writes a String as a sequence of chars.
793      *
794      * @param str the String of chars to be written
795      * @throws IOException if I/O errors occur while writing to the underlying
796      * stream
797      */

798     public void writeChars(String JavaDoc str) throws IOException JavaDoc {
799     bout.writeChars(str);
800     }
801
802     /**
803      * Primitive data write of this String in
804      * <a HREF="DataInput.html#modified-utf-8">modified UTF-8</a>
805      * format. Note that there is a
806      * significant difference between writing a String into the stream as
807      * primitive data or as an Object. A String instance written by writeObject
808      * is written into the stream as a String initially. Future writeObject()
809      * calls write references to the string into the stream.
810      *
811      * @param str the String to be written
812      * @throws IOException if I/O errors occur while writing to the underlying
813      * stream
814      */

815     public void writeUTF(String JavaDoc str) throws IOException JavaDoc {
816     bout.writeUTF(str);
817     }
818     
819     /**
820      * Provide programmatic access to the persistent fields to be written
821      * to ObjectOutput.
822      *
823      * @since 1.2
824      */

825     public static abstract class PutField {
826
827     /**
828      * Put the value of the named boolean field into the persistent field.
829      *
830      * @param name the name of the serializable field
831      * @param val the value to assign to the field
832      */

833     public abstract void put(String JavaDoc name, boolean val);
834
835     /**
836      * Put the value of the named byte field into the persistent field.
837      *
838      * @param name the name of the serializable field
839      * @param val the value to assign to the field
840      */

841     public abstract void put(String JavaDoc name, byte val);
842
843     /**
844      * Put the value of the named char field into the persistent field.
845      *
846      * @param name the name of the serializable field
847      * @param val the value to assign to the field
848      */

849     public abstract void put(String JavaDoc name, char val);
850
851     /**
852      * Put the value of the named short field into the persistent field.
853      *
854      * @param name the name of the serializable field
855      * @param val the value to assign to the field
856      */

857     public abstract void put(String JavaDoc name, short val);
858
859     /**
860      * Put the value of the named int field into the persistent field.
861      *
862      * @param name the name of the serializable field
863      * @param val the value to assign to the field
864      */

865     public abstract void put(String JavaDoc name, int val);
866
867     /**
868      * Put the value of the named long field into the persistent field.
869      *
870      * @param name the name of the serializable field
871      * @param val the value to assign to the field
872      */

873     public abstract void put(String JavaDoc name, long val);
874
875     /**
876      * Put the value of the named float field into the persistent field.
877      *
878      * @param name the name of the serializable field
879      * @param val the value to assign to the field
880      */

881     public abstract void put(String JavaDoc name, float val);
882
883     /**
884      * Put the value of the named double field into the persistent field.
885      *
886      * @param name the name of the serializable field
887      * @param val the value to assign to the field
888      */

889     public abstract void put(String JavaDoc name, double val);
890
891     /**
892      * Put the value of the named Object field into the persistent field.
893      *
894      * @param name the name of the serializable field
895      * @param val the value to assign to the field
896      */

897     public abstract void put(String JavaDoc name, Object JavaDoc val);
898
899     /**
900      * Write the data and fields to the specified ObjectOutput stream.
901      *
902      * @param out the stream to write the data and fields to
903      * @throws IOException if I/O errors occur while writing to the
904      * underlying stream
905      * @deprecated This method does not write the values contained by this
906      * <code>PutField</code> object in a proper format, and may
907      * result in corruption of the serialization stream. The
908      * correct way to write <code>PutField</code> data is by
909      * calling the {@link java.io.ObjectOutputStream#writeFields()}
910      * method.
911      */

912         @Deprecated JavaDoc
913     public abstract void write(ObjectOutput JavaDoc out) throws IOException JavaDoc;
914     }
915
916
917     /**
918      * Returns protocol version in use.
919      */

920     int getProtocolVersion() {
921     return protocol;
922     }
923
924     /**
925      * Writes string without allowing it to be replaced in stream. Used by
926      * ObjectStreamClass to write class descriptor type strings.
927      */

928     void writeTypeString(String JavaDoc str) throws IOException JavaDoc {
929     int handle;
930     if (str == null) {
931         writeNull();
932     } else if ((handle = handles.lookup(str)) != -1) {
933         writeHandle(handle);
934     } else {
935         writeString(str, false);
936     }
937     }
938     
939     /**
940      * Verifies that this (possibly subclass) instance can be constructed
941      * without violating security constraints: the subclass must not override
942      * security-sensitive non-final methods, or else the
943      * "enableSubclassImplementation" SerializablePermission is checked.
944      */

945     private void verifySubclass() {
946     Class JavaDoc cl = getClass();
947     processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
948     WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
949     Boolean JavaDoc result = Caches.subclassAudits.get(key);
950     if (result == null) {
951         result = Boolean.valueOf(auditSubclass(cl));
952         Caches.subclassAudits.putIfAbsent(key, result);
953     }
954     if (result.booleanValue()) {
955         return;
956     }
957     SecurityManager JavaDoc sm = System.getSecurityManager();
958     if (sm != null) {
959         sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
960     }
961     }
962     
963     /**
964      * Performs reflective checks on given subclass to verify that it doesn't
965      * override security-sensitive non-final methods. Returns true if subclass
966      * is "safe", false otherwise.
967      */

968     private static boolean auditSubclass(final Class JavaDoc subcl) {
969     Boolean JavaDoc result = (Boolean JavaDoc) AccessController.doPrivileged(
970