1. /*
  2. * @(#)ObjectOutputStream.java 1.145 04/05/28
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. import java.security.AccessController;
  9. import java.security.PrivilegedAction;
  10. import java.util.Arrays;
  11. import sun.misc.SoftCache;
  12. /**
  13. * An ObjectOutputStream writes primitive data types and graphs of Java objects
  14. * to an OutputStream. The objects can be read (reconstituted) using an
  15. * ObjectInputStream. Persistent storage of objects can be accomplished by
  16. * using a file for the stream. If the stream is a network socket stream, the
  17. * objects can be reconstituted on another host or in another process.
  18. *
  19. * <p>Only objects that support the java.io.Serializable interface can be
  20. * written to streams. The class of each serializable object is encoded
  21. * including the class name and signature of the class, the values of the
  22. * object's fields and arrays, and the closure of any other objects referenced
  23. * from the initial objects.
  24. *
  25. * <p>The method writeObject is used to write an object to the stream. Any
  26. * object, including Strings and arrays, is written with writeObject. Multiple
  27. * objects or primitives can be written to the stream. The objects must be
  28. * read back from the corresponding ObjectInputstream with the same types and
  29. * in the same order as they were written.
  30. *
  31. * <p>Primitive data types can also be written to the stream using the
  32. * appropriate methods from DataOutput. Strings can also be written using the
  33. * writeUTF method.
  34. *
  35. * <p>The default serialization mechanism for an object writes the class of the
  36. * object, the class signature, and the values of all non-transient and
  37. * non-static fields. References to other objects (except in transient or
  38. * static fields) cause those objects to be written also. Multiple references
  39. * to a single object are encoded using a reference sharing mechanism so that
  40. * graphs of objects can be restored to the same shape as when the original was
  41. * written.
  42. *
  43. * <p>For example to write an object that can be read by the example in
  44. * ObjectInputStream:
  45. * <br>
  46. * <pre>
  47. * FileOutputStream fos = new FileOutputStream("t.tmp");
  48. * ObjectOutputStream oos = new ObjectOutputStream(fos);
  49. *
  50. * oos.writeInt(12345);
  51. * oos.writeObject("Today");
  52. * oos.writeObject(new Date());
  53. *
  54. * oos.close();
  55. * </pre>
  56. *
  57. * <p>Classes that require special handling during the serialization and
  58. * deserialization process must implement special methods with these exact
  59. * signatures:
  60. * <br>
  61. * <pre>
  62. * private void readObject(java.io.ObjectInputStream stream)
  63. * throws IOException, ClassNotFoundException;
  64. * private void writeObject(java.io.ObjectOutputStream stream)
  65. * throws IOException
  66. * </pre>
  67. *
  68. * <p>The writeObject method is responsible for writing the state of the object
  69. * for its particular class so that the corresponding readObject method can
  70. * restore it. The method does not need to concern itself with the state
  71. * belonging to the object's superclasses or subclasses. State is saved by
  72. * writing the individual fields to the ObjectOutputStream using the
  73. * writeObject method or by using the methods for primitive data types
  74. * supported by DataOutput.
  75. *
  76. * <p>Serialization does not write out the fields of any object that does not
  77. * implement the java.io.Serializable interface. Subclasses of Objects that
  78. * are not serializable can be serializable. In this case the non-serializable
  79. * class must have a no-arg constructor to allow its fields to be initialized.
  80. * In this case it is the responsibility of the subclass to save and restore
  81. * the state of the non-serializable class. It is frequently the case that the
  82. * fields of that class are accessible (public, package, or protected) or that
  83. * there are get and set methods that can be used to restore the state.
  84. *
  85. * <p>Serialization of an object can be prevented by implementing writeObject
  86. * and readObject methods that throw the NotSerializableException. The
  87. * exception will be caught by the ObjectOutputStream and abort the
  88. * serialization process.
  89. *
  90. * <p>Implementing the Externalizable interface allows the object to assume
  91. * complete control over the contents and format of the object's serialized
  92. * form. The methods of the Externalizable interface, writeExternal and
  93. * readExternal, are called to save and restore the objects state. When
  94. * implemented by a class they can write and read their own state using all of
  95. * the methods of ObjectOutput and ObjectInput. It is the responsibility of
  96. * the objects to handle any versioning that occurs.
  97. *
  98. * <p>Enum constants are serialized differently than ordinary serializable or
  99. * externalizable objects. The serialized form of an enum constant consists
  100. * solely of its name; field values of the constant are not transmitted. To
  101. * serialize an enum constant, ObjectOutputStream writes the string returned by
  102. * the constant's name method. Like other serializable or externalizable
  103. * objects, enum constants can function as the targets of back references
  104. * appearing subsequently in the serialization stream. The process by which
  105. * enum constants are serialized cannot be customized; any class-specific
  106. * writeObject and writeReplace methods defined by enum types are ignored
  107. * during serialization. Similarly, any serialPersistentFields or
  108. * serialVersionUID field declarations are also ignored--all enum types have a
  109. * fixed serialVersionUID of 0L.
  110. *
  111. * <p>Primitive data, excluding serializable fields and externalizable data, is
  112. * written to the ObjectOutputStream in block-data records. A block data record
  113. * is composed of a header and data. The block data header consists of a marker
  114. * and the number of bytes to follow the header. Consecutive primitive data
  115. * writes are merged into one block-data record. The blocking factor used for
  116. * a block-data record will be 1024 bytes. Each block-data record will be
  117. * filled up to 1024 bytes, or be written whenever there is a termination of
  118. * block-data mode. Calls to the ObjectOutputStream methods writeObject,
  119. * defaultWriteObject and writeFields initially terminate any existing
  120. * block-data record.
  121. *
  122. * @author Mike Warres
  123. * @author Roger Riggs
  124. * @version 1.145, 04/05/28
  125. * @see java.io.DataOutput
  126. * @see java.io.ObjectInputStream
  127. * @see java.io.Serializable
  128. * @see java.io.Externalizable
  129. * @see <a href="../../../guide/serialization/spec/output.doc.html">Object Serialization Specification, Section 2, Object Output Classes</a>
  130. * @since JDK1.1
  131. */
  132. public class ObjectOutputStream
  133. extends OutputStream implements ObjectOutput, ObjectStreamConstants
  134. {
  135. /** cache of subclass security audit results */
  136. private static final SoftCache subclassAudits = new SoftCache(5);
  137. /** filter stream for handling block data conversion */
  138. private final BlockDataOutputStream bout;
  139. /** obj -> wire handle map */
  140. private final HandleTable handles;
  141. /** obj -> replacement obj map */
  142. private final ReplaceTable subs;
  143. /** stream protocol version */
  144. private int protocol = PROTOCOL_VERSION_2;
  145. /** recursion depth */
  146. private int depth;
  147. /** buffer for writing primitive field values */
  148. private byte[] primVals;
  149. /** if true, invoke writeObjectOverride() instead of writeObject() */
  150. private final boolean enableOverride;
  151. /** if true, invoke replaceObject() */
  152. private boolean enableReplace;
  153. // values below valid only during upcalls to writeObject()/writeExternal()
  154. /** object currently being serialized */
  155. private Object curObj;
  156. /** descriptor for current class (null if in writeExternal()) */
  157. private ObjectStreamClass curDesc;
  158. /** current PutField object */
  159. private PutFieldImpl curPut;
  160. /**
  161. * Creates an ObjectOutputStream that writes to the specified OutputStream.
  162. * This constructor writes the serialization stream header to the
  163. * underlying stream; callers may wish to flush the stream immediately to
  164. * ensure that constructors for receiving ObjectInputStreams will not block
  165. * when reading the header.
  166. *
  167. * <p>If a security manager is installed, this constructor will check for
  168. * the "enableSubclassImplementation" SerializablePermission when invoked
  169. * directly or indirectly by the constructor of a subclass which overrides
  170. * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
  171. * methods.
  172. *
  173. * @param out output stream to write to
  174. * @throws IOException if an I/O error occurs while writing stream header
  175. * @throws SecurityException if untrusted subclass illegally overrides
  176. * security-sensitive methods
  177. * @throws NullPointerException if <code>out</code> is <code>null</code>
  178. * @see ObjectOutputStream#ObjectOutputStream()
  179. * @see ObjectOutputStream#putFields()
  180. * @see ObjectInputStream#ObjectInputStream(InputStream)
  181. */
  182. public ObjectOutputStream(OutputStream out) throws IOException {
  183. verifySubclass();
  184. bout = new BlockDataOutputStream(out);
  185. handles = new HandleTable(10, (float) 3.00);
  186. subs = new ReplaceTable(10, (float) 3.00);
  187. enableOverride = false;
  188. writeStreamHeader();
  189. bout.setBlockDataMode(true);
  190. }
  191. /**
  192. * Provide a way for subclasses that are completely reimplementing
  193. * ObjectOutputStream to not have to allocate private data just used by
  194. * this implementation of ObjectOutputStream.
  195. *
  196. * <p>If there is a security manager installed, this method first calls the
  197. * security manager's <code>checkPermission</code> method with a
  198. * <code>SerializablePermission("enableSubclassImplementation")</code>
  199. * permission to ensure it's ok to enable subclassing.
  200. *
  201. * @throws SecurityException if a security manager exists and its
  202. * <code>checkPermission</code> method denies enabling
  203. * subclassing.
  204. * @see SecurityManager#checkPermission
  205. * @see java.io.SerializablePermission
  206. */
  207. protected ObjectOutputStream() throws IOException, SecurityException {
  208. SecurityManager sm = System.getSecurityManager();
  209. if (sm != null) {
  210. sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  211. }
  212. bout = null;
  213. handles = null;
  214. subs = null;
  215. enableOverride = true;
  216. }
  217. /**
  218. * Specify stream protocol version to use when writing the stream.
  219. *
  220. * <p>This routine provides a hook to enable the current version of
  221. * Serialization to write in a format that is backwards compatible to a
  222. * previous version of the stream format.
  223. *
  224. * <p>Every effort will be made to avoid introducing additional
  225. * backwards incompatibilities; however, sometimes there is no
  226. * other alternative.
  227. *
  228. * @param version use ProtocolVersion from java.io.ObjectStreamConstants.
  229. * @throws IllegalStateException if called after any objects
  230. * have been serialized.
  231. * @throws IllegalArgumentException if invalid version is passed in.
  232. * @throws IOException if I/O errors occur
  233. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
  234. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
  235. * @since 1.2
  236. */
  237. public void useProtocolVersion(int version) throws IOException {
  238. if (handles.size() != 0) {
  239. // REMIND: implement better check for pristine stream?
  240. throw new IllegalStateException("stream non-empty");
  241. }
  242. switch (version) {
  243. case PROTOCOL_VERSION_1:
  244. case PROTOCOL_VERSION_2:
  245. protocol = version;
  246. break;
  247. default:
  248. throw new IllegalArgumentException(
  249. "unknown version: " + version);
  250. }
  251. }
  252. /**
  253. * Write the specified object to the ObjectOutputStream. The class of the
  254. * object, the signature of the class, and the values of the non-transient
  255. * and non-static fields of the class and all of its supertypes are
  256. * written. Default serialization for a class can be overridden using the
  257. * writeObject and the readObject methods. Objects referenced by this
  258. * object are written transitively so that a complete equivalent graph of
  259. * objects can be reconstructed by an ObjectInputStream.
  260. *
  261. * <p>Exceptions are thrown for problems with the OutputStream and for
  262. * classes that should not be serialized. All exceptions are fatal to the
  263. * OutputStream, which is left in an indeterminate state, and it is up to
  264. * the caller to ignore or recover the stream state.
  265. *
  266. * @throws InvalidClassException Something is wrong with a class used by
  267. * serialization.
  268. * @throws NotSerializableException Some object to be serialized does not
  269. * implement the java.io.Serializable interface.
  270. * @throws IOException Any exception thrown by the underlying
  271. * OutputStream.
  272. */
  273. public final void writeObject(Object obj) throws IOException {
  274. if (enableOverride) {
  275. writeObjectOverride(obj);
  276. return;
  277. }
  278. try {
  279. writeObject0(obj, false);
  280. } catch (IOException ex) {
  281. if (depth == 0) {
  282. writeFatalException(ex);
  283. }
  284. throw ex;
  285. }
  286. }
  287. /**
  288. * Method used by subclasses to override the default writeObject method.
  289. * This method is called by trusted subclasses of ObjectInputStream that
  290. * constructed ObjectInputStream using the protected no-arg constructor.
  291. * The subclass is expected to provide an override method with the modifier
  292. * "final".
  293. *
  294. * @param obj object to be written to the underlying stream
  295. * @throws IOException if there are I/O errors while writing to the
  296. * underlying stream
  297. * @see #ObjectOutputStream()
  298. * @see #writeObject(Object)
  299. * @since 1.2
  300. */
  301. protected void writeObjectOverride(Object obj) throws IOException {
  302. }
  303. /**
  304. * Writes an "unshared" object to the ObjectOutputStream. This method is
  305. * identical to writeObject, except that it always writes the given object
  306. * as a new, unique object in the stream (as opposed to a back-reference
  307. * pointing to a previously serialized instance). Specifically:
  308. * <ul>
  309. * <li>An object written via writeUnshared is always serialized in the
  310. * same manner as a newly appearing object (an object that has not
  311. * been written to the stream yet), regardless of whether or not the
  312. * object has been written previously.
  313. *
  314. * <li>If writeObject is used to write an object that has been previously
  315. * written with writeUnshared, the previous writeUnshared operation
  316. * is treated as if it were a write of a separate object. In other
  317. * words, ObjectOutputStream will never generate back-references to
  318. * object data written by calls to writeUnshared.
  319. * </ul>
  320. * While writing an object via writeUnshared does not in itself guarantee a
  321. * unique reference to the object when it is deserialized, it allows a
  322. * single object to be defined multiple times in a stream, so that multiple
  323. * calls to readUnshared by the receiver will not conflict. Note that the
  324. * rules described above only apply to the base-level object written with
  325. * writeUnshared, and not to any transitively referenced sub-objects in the
  326. * object graph to be serialized.
  327. *
  328. * <p>ObjectOutputStream subclasses which override this method can only be
  329. * constructed in security contexts possessing the
  330. * "enableSubclassImplementation" SerializablePermission; any attempt to
  331. * instantiate such a subclass without this permission will cause a
  332. * SecurityException to be thrown.
  333. *
  334. * @param obj object to write to stream
  335. * @throws NotSerializableException if an object in the graph to be
  336. * serialized does not implement the Serializable interface
  337. * @throws InvalidClassException if a problem exists with the class of an
  338. * object to be serialized
  339. * @throws IOException if an I/O error occurs during serialization
  340. */
  341. public void writeUnshared(Object obj) throws IOException {
  342. try {
  343. writeObject0(obj, true);
  344. } catch (IOException ex) {
  345. if (depth == 0) {
  346. writeFatalException(ex);
  347. }
  348. throw ex;
  349. }
  350. }
  351. /**
  352. * Write the non-static and non-transient fields of the current class to
  353. * this stream. This may only be called from the writeObject method of the
  354. * class being serialized. It will throw the NotActiveException if it is
  355. * called otherwise.
  356. *
  357. * @throws IOException if I/O errors occur while writing to the underlying
  358. * <code>OutputStream</code>
  359. */
  360. public void defaultWriteObject() throws IOException {
  361. if (curObj == null || curDesc == null) {
  362. throw new NotActiveException("not in call to writeObject");
  363. }
  364. bout.setBlockDataMode(false);
  365. defaultWriteFields(curObj, curDesc);
  366. bout.setBlockDataMode(true);
  367. }
  368. /**
  369. * Retrieve the object used to buffer persistent fields to be written to
  370. * the stream. The fields will be written to the stream when writeFields
  371. * method is called.
  372. *
  373. * @return an instance of the class Putfield that holds the serializable
  374. * fields
  375. * @throws IOException if I/O errors occur
  376. * @since 1.2
  377. */
  378. public ObjectOutputStream.PutField putFields() throws IOException {
  379. if (curPut == null) {
  380. if (curObj == null || curDesc == null) {
  381. throw new NotActiveException("not in call to writeObject");
  382. }
  383. curPut = new PutFieldImpl(curDesc);
  384. }
  385. return curPut;
  386. }
  387. /**
  388. * Write the buffered fields to the stream.
  389. *
  390. * @throws IOException if I/O errors occur while writing to the underlying
  391. * stream
  392. * @throws NotActiveException Called when a classes writeObject method was
  393. * not called to write the state of the object.
  394. * @since 1.2
  395. */
  396. public void writeFields() throws IOException {
  397. if (curPut == null) {
  398. throw new NotActiveException("no current PutField object");
  399. }
  400. bout.setBlockDataMode(false);
  401. curPut.writeFields();
  402. bout.setBlockDataMode(true);
  403. }
  404. /**
  405. * Reset will disregard the state of any objects already written to the
  406. * stream. The state is reset to be the same as a new ObjectOutputStream.
  407. * The current point in the stream is marked as reset so the corresponding
  408. * ObjectInputStream will be reset at the same point. Objects previously
  409. * written to the stream will not be refered to as already being in the
  410. * stream. They will be written to the stream again.
  411. *
  412. * @throws IOException if reset() is invoked while serializing an object.
  413. */
  414. public void reset() throws IOException {
  415. if (depth != 0) {
  416. throw new IOException("stream active");
  417. }
  418. bout.setBlockDataMode(false);
  419. bout.writeByte(TC_RESET);
  420. clear();
  421. bout.setBlockDataMode(true);
  422. }
  423. /**
  424. * Subclasses may implement this method to allow class data to be stored in
  425. * the stream. By default this method does nothing. The corresponding
  426. * method in ObjectInputStream is resolveClass. This method is called
  427. * exactly once for each unique class in the stream. The class name and
  428. * signature will have already been written to the stream. This method may
  429. * make free use of the ObjectOutputStream to save any representation of
  430. * the class it deems suitable (for example, the bytes of the class file).
  431. * The resolveClass method in the corresponding subclass of
  432. * ObjectInputStream must read and use any data or objects written by
  433. * annotateClass.
  434. *
  435. * @param cl the class to annotate custom data for
  436. * @throws IOException Any exception thrown by the underlying
  437. * OutputStream.
  438. */
  439. protected void annotateClass(Class<?> cl) throws IOException {
  440. }
  441. /**
  442. * Subclasses may implement this method to store custom data in the stream
  443. * along with descriptors for dynamic proxy classes.
  444. *
  445. * <p>This method is called exactly once for each unique proxy class
  446. * descriptor in the stream. The default implementation of this method in
  447. * <code>ObjectOutputStream</code> does nothing.
  448. *
  449. * <p>The corresponding method in <code>ObjectInputStream</code> is
  450. * <code>resolveProxyClass</code>. For a given subclass of
  451. * <code>ObjectOutputStream</code> that overrides this method, the
  452. * <code>resolveProxyClass</code> method in the corresponding subclass of
  453. * <code>ObjectInputStream</code> must read any data or objects written by
  454. * <code>annotateProxyClass</code>.
  455. *
  456. * @param cl the proxy class to annotate custom data for
  457. * @throws IOException any exception thrown by the underlying
  458. * <code>OutputStream</code>
  459. * @see ObjectInputStream#resolveProxyClass(String[])
  460. * @since 1.3
  461. */
  462. protected void annotateProxyClass(Class<?> cl) throws IOException {
  463. }
  464. /**
  465. * This method will allow trusted subclasses of ObjectOutputStream to
  466. * substitute one object for another during serialization. Replacing
  467. * objects is disabled until enableReplaceObject is called. The
  468. * enableReplaceObject method checks that the stream requesting to do
  469. * replacement can be trusted. The first occurrence of each object written
  470. * into the serialization stream is passed to replaceObject. Subsequent
  471. * references to the object are replaced by the object returned by the
  472. * original call to replaceObject. To ensure that the private state of
  473. * objects is not unintentionally exposed, only trusted streams may use
  474. * replaceObject.
  475. *
  476. * <p>The ObjectOutputStream.writeObject method takes a parameter of type
  477. * Object (as opposed to type Serializable) to allow for cases where
  478. * non-serializable objects are replaced by serializable ones.
  479. *
  480. * <p>When a subclass is replacing objects it must insure that either a
  481. * complementary substitution must be made during deserialization or that
  482. * the substituted object is compatible with every field where the
  483. * reference will be stored. Objects whose type is not a subclass of the
  484. * type of the field or array element abort the serialization by raising an
  485. * exception and the object is not be stored.
  486. *
  487. * <p>This method is called only once when each object is first
  488. * encountered. All subsequent references to the object will be redirected
  489. * to the new object. This method should return the object to be
  490. * substituted or the original object.
  491. *
  492. * <p>Null can be returned as the object to be substituted, but may cause
  493. * NullReferenceException in classes that contain references to the
  494. * original object since they may be expecting an object instead of
  495. * null.
  496. *
  497. * @param obj the object to be replaced
  498. * @return the alternate object that replaced the specified one
  499. * @throws IOException Any exception thrown by the underlying
  500. * OutputStream.
  501. */
  502. protected Object replaceObject(Object obj) throws IOException {
  503. return obj;
  504. }
  505. /**
  506. * Enable the stream to do replacement of objects in the stream. When
  507. * enabled, the replaceObject method is called for every object being
  508. * serialized.
  509. *
  510. * <p>If <code>enable</code> is true, and there is a security manager
  511. * installed, this method first calls the security manager's
  512. * <code>checkPermission</code> method with a
  513. * <code>SerializablePermission("enableSubstitution")</code> permission to
  514. * ensure it's ok to enable the stream to do replacement of objects in the
  515. * stream.
  516. *
  517. * @param enable boolean parameter to enable replacement of objects
  518. * @return the previous setting before this method was invoked
  519. * @throws SecurityException if a security manager exists and its
  520. * <code>checkPermission</code> method denies enabling the stream
  521. * to do replacement of objects in the stream.
  522. * @see SecurityManager#checkPermission
  523. * @see java.io.SerializablePermission
  524. */
  525. protected boolean enableReplaceObject(boolean enable)
  526. throws SecurityException
  527. {
  528. if (enable == enableReplace) {
  529. return enable;
  530. }
  531. if (enable) {
  532. SecurityManager sm = System.getSecurityManager();
  533. if (sm != null) {
  534. sm.checkPermission(SUBSTITUTION_PERMISSION);
  535. }
  536. }
  537. enableReplace = enable;
  538. return !enableReplace;
  539. }
  540. /**
  541. * The writeStreamHeader method is provided so subclasses can append or
  542. * prepend their own header to the stream. It writes the magic number and
  543. * version to the stream.
  544. *
  545. * @throws IOException if I/O errors occur while writing to the underlying
  546. * stream
  547. */
  548. protected void writeStreamHeader() throws IOException {
  549. bout.writeShort(STREAM_MAGIC);
  550. bout.writeShort(STREAM_VERSION);
  551. }
  552. /**
  553. * Write the specified class descriptor to the ObjectOutputStream. Class
  554. * descriptors are used to identify the classes of objects written to the
  555. * stream. Subclasses of ObjectOutputStream may override this method to
  556. * customize the way in which class descriptors are written to the
  557. * serialization stream. The corresponding method in ObjectInputStream,
  558. * <code>readClassDescriptor</code>, should then be overridden to
  559. * reconstitute the class descriptor from its custom stream representation.
  560. * By default, this method writes class descriptors according to the format
  561. * defined in the Object Serialization specification.
  562. *
  563. * <p>Note that this method will only be called if the ObjectOutputStream
  564. * is not using the old serialization stream format (set by calling
  565. * ObjectOutputStream's <code>useProtocolVersion</code> method). If this
  566. * serialization stream is using the old format
  567. * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written
  568. * internally in a manner that cannot be overridden or customized.
  569. *
  570. * @param desc class descriptor to write to the stream
  571. * @throws IOException If an I/O error has occurred.
  572. * @see java.io.ObjectInputStream#readClassDescriptor()
  573. * @see #useProtocolVersion(int)
  574. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
  575. * @since 1.3
  576. */
  577. protected void writeClassDescriptor(ObjectStreamClass desc)
  578. throws IOException
  579. {
  580. desc.writeNonProxy(this);
  581. }
  582. /**
  583. * Writes a byte. This method will block until the byte is actually
  584. * written.
  585. *
  586. * @param val the byte to be written to the stream
  587. * @throws IOException If an I/O error has occurred.
  588. */
  589. public void write(int val) throws IOException {
  590. bout.write(val);
  591. }
  592. /**
  593. * Writes an array of bytes. This method will block until the bytes are
  594. * actually written.
  595. *
  596. * @param buf the data to be written
  597. * @throws IOException If an I/O error has occurred.
  598. */
  599. public void write(byte[] buf) throws IOException {
  600. bout.write(buf, 0, buf.length, false);
  601. }
  602. /**
  603. * Writes a sub array of bytes.
  604. *
  605. * @param buf the data to be written
  606. * @param off the start offset in the data
  607. * @param len the number of bytes that are written
  608. * @throws IOException If an I/O error has occurred.
  609. */
  610. public void write(byte[] buf, int off, int len) throws IOException {
  611. if (buf == null) {
  612. throw new NullPointerException();
  613. }
  614. int endoff = off + len;
  615. if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
  616. throw new IndexOutOfBoundsException();
  617. }
  618. bout.write(buf, off, len, false);
  619. }
  620. /**
  621. * Flushes the stream. This will write any buffered output bytes and flush
  622. * through to the underlying stream.
  623. *
  624. * @throws IOException If an I/O error has occurred.
  625. */
  626. public void flush() throws IOException {
  627. bout.flush();
  628. }
  629. /**
  630. * Drain any buffered data in ObjectOutputStream. Similar to flush but
  631. * does not propagate the flush to the underlying stream.
  632. *
  633. * @throws IOException if I/O errors occur while writing to the underlying
  634. * stream
  635. */
  636. protected void drain() throws IOException {
  637. bout.drain();
  638. }
  639. /**
  640. * Closes the stream. This method must be called to release any resources
  641. * associated with the stream.
  642. *
  643. * @throws IOException If an I/O error has occurred.
  644. */
  645. public void close() throws IOException {
  646. flush();
  647. clear();
  648. bout.close();
  649. }
  650. /**
  651. * Writes a boolean.
  652. *
  653. * @param val the boolean to be written
  654. * @throws IOException if I/O errors occur while writing to the underlying
  655. * stream
  656. */
  657. public void writeBoolean(boolean val) throws IOException {
  658. bout.writeBoolean(val);
  659. }
  660. /**
  661. * Writes an 8 bit byte.
  662. *
  663. * @param val the byte value to be written
  664. * @throws IOException if I/O errors occur while writing to the underlying
  665. * stream
  666. */
  667. public void writeByte(int val) throws IOException {
  668. bout.writeByte(val);
  669. }
  670. /**
  671. * Writes a 16 bit short.
  672. *
  673. * @param val the short value to be written
  674. * @throws IOException if I/O errors occur while writing to the underlying
  675. * stream
  676. */
  677. public void writeShort(int val) throws IOException {
  678. bout.writeShort(val);
  679. }
  680. /**
  681. * Writes a 16 bit char.
  682. *
  683. * @param val the char value to be written
  684. * @throws IOException if I/O errors occur while writing to the underlying
  685. * stream
  686. */
  687. public void writeChar(int val) throws IOException {
  688. bout.writeChar(val);
  689. }
  690. /**
  691. * Writes a 32 bit int.
  692. *
  693. * @param val the integer value to be written
  694. * @throws IOException if I/O errors occur while writing to the underlying
  695. * stream
  696. */
  697. public void writeInt(int val) throws IOException {
  698. bout.writeInt(val);
  699. }
  700. /**
  701. * Writes a 64 bit long.
  702. *
  703. * @param val the long value to be written
  704. * @throws IOException if I/O errors occur while writing to the underlying
  705. * stream
  706. */
  707. public void writeLong(long val) throws IOException {
  708. bout.writeLong(val);
  709. }
  710. /**
  711. * Writes a 32 bit float.
  712. *
  713. * @param val the float value to be written
  714. * @throws IOException if I/O errors occur while writing to the underlying
  715. * stream
  716. */
  717. public void writeFloat(float val) throws IOException {
  718. bout.writeFloat(val);
  719. }
  720. /**
  721. * Writes a 64 bit double.
  722. *
  723. * @param val the double value to be written
  724. * @throws IOException if I/O errors occur while writing to the underlying
  725. * stream
  726. */
  727. public void writeDouble(double val) throws IOException {
  728. bout.writeDouble(val);
  729. }
  730. /**
  731. * Writes a String as a sequence of bytes.
  732. *
  733. * @param str the String of bytes to be written
  734. * @throws IOException if I/O errors occur while writing to the underlying
  735. * stream
  736. */
  737. public void writeBytes(String str) throws IOException {
  738. bout.writeBytes(str);
  739. }
  740. /**
  741. * Writes a String as a sequence of chars.
  742. *
  743. * @param str the String of chars to be written
  744. * @throws IOException if I/O errors occur while writing to the underlying
  745. * stream
  746. */
  747. public void writeChars(String str) throws IOException {
  748. bout.writeChars(str);
  749. }
  750. /**
  751. * Primitive data write of this String in
  752. * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
  753. * format. Note that there is a
  754. * significant difference between writing a String into the stream as
  755. * primitive data or as an Object. A String instance written by writeObject
  756. * is written into the stream as a String initially. Future writeObject()
  757. * calls write references to the string into the stream.
  758. *
  759. * @param str the String to be written
  760. * @throws IOException if I/O errors occur while writing to the underlying
  761. * stream
  762. */
  763. public void writeUTF(String str) throws IOException {
  764. bout.writeUTF(str);
  765. }
  766. /**
  767. * Provide programmatic access to the persistent fields to be written
  768. * to ObjectOutput.
  769. *
  770. * @since 1.2
  771. */
  772. public static abstract class PutField {
  773. /**
  774. * Put the value of the named boolean field into the persistent field.
  775. *
  776. * @param name the name of the serializable field
  777. * @param val the value to assign to the field
  778. */
  779. public abstract void put(String name, boolean val);
  780. /**
  781. * Put the value of the named byte field into the persistent field.
  782. *
  783. * @param name the name of the serializable field
  784. * @param val the value to assign to the field
  785. */
  786. public abstract void put(String name, byte val);
  787. /**
  788. * Put the value of the named char field into the persistent field.
  789. *
  790. * @param name the name of the serializable field
  791. * @param val the value to assign to the field
  792. */
  793. public abstract void put(String name, char val);
  794. /**
  795. * Put the value of the named short field into the persistent field.
  796. *
  797. * @param name the name of the serializable field
  798. * @param val the value to assign to the field
  799. */
  800. public abstract void put(String name, short val);
  801. /**
  802. * Put the value of the named int field into the persistent field.
  803. *
  804. * @param name the name of the serializable field
  805. * @param val the value to assign to the field
  806. */
  807. public abstract void put(String name, int val);
  808. /**
  809. * Put the value of the named long field into the persistent field.
  810. *
  811. * @param name the name of the serializable field
  812. * @param val the value to assign to the field
  813. */
  814. public abstract void put(String name, long val);
  815. /**
  816. * Put the value of the named float field into the persistent field.
  817. *
  818. * @param name the name of the serializable field
  819. * @param val the value to assign to the field
  820. */
  821. public abstract void put(String name, float val);
  822. /**
  823. * Put the value of the named double field into the persistent field.
  824. *
  825. * @param name the name of the serializable field
  826. * @param val the value to assign to the field
  827. */
  828. public abstract void put(String name, double val);
  829. /**
  830. * Put the value of the named Object field into the persistent field.
  831. *
  832. * @param name the name of the serializable field
  833. * @param val the value to assign to the field
  834. */
  835. public abstract void put(String name, Object val);
  836. /**
  837. * Write the data and fields to the specified ObjectOutput stream.
  838. *
  839. * @param out the stream to write the data and fields to
  840. * @throws IOException if I/O errors occur while writing to the
  841. * underlying stream
  842. * @deprecated This method does not write the values contained by this
  843. * <code>PutField</code> object in a proper format, and may
  844. * result in corruption of the serialization stream. The
  845. * correct way to write <code>PutField</code> data is by
  846. * calling the {@link java.io.ObjectOutputStream#writeFields()}
  847. * method.
  848. */
  849. @Deprecated
  850. public abstract void write(ObjectOutput out) throws IOException;
  851. }
  852. /**
  853. * Returns protocol version in use.
  854. */
  855. int getProtocolVersion() {
  856. return protocol;
  857. }
  858. /**
  859. * Writes string without allowing it to be replaced in stream. Used by
  860. * ObjectStreamClass to write class descriptor type strings.
  861. */
  862. void writeTypeString(String str) throws IOException {
  863. int handle;
  864. if (str == null) {
  865. writeNull();
  866. } else if ((handle = handles.lookup(str)) != -1) {
  867. writeHandle(handle);
  868. } else {
  869. writeString(str, false);
  870. }
  871. }
  872. /**
  873. * Verifies that this (possibly subclass) instance can be constructed
  874. * without violating security constraints: the subclass must not override
  875. * security-sensitive non-final methods, or else the
  876. * "enableSubclassImplementation" SerializablePermission is checked.
  877. */
  878. private void verifySubclass() {
  879. Class cl = getClass();
  880. synchronized (subclassAudits) {
  881. Boolean result = (Boolean) subclassAudits.get(cl);
  882. if (result == null) {
  883. /*
  884. * Note: only new Boolean instances (i.e., not Boolean.TRUE or
  885. * Boolean.FALSE) must be used as cache values, otherwise cache
  886. * entry will pin associated class.
  887. */
  888. result = new Boolean(auditSubclass(cl));
  889. subclassAudits.put(cl, result);
  890. }
  891. if (result.booleanValue()) {
  892. return;
  893. }
  894. }
  895. SecurityManager sm = System.getSecurityManager();
  896. if (sm != null) {
  897. sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  898. }
  899. }
  900. /**
  901. * Performs reflective checks on given subclass to verify that it doesn't
  902. * override security-sensitive non-final methods. Returns true if subclass
  903. * is "safe", false otherwise.
  904. */
  905. private static boolean auditSubclass(final Class subcl) {
  906. Boolean result = (Boolean) AccessController.doPrivileged(
  907. new PrivilegedAction() {
  908. public Object run() {
  909. for (Class cl = subcl;
  910. cl != ObjectOutputStream.class;
  911. cl = cl.getSuperclass())
  912. {
  913. try {
  914. cl.getDeclaredMethod(
  915. "writeUnshared", new Class[] { Object.class });
  916. return Boolean.FALSE;
  917. } catch (NoSuchMethodException ex) {
  918. }
  919. try {
  920. cl.getDeclaredMethod("putFields", new Class[0]);
  921. return Boolean.FALSE;
  922. } catch (NoSuchMethodException ex) {
  923. }
  924. }
  925. return Boolean.TRUE;
  926. }
  927. }
  928. );
  929. return result.booleanValue();
  930. }
  931. /**
  932. * Clears internal data structures.
  933. */
  934. private void clear() {
  935. subs.clear();
  936. handles.clear();
  937. }
  938. /**
  939. * Underlying writeObject/writeUnshared implementation.
  940. */
  941. private void writeObject0(Object obj, boolean unshared)
  942. throws IOException
  943. {
  944. boolean oldMode = bout.setBlockDataMode(false);
  945. depth++;
  946. try {
  947. // handle previously written and non-replaceable objects
  948. int h;
  949. if ((obj = subs.lookup(obj)) == null) {
  950. writeNull();
  951. return;
  952. } else if (!unshared && (h = handles.lookup(obj)) != -1) {
  953. writeHandle(h);
  954. return;
  955. } else if (obj instanceof Class) {
  956. writeClass((Class) obj, unshared);
  957. return;
  958. } else if (obj instanceof ObjectStreamClass) {
  959. writeClassDesc((ObjectStreamClass) obj, unshared);
  960. return;
  961. }
  962. // check for replacement object
  963. Object orig = obj;
  964. Class cl = obj.getClass();
  965. ObjectStreamClass desc;
  966. for (;;) {
  967. // REMIND: skip this check for strings/arrays?
  968. Class repCl;
  969. desc = ObjectStreamClass.lookup(cl, true);
  970. if (!desc.hasWriteReplaceMethod() ||
  971. (obj = desc.invokeWriteReplace(obj)) == null ||
  972. (repCl = obj.getClass()) == cl)
  973. {
  974. break;
  975. }
  976. cl = repCl;
  977. }
  978. if (enableReplace) {
  979. Object rep = replaceObject(obj);
  980. if (rep != obj && rep != null) {
  981. cl = rep.getClass();
  982. desc = ObjectStreamClass.lookup(cl, true);
  983. }
  984. obj = rep;
  985. }
  986. // if object replaced, run through original checks a second time
  987. if (obj != orig) {
  988. subs.assign(orig, obj);
  989. if (obj == null) {
  990. writeNull();
  991. return;
  992. } else if (!unshared && (h = handles.lookup(obj)) != -1) {
  993. writeHandle(h);
  994. return;
  995. } else if (obj instanceof Class) {
  996. writeClass((Class) obj, unshared);
  997. return;
  998. } else if (obj instanceof ObjectStreamClass) {
  999. writeClassDesc((ObjectStreamClass) obj, unshared);
  1000. return;
  1001. }
  1002. }
  1003. // remaining cases
  1004. if (obj instanceof String) {
  1005. writeString((String) obj, unshared);
  1006. } else if (cl.isArray()) {
  1007. writeArray(obj, desc, unshared);
  1008. } else if (obj instanceof Enum) {
  1009. writeEnum((Enum) obj, desc, unshared);
  1010. } else if (obj instanceof Serializable) {
  1011. writeOrdinaryObject(obj, desc, unshared);
  1012. } else {
  1013. throw new NotSerializableException(cl.getName());
  1014. }
  1015. } finally {
  1016. depth--;
  1017. bout.setBlockDataMode(oldMode);
  1018. }
  1019. }
  1020. /**
  1021. * Writes null code to stream.
  1022. */
  1023. private void writeNull() throws IOException {
  1024. bout.writeByte(TC_NULL);
  1025. }
  1026. /**
  1027. * Writes given object handle to stream.
  1028. */
  1029. private void writeHandle(int handle) throws IOException {
  1030. bout.writeByte(TC_REFERENCE);
  1031. bout.writeInt(baseWireHandle + handle);
  1032. }
  1033. /**
  1034. * Writes representation of given class to stream.
  1035. */
  1036. private void writeClass(Class cl, boolean unshared) throws IOException {
  1037. bout.writeByte(TC_CLASS);
  1038. writeClassDesc(ObjectStreamClass.lookup(cl, true), false);
  1039. handles.assign(unshared ? null : cl);
  1040. }
  1041. /**
  1042. * Writes representation of given class descriptor to stream.
  1043. */
  1044. private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
  1045. throws IOException
  1046. {
  1047. int handle;
  1048. if (desc == null) {
  1049. writeNull();
  1050. } else if (!unshared && (handle = handles.lookup(desc)) != -1) {
  1051. writeHandle(handle);
  1052. } else if (desc.isProxy()) {
  1053. writeProxyDesc(desc, unshared);
  1054. } else {
  1055. writeNonProxyDesc(desc, unshared);
  1056. }
  1057. }
  1058. /**
  1059. * Writes class descriptor representing a dynamic proxy class to stream.
  1060. */
  1061. private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
  1062. throws IOException
  1063. {
  1064. bout.writeByte(TC_PROXYCLASSDESC);
  1065. handles.assign(unshared ? null : desc);
  1066. Class cl = desc.forClass();
  1067. Class[] ifaces = cl.getInterfaces();
  1068. bout.writeInt(ifaces.length);
  1069. for (int i = 0; i < ifaces.length; i++) {
  1070. bout.writeUTF(ifaces[i].getName());
  1071. }
  1072. bout.setBlockDataMode(true);
  1073. annotateProxyClass(cl);
  1074. bout.setBlockDataMode(false);
  1075. bout.writeByte(TC_ENDBLOCKDATA);
  1076. writeClassDesc(desc.getSuperDesc(), false);
  1077. }
  1078. /**
  1079. * Writes class descriptor representing a standard (i.e., not a dynamic
  1080. * proxy) class to stream.
  1081. */
  1082. private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
  1083. throws IOException
  1084. {
  1085. bout.writeByte(TC_CLASSDESC);
  1086. handles.assign(unshared ? null : desc);
  1087. if (protocol == PROTOCOL_VERSION_1) {
  1088. // do not invoke class descriptor write hook with old protocol
  1089. desc.writeNonProxy(this);
  1090. } else {
  1091. writeClassDescriptor(desc);
  1092. }
  1093. Class cl = desc.forClass();
  1094. bout.setBlockDataMode(true);
  1095. annotateClass(cl);
  1096. bout.setBlockDataMode(false);
  1097. bout.writeByte(TC_ENDBLOCKDATA);
  1098. writeClassDesc(desc.getSuperDesc(), false);
  1099. }
  1100. /**
  1101. * Writes given string to stream, using standard or long UTF format
  1102. * depending on string length.
  1103. */
  1104. private void writeString(String str, boolean unshared) throws IOException {
  1105. handles.assign(unshared ? null : str);
  1106. long utflen = bout.getUTFLength(str);
  1107. if (utflen <= 0xFFFF) {
  1108. bout.writeByte(TC_STRING);
  1109. bout.writeUTF(str, utflen);
  1110. } else {
  1111. bout.writeByte(TC_LONGSTRING);
  1112. bout.writeLongUTF(str, utflen);
  1113. }
  1114. }
  1115. /**
  1116. * Writes given array object to stream.
  1117. */
  1118. private void writeArray(Object array,
  1119. ObjectStreamClass desc,
  1120. boolean unshared)
  1121. throws IOException
  1122. {
  1123. bout.writeByte(TC_ARRAY);
  1124. writeClassDesc(desc, false);
  1125. handles.assign(unshared ? null : array);
  1126. Class ccl = desc.forClass().getComponentType();
  1127. if (ccl.isPrimitive()) {
  1128. if (ccl == Integer.TYPE) {
  1129. int[] ia = (int[]) array;
  1130. bout.writeInt(ia.length);
  1131. bout.writeInts(ia, 0, ia.length);
  1132. } else if (ccl == Byte.TYPE) {
  1133. byte[] ba = (byte[]) array;
  1134. bout.writeInt(ba.length);
  1135. bout.write(ba, 0, ba.length, true);
  1136. } else if (ccl == Long.TYPE) {
  1137. long[] ja = (long[]) array;
  1138. bout.writeInt(ja.length);
  1139. bout.writeLongs(ja, 0, ja.length);
  1140. } else if (ccl == Float.TYPE) {
  1141. float[] fa = (float[]) array;
  1142. bout.writeInt(fa.length);
  1143. bout.writeFloats(fa, 0, fa.length);
  1144. } else if (ccl == Double.TYPE) {
  1145. double[] da = (double[]) array;
  1146. bout.writeInt(da.length);
  1147. bout.writeDoubles(da, 0, da.length);
  1148. } else if (ccl == Short.TYPE) {
  1149. short[] sa = (short[]) array;
  1150. bout.writeInt(sa.length);
  1151. bout.writeShorts(sa, 0, sa.length);
  1152. } else if (ccl == Character.TYPE) {
  1153. char[] ca = (char[]) array;
  1154. bout.writeInt(ca.length);
  1155. bout.writeChars(ca, 0, ca.length);
  1156. } else if (ccl == Boolean.TYPE) {
  1157. boolean[] za = (boolean[]) array;
  1158. bout.writeInt(za.length);
  1159. bout.writeBooleans(za, 0, za.length);
  1160. } else {
  1161. throw new InternalError();
  1162. }
  1163. } else {
  1164. Object[] objs = (Object[]) array;
  1165. int len = objs.length;
  1166. bout.writeInt(len);
  1167. for (int i = 0; i < len; i++) {
  1168. writeObject0(objs[i], false);
  1169. }
  1170. }
  1171. }
  1172. /**
  1173. * Writes given enum constant to stream.
  1174. */
  1175. private void writeEnum(Enum en,
  1176. ObjectStreamClass desc,
  1177. boolean unshared)
  1178. throws IOException
  1179. {
  1180. bout.writeByte(TC_ENUM);
  1181. ObjectStreamClass sdesc = desc.getSuperDesc();
  1182. writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
  1183. handles.assign(unshared ? null : en);
  1184. writeString(en.name(), false);
  1185. }
  1186. /**
  1187. * Writes representation of a "ordinary" (i.e., not a String, Class,
  1188. * ObjectStreamClass, array, or enum constant) serializable object to the
  1189. * stream.
  1190. */
  1191. private void writeOrdinaryObject(Object obj,
  1192. ObjectStreamClass desc,
  1193. boolean unshared)
  1194. throws IOException
  1195. {
  1196. desc.checkSerialize();
  1197. bout.writeByte(TC_OBJECT);
  1198. writeClassDesc(desc, false);
  1199. handles.assign(unshared ? null : obj);
  1200. if (desc.isExternalizable() && !desc.isProxy()) {
  1201. writeExternalData((Externalizable) obj);
  1202. } else {
  1203. writeSerialData(obj, desc);
  1204. }
  1205. }
  1206. /**
  1207. * Writes externalizable data of given object by invoking its
  1208. * writeExternal() method.
  1209. */
  1210. private void writeExternalData(Externalizable obj) throws IOException {
  1211. Object oldObj = curObj;
  1212. ObjectStreamClass oldDesc = curDesc;
  1213. PutFieldImpl oldPut = curPut;
  1214. curObj = obj;
  1215. curDesc = null;
  1216. curPut = null;
  1217. if (protocol == PROTOCOL_VERSION_1) {
  1218. obj.writeExternal(this);
  1219. } else {
  1220. bout.setBlockDataMode(true);
  1221. obj.writeExternal(this);
  1222. bout.setBlockDataMode(false);
  1223. bout.writeByte(TC_ENDBLOCKDATA);
  1224. }
  1225. curObj = oldObj;
  1226. curDesc = oldDesc;
  1227. curPut = oldPut;
  1228. }
  1229. /**
  1230. * Writes instance data for each serializable class of given object, from
  1231. * superclass to subclass.
  1232. */
  1233. private void writeSerialData(Object obj, ObjectStreamClass desc)
  1234. throws IOException
  1235. {
  1236. ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
  1237. for (int i = 0; i < slots.length; i++) {
  1238. ObjectStreamClass slotDesc = slots[i].desc;
  1239. if (slotDesc.hasWriteObjectMethod()) {
  1240. Object oldObj = curObj;
  1241. ObjectStreamClass oldDesc = curDesc;
  1242. PutFieldImpl oldPut = curPut;
  1243. curObj = obj;
  1244. curDesc = slotDesc;
  1245. curPut = null;
  1246. bout.setBlockDataMode(true);
  1247. slotDesc.invokeWriteObject(obj, this);
  1248. bout.setBlockDataMode(false);
  1249. bout.writeByte(TC_ENDBLOCKDATA);
  1250. curObj = oldObj;
  1251. curDesc = oldDesc;
  1252. curPut = oldPut;
  1253. } else {
  1254. defaultWriteFields(obj, slotDesc);
  1255. }
  1256. }
  1257. }
  1258. /**
  1259. * Fetches and writes values of serializable fields of given object to
  1260. * stream. The given class descriptor specifies which field values to
  1261. * write, and in which order they should be written.
  1262. */
  1263. private void defaultWriteFields(Object obj, ObjectStreamClass desc)
  1264. throws IOException
  1265. {
  1266. // REMIND: perform conservative isInstance check here?
  1267. desc.checkDefaultSerialize();
  1268. int primDataSize = desc.getPrimDataSize();
  1269. if (primVals == null || primVals.length < primDataSize) {
  1270. primVals = new byte[primDataSize];
  1271. }
  1272. desc.getPrimFieldValues(obj, primVals);
  1273. bout.write(primVals, 0, primDataSize, false);
  1274. ObjectStreamField[] fields = desc.getFields(false);
  1275. Object[] objVals = new Object[desc.getNumObjFields()];
  1276. int numPrimFields = fields.length - objVals.length;
  1277. desc.getObjFieldValues(obj, objVals);
  1278. for (int i = 0; i < objVals.length; i++) {
  1279. writeObject0(objVals[i], fields[numPrimFields + i].isUnshared());
  1280. }
  1281. }
  1282. /**
  1283. * Attempts to write to stream fatal IOException that has caused
  1284. * serialization to abort.
  1285. */
  1286. private void writeFatalException(IOException ex) throws IOException {
  1287. /*
  1288. * Note: the serialization specification states that if a second
  1289. * IOException occurs while attempting to serialize the original fatal
  1290. * exception to the stream, then a StreamCorruptedException should be
  1291. * thrown (section 2.1). However, due to a bug in previous
  1292. * implementations of serialization, StreamCorruptedExceptions were
  1293. * rarely (if ever) actually thrown--the "root" exceptions from
  1294. * underlying streams were thrown instead. This historical behavior is
  1295. * followed here for consistency.
  1296. */
  1297. clear();
  1298. boolean oldMode = bout.setBlockDataMode(false);
  1299. try {
  1300. bout.writeByte(TC_EXCEPTION);
  1301. writeObject0(ex, false);
  1302. clear();
  1303. } finally {
  1304. bout.setBlockDataMode(oldMode);
  1305. }
  1306. }
  1307. /**
  1308. * Converts specified span of float values into byte values.
  1309. */
  1310. // REMIND: remove once hotspot inlines Float.floatToIntBits
  1311. private static native void floatsToBytes(float[] src, int srcpos,
  1312. byte[] dst, int dstpos,
  1313. int nfloats);
  1314. /**
  1315. * Converts specified span of double values into byte values.
  1316. */
  1317. // REMIND: remove once hotspot inlines Double.doubleToLongBits
  1318. private static native void doublesToBytes(double[] src, int srcpos,
  1319. byte[] dst, int dstpos,
  1320. int ndoubles);
  1321. /**
  1322. * Default PutField implementation.
  1323. */
  1324. private class PutFieldImpl extends PutField {
  1325. /** class descriptor describing serializable fields */
  1326. private final ObjectStreamClass desc;
  1327. /** primitive field values */
  1328. private final byte[] primVals;
  1329. /** object field values */
  1330. private final Object[] objVals;
  1331. /**
  1332. * Creates PutFieldImpl object for writing fields defined in given
  1333. * class descriptor.
  1334. */
  1335. PutFieldImpl(ObjectStreamClass desc) {
  1336. this.desc = desc;
  1337. primVals = new byte[desc.getPrimDataSize()];
  1338. objVals = new Object[desc.getNumObjFields()];
  1339. }
  1340. public void put(String name, boolean val) {
  1341. Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
  1342. }
  1343. public void put(String name, byte val) {
  1344. primVals[getFieldOffset(name, Byte.TYPE)] = val;
  1345. }
  1346. public void put(String name, char val) {
  1347. Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
  1348. }
  1349. public void put(String name, short val) {
  1350. Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
  1351. }
  1352. public void put(String name, int val) {
  1353. Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
  1354. }
  1355. public void put(String name, float val) {
  1356. Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
  1357. }
  1358. public void put(String name, long val) {
  1359. Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
  1360. }
  1361. public void put(String name, double val) {
  1362. Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
  1363. }
  1364. public void put(String name, Object val) {
  1365. objVals[getFieldOffset(name, Object.class)] = val;
  1366. }
  1367. // deprecated in ObjectOutputStream.PutField
  1368. public void write(ObjectOutput out) throws IOException {
  1369. /*
  1370. * Applications should *not* use this method to write PutField
  1371. * data, as it will lead to stream corruption if the PutField
  1372. * object writes any primitive data (since block data mode is not
  1373. * unset/set properly, as is done in OOS.writeFields()). This
  1374. * broken implementation is being retained solely for behavioral
  1375. * compatibility, in order to support applications which use
  1376. * OOS.PutField.write() for writing only non-primitive data.
  1377. *
  1378. * Serialization of unshared objects is not implemented here since
  1379. * it is not necessary for backwards compatibility; also, unshared
  1380. * semantics may not be supported by the given ObjectOutput
  1381. * instance. Applications which write unshared objects using the
  1382. * PutField API must use OOS.writeFields().
  1383. */
  1384. out.write(primVals, 0, primVals.length);
  1385. ObjectStreamField[] fields = desc.getFields(false);
  1386. int numPrimFields = fields.length - objVals.length;
  1387. // REMIND: warn if numPrimFields > 0?
  1388. for (int i = 0; i < objVals.length; i++) {
  1389. if (fields[numPrimFields + i].isUnshared()) {
  1390. throw new IOException("cannot write unshared object");
  1391. }
  1392. out.writeObject(objVals[i]);
  1393. }
  1394. }
  1395. /**
  1396. * Writes buffered primitive data and object fields to stream.
  1397. */
  1398. void writeFields() throws IOException {
  1399. bout.write(primVals, 0, primVals.length, false);
  1400. ObjectStreamField[] fields = desc.getFields(false);
  1401. int numPrimFields = fields.length - objVals.length;
  1402. for (int i = 0; i < objVals.length; i++) {
  1403. writeObject0(
  1404. objVals[i], fields[numPrimFields + i].isUnshared());
  1405. }
  1406. }
  1407. /**
  1408. * Returns offset of field with given name and type. A specified type
  1409. * of null matches all types, Object.class matches all non-primitive
  1410. * types, and any other non-null type matches assignable types only.
  1411. * Throws IllegalArgumentException if no matching field found.
  1412. */
  1413. private int getFieldOffset(String name, Class type) {
  1414. ObjectStreamField field = desc.getField(name, type);
  1415. if (field == null) {
  1416. throw new IllegalArgumentException("no such field");
  1417. }
  1418. return field.getOffset();
  1419. }
  1420. }
  1421. /**
  1422. * Buffered output stream with two modes: in default mode, outputs data in
  1423. * same format as DataOutputStream; in "block data" mode, outputs data
  1424. * bracketed by block data markers (see object serialization specification
  1425. * for details).
  1426. */
  1427. private static class BlockDataOutputStream
  1428. extends OutputStream implements DataOutput
  1429. {
  1430. /** maximum data block length */
  1431. private static final int MAX_BLOCK_SIZE = 1024;
  1432. /** maximum data block header length */
  1433. private static final int MAX_HEADER_SIZE = 5;
  1434. /** (tunable) length of char buffer (for writing strings) */
  1435. private static final int CHAR_BUF_SIZE = 256;
  1436. /** buffer for writing general/block data */
  1437. private final byte[] buf = new byte[MAX_BLOCK_SIZE];
  1438. /** buffer for writing block data headers */
  1439. private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
  1440. /** char buffer for fast string writes */
  1441. private final char[] cbuf = new char[CHAR_BUF_SIZE];
  1442. /** block data mode */
  1443. private boolean blkmode = false;
  1444. /** current offset into buf */
  1445. private int pos = 0;
  1446. /** underlying output stream */
  1447. private final OutputStream out;
  1448. /** loopback stream (for data writes that span data blocks) */
  1449. private final DataOutputStream dout;
  1450. /**
  1451. * Creates new BlockDataOutputStream on top of given underlying stream.
  1452. * Block data mode is turned off by default.
  1453. */
  1454. BlockDataOutputStream(OutputStream out) {
  1455. this.out = out;
  1456. dout = new DataOutputStream(this);
  1457. }
  1458. /**
  1459. * Sets block data mode to the given mode (true == on, false == off)
  1460. * and returns the previous mode value. If the new mode is the same as
  1461. * the old mode, no action is taken. If the new mode differs from the
  1462. * old mode, any buffered data is flushed before switching to the new
  1463. * mode.
  1464. */
  1465. boolean setBlockDataMode(boolean mode) throws IOException {
  1466. if (blkmode == mode) {
  1467. return blkmode;
  1468. }
  1469. drain();
  1470. blkmode = mode;
  1471. return !blkmode;
  1472. }
  1473. /**
  1474. * Returns true if the stream is currently in block data mode, false
  1475. * otherwise.
  1476. */
  1477. boolean getBlockDataMode() {
  1478. return blkmode;
  1479. }
  1480. /* ----------------- generic output stream methods ----------------- */
  1481. /*
  1482. * The following methods are equivalent to their counterparts in
  1483. * OutputStream, except that they partition written data into data
  1484. * blocks when in block data mode.
  1485. */
  1486. public void write(int b) throws IOException {
  1487. if (pos >= MAX_BLOCK_SIZE) {
  1488. drain();
  1489. }
  1490. buf[pos++] = (byte) b;
  1491. }
  1492. public void write(byte[] b) throws IOException {
  1493. write(b, 0, b.length, false);
  1494. }
  1495. public void write(byte[] b, int off, int len) throws IOException {
  1496. write(b, off, len, false);
  1497. }
  1498. public void flush() throws IOException {
  1499. drain();
  1500. out.flush();
  1501. }
  1502. public void close() throws IOException {
  1503. flush();
  1504. out.close();
  1505. }
  1506. /**
  1507. * Writes specified span of byte values from given array. If copy is
  1508. * true, copies the values to an intermediate buffer before writing
  1509. * them to underlying stream (to avoid exposing a reference to the
  1510. * original byte array).
  1511. */
  1512. void write(byte[] b, int off, int len, boolean copy)
  1513. throws IOException
  1514. {
  1515. if (!(copy || blkmode)) { // write directly
  1516. drain();
  1517. out.write(b, off, len);
  1518. return;
  1519. }
  1520. while (len > 0) {
  1521. if (pos >= MAX_BLOCK_SIZE) {
  1522. drain();
  1523. }
  1524. if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) {
  1525. // avoid unnecessary copy
  1526. writeBlockHeader(MAX_BLOCK_SIZE);
  1527. out.write(b, off, MAX_BLOCK_SIZE);
  1528. off += MAX_BLOCK_SIZE;
  1529. len -= MAX_BLOCK_SIZE;
  1530. } else {
  1531. int wlen = Math.min(len, MAX_BLOCK_SIZE - pos);
  1532. System.arraycopy(b, off, buf, pos, wlen);
  1533. pos += wlen;
  1534. off += wlen;
  1535. len -= wlen;
  1536. }
  1537. }
  1538. }
  1539. /**
  1540. * Writes all buffered data from this stream to the underlying stream,
  1541. * but does not flush underlying stream.
  1542. */
  1543. void drain() throws IOException {
  1544. if (pos == 0) {
  1545. return;
  1546. }
  1547. if (blkmode) {
  1548. writeBlockHeader(pos);
  1549. }
  1550. out.write(buf, 0, pos);
  1551. pos = 0;
  1552. }
  1553. /**
  1554. * Writes block data header. Data blocks shorter than 256 bytes are
  1555. * prefixed with a 2-byte header; all others start with a 5-byte
  1556. * header.
  1557. */
  1558. private void writeBlockHeader(int len) throws IOException {
  1559. if (len <= 0xFF) {
  1560. hbuf[0] = TC_BLOCKDATA;
  1561. hbuf[1] = (byte) len;
  1562. out.write(hbuf, 0, 2);
  1563. } else {
  1564. hbuf[0] = TC_BLOCKDATALONG;
  1565. Bits.putInt(hbuf, 1, len);
  1566. out.write(hbuf, 0, 5);
  1567. }
  1568. }
  1569. /* ----------------- primitive data output methods ----------------- */
  1570. /*
  1571. * The following methods are equivalent to their counterparts in
  1572. * DataOutputStream, except that they partition written data into data
  1573. * blocks when in block data mode.
  1574. */
  1575. public void writeBoolean(boolean v) throws IOException {
  1576. if (pos >= MAX_BLOCK_SIZE) {
  1577. drain();
  1578. }
  1579. Bits.putBoolean(buf, pos++, v);
  1580. }
  1581. public void writeByte(int v) throws IOException {
  1582. if (pos >= MAX_BLOCK_SIZE) {
  1583. drain();
  1584. }
  1585. buf[pos++] = (byte) v;
  1586. }
  1587. public void writeChar(int v) throws IOException {
  1588. if (pos + 2 <= MAX_BLOCK_SIZE) {
  1589. Bits.putChar(buf, pos, (char) v);
  1590. pos += 2;
  1591. } else {
  1592. dout.writeChar(v);
  1593. }
  1594. }
  1595. public void writeShort(int v) throws IOException {
  1596. if (pos + 2 <= MAX_BLOCK_SIZE) {
  1597. Bits.putShort(buf, pos, (short) v);
  1598. pos += 2;
  1599. } else {
  1600. dout.writeShort(v);
  1601. }
  1602. }
  1603. public void writeInt(int v) throws IOException {
  1604. if (pos + 4 <= MAX_BLOCK_SIZE) {
  1605. Bits.putInt(buf, pos, v);
  1606. pos += 4;
  1607. } else {
  1608. dout.writeInt(v);
  1609. }
  1610. }
  1611. public void writeFloat(float v) throws IOException {
  1612. if (pos + 4 <= MAX_BLOCK_SIZE) {
  1613. Bits.putFloat(buf, pos, v);
  1614. pos += 4;
  1615. } else {
  1616. dout.writeFloat(v);
  1617. }
  1618. }
  1619. public void writeLong(long v) throws IOException {
  1620. if (pos + 8 <= MAX_BLOCK_SIZE) {
  1621. Bits.putLong(buf, pos, v);
  1622. pos += 8;
  1623. } else {
  1624. dout.writeLong(v);
  1625. }
  1626. }
  1627. public void writeDouble(double v) throws IOException {
  1628. if (pos + 8 <= MAX_BLOCK_SIZE) {
  1629. Bits.putDouble(buf, pos, v);
  1630. pos += 8;
  1631. } else {
  1632. dout.writeDouble(v);
  1633. }
  1634. }
  1635. public void writeBytes(String s) throws IOException {
  1636. int endoff = s.length();
  1637. int cpos = 0;
  1638. int csize = 0;
  1639. for (int off = 0; off < endoff; ) {
  1640. if (cpos >= csize) {
  1641. cpos = 0;
  1642. csize = Math.min(endoff - off, CHAR_BUF_SIZE);
  1643. s.getChars(off, off + csize, cbuf, 0);
  1644. }
  1645. if (pos >= MAX_BLOCK_SIZE) {
  1646. drain();
  1647. }
  1648. int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
  1649. int stop = pos + n;
  1650. while (pos < stop) {
  1651. buf[pos++] = (byte) cbuf[cpos++];
  1652. }
  1653. off += n;
  1654. }
  1655. }
  1656. public void writeChars(String s) throws IOException {
  1657. int endoff = s.length();
  1658. for (int off = 0; off < endoff; ) {
  1659. int csize = Math.min(endoff - off, CHAR_BUF_SIZE);
  1660. s.getChars(off, off + csize, cbuf, 0);
  1661. writeChars(cbuf, 0, csize);
  1662. off += csize;
  1663. }
  1664. }
  1665. public void writeUTF(String s) throws IOException {
  1666. writeUTF(s, getUTFLength(s));
  1667. }
  1668. /* -------------- primitive data array output methods -------------- */
  1669. /*
  1670. * The following methods write out spans of primitive data values.
  1671. * Though equivalent to calling the corresponding primitive write
  1672. * methods repeatedly, these methods are optimized for writing groups
  1673. * of primitive data values more efficiently.
  1674. */
  1675. void writeBooleans(boolean[] v, int off, int len) throws IOException {
  1676. int endoff = off + len;
  1677. while (off < endoff) {
  1678. if (pos >= MAX_BLOCK_SIZE) {
  1679. drain();
  1680. }
  1681. int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos));
  1682. while (off < stop) {
  1683. Bits.putBoolean(buf, pos++, v[off++]);
  1684. }
  1685. }
  1686. }
  1687. void writeChars(char[] v, int off, int len) throws IOException {
  1688. int limit = MAX_BLOCK_SIZE - 2;
  1689. int endoff = off + len;
  1690. while (off < endoff) {
  1691. if (pos <= limit) {
  1692. int avail = (MAX_BLOCK_SIZE - pos) >> 1;
  1693. int stop = Math.min(endoff, off + avail);
  1694. while (off < stop) {
  1695. Bits.putChar(buf, pos, v[off++]);
  1696. pos += 2;
  1697. }
  1698. } else {
  1699. dout.writeChar(v[off++]);
  1700. }
  1701. }
  1702. }
  1703. void writeShorts(short[] v, int off, int len) throws IOException {
  1704. int limit = MAX_BLOCK_SIZE - 2;
  1705. int endoff = off + len;
  1706. while (off < endoff) {
  1707. if (pos <= limit) {
  1708. int avail = (MAX_BLOCK_SIZE - pos) >> 1;
  1709. int stop = Math.min(endoff, off + avail);
  1710. while (off < stop) {
  1711. Bits.putShort(buf, pos, v[off++]);
  1712. pos += 2;
  1713. }
  1714. } else {
  1715. dout.writeShort(v[off++]);
  1716. }
  1717. }
  1718. }
  1719. void writeInts(int[] v, int off, int len) throws IOException {
  1720. int limit = MAX_BLOCK_SIZE - 4;
  1721. int endoff = off + len;
  1722. while (off < endoff) {
  1723. if (pos <= limit) {
  1724. int avail = (MAX_BLOCK_SIZE - pos) >> 2;
  1725. int stop = Math.min(endoff, off + avail);
  1726. while (off < stop) {
  1727. Bits.putInt(buf, pos, v[off++]);
  1728. pos += 4;
  1729. }
  1730. } else {
  1731. dout.writeInt(v[off++]);
  1732. }
  1733. }
  1734. }
  1735. void writeFloats(float[] v, int off, int len) throws IOException {
  1736. int limit = MAX_BLOCK_SIZE - 4;
  1737. int endoff = off + len;
  1738. while (off < endoff) {
  1739. if (pos <= limit) {
  1740. int avail = (MAX_BLOCK_SIZE - pos) >> 2;
  1741. int chunklen = Math.min(endoff - off, avail);
  1742. floatsToBytes(v, off, buf, pos, chunklen);
  1743. off += chunklen;
  1744. pos += chunklen << 2;
  1745. } else {
  1746. dout.writeFloat(v[off++]);
  1747. }
  1748. }
  1749. }
  1750. void writeLongs(long[] v, int off, int len) throws IOException {
  1751. int limit = MAX_BLOCK_SIZE - 8;
  1752. int endoff = off + len;
  1753. while (off < endoff) {
  1754. if (pos <= limit) {
  1755. int avail = (MAX_BLOCK_SIZE - pos) >> 3;
  1756. int stop = Math.min(endoff, off + avail);
  1757. while (off < stop) {
  1758. Bits.putLong(buf, pos, v[off++]);
  1759. pos += 8;
  1760. }
  1761. } else {
  1762. dout.writeLong(v[off++]);
  1763. }
  1764. }
  1765. }
  1766. void writeDoubles(double[] v, int off, int len) throws IOException {
  1767. int limit = MAX_BLOCK_SIZE - 8;
  1768. int endoff = off + len;
  1769. while (off < endoff) {
  1770. if (pos <= limit) {
  1771. int avail = (MAX_BLOCK_SIZE - pos) >> 3;
  1772. int chunklen = Math.min(endoff - off, avail);
  1773. doublesToBytes(v, off, buf, pos, chunklen);
  1774. off += chunklen;
  1775. pos += chunklen << 3;
  1776. } else {
  1777. dout.writeDouble(v[off++]);
  1778. }
  1779. }
  1780. }
  1781. /**
  1782. * Returns the length in bytes of the UTF encoding of the given string.
  1783. */
  1784. long getUTFLength(String s) {
  1785. int len = s.length();
  1786. long utflen = 0;
  1787. for (int off = 0; off < len; ) {
  1788. int csize = Math.min(len - off, CHAR_BUF_SIZE);
  1789. s.getChars(off, off + csize, cbuf, 0);
  1790. for (int cpos = 0; cpos < csize; cpos++) {
  1791. char c = cbuf[cpos];
  1792. if (c >= 0x0001 && c <= 0x007F) {
  1793. utflen++;
  1794. } else if (c > 0x07FF) {
  1795. utflen += 3;
  1796. } else {
  1797. utflen += 2;
  1798. }
  1799. }
  1800. off += csize;
  1801. }
  1802. return utflen;
  1803. }
  1804. /**
  1805. * Writes the given string in UTF format. This method is used in
  1806. * situations where the UTF encoding length of the string is already
  1807. * known; specifying it explicitly avoids a prescan of the string to
  1808. * determine its UTF length.
  1809. */
  1810. void writeUTF(String s, long utflen) throws IOException {
  1811. if (utflen > 0xFFFFL) {
  1812. throw new UTFDataFormatException();
  1813. }
  1814. writeShort((int) utflen);
  1815. if (utflen == (long) s.length()) {
  1816. writeBytes(s);
  1817. } else {
  1818. writeUTFBody(s);
  1819. }
  1820. }
  1821. /**
  1822. * Writes given string in "long" UTF format. "Long" UTF format is
  1823. * identical to standard UTF, except that it uses an 8 byte header
  1824. * (instead of the standard 2 bytes) to convey the UTF encoding length.
  1825. */
  1826. void writeLongUTF(String s) throws IOException {
  1827. writeLongUTF(s, getUTFLength(s));
  1828. }
  1829. /**
  1830. * Writes given string in "long" UTF format, where the UTF encoding
  1831. * length of the string is already known.
  1832. */
  1833. void writeLongUTF(String s, long utflen) throws IOException {
  1834. writeLong(utflen);
  1835. if (utflen == (long) s.length()) {
  1836. writeBytes(s);
  1837. } else {
  1838. writeUTFBody(s);
  1839. }
  1840. }
  1841. /**
  1842. * Writes the "body" (i.e., the UTF representation minus the 2-byte or
  1843. * 8-byte length header) of the UTF encoding for the given string.
  1844. */
  1845. private void writeUTFBody(String s) throws IOException {
  1846. int limit = MAX_BLOCK_SIZE - 3;
  1847. int len = s.length();
  1848. for (int off = 0; off < len; ) {
  1849. int csize = Math.min(len - off, CHAR_BUF_SIZE);
  1850. s.getChars(off, off + csize, cbuf, 0);
  1851. for (int cpos = 0; cpos < csize; cpos++) {
  1852. char c = cbuf[cpos];
  1853. if (pos <= limit) {
  1854. if (c <= 0x007F && c != 0) {
  1855. buf[pos++] = (byte) c;
  1856. } else if (c > 0x07FF) {
  1857. buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
  1858. buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
  1859. buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
  1860. pos += 3;
  1861. } else {
  1862. buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
  1863. buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
  1864. pos += 2;
  1865. }
  1866. } else { // write one byte at a time to normalize block
  1867. if (c <= 0x007F && c != 0) {
  1868. write(c);
  1869. } else if (c > 0x07FF) {
  1870. write(0xE0 | ((c >> 12) & 0x0F));
  1871. write(0x80 | ((c >> 6) & 0x3F));
  1872. write(0x80 | ((c >> 0) & 0x3F));
  1873. } else {
  1874. write(0xC0 | ((c >> 6) & 0x1F));
  1875. write(0x80 | ((c >> 0) & 0x3F));
  1876. }
  1877. }
  1878. }
  1879. off += csize;
  1880. }
  1881. }
  1882. }
  1883. /**
  1884. * Lightweight identity hash table which maps objects to integer handles,
  1885. * assigned in ascending order.
  1886. */
  1887. private static class HandleTable {
  1888. /* number of mappings in table/next available handle */
  1889. private int size;
  1890. /* size threshold determining when to expand hash spine */
  1891. private int threshold;
  1892. /* factor for computing size threshold */
  1893. private final float loadFactor;
  1894. /* maps hash value -> candidate handle value */
  1895. private int[] spine;
  1896. /* maps handle value -> next candidate handle value */
  1897. private int[] next;
  1898. /* maps handle value -> associated object */
  1899. private Object[] objs;
  1900. /**
  1901. * Creates new HandleTable with given capacity and load factor.
  1902. */
  1903. HandleTable(int initialCapacity, float loadFactor) {
  1904. this.loadFactor = loadFactor;
  1905. spine = new int[initialCapacity];
  1906. next = new int[initialCapacity];
  1907. objs = new Object[initialCapacity];
  1908. threshold = (int) (initialCapacity * loadFactor);
  1909. clear();
  1910. }
  1911. /**
  1912. * Assigns next available handle to given object, and returns handle
  1913. * value. Handles are assigned in ascending order starting at 0.
  1914. */
  1915. int assign(Object obj) {
  1916. if (size >= next.length) {
  1917. growEntries();
  1918. }
  1919. if (size >= threshold) {
  1920. growSpine();
  1921. }
  1922. insert(obj, size);
  1923. return size++;
  1924. }
  1925. /**
  1926. * Looks up and returns handle associated with given object, or -1 if
  1927. * no mapping found.
  1928. */
  1929. int lookup(Object obj) {
  1930. if (size == 0) {
  1931. return -1;
  1932. }
  1933. int index = hash(obj) % spine.length;
  1934. for (int i = spine[index]; i >= 0; i = next[i]) {
  1935. if (objs[i] == obj) {
  1936. return i;
  1937. }
  1938. }
  1939. return -1;
  1940. }
  1941. /**
  1942. * Resets table to its initial (empty) state.
  1943. */
  1944. void clear() {
  1945. Arrays.fill(spine, -1);
  1946. Arrays.fill(objs, 0, size, null);
  1947. size = 0;
  1948. }
  1949. /**
  1950. * Returns the number of mappings currently in table.
  1951. */
  1952. int size() {
  1953. return size;
  1954. }
  1955. /**
  1956. * Inserts mapping object -> handle mapping into table. Assumes table
  1957. * is large enough to accommodate new mapping.
  1958. */
  1959. private void insert(Object obj, int handle) {
  1960. int index = hash(obj) % spine.length;
  1961. objs[handle] = obj;
  1962. next[handle] = spine[index];
  1963. spine[index] = handle;
  1964. }
  1965. /**
  1966. * Expands the hash "spine" -- equivalent to increasing the number of
  1967. * buckets in a conventional hash table.
  1968. */
  1969. private void growSpine() {
  1970. spine = new int[(spine.length << 1) + 1];
  1971. threshold = (int) (spine.length * loadFactor);
  1972. Arrays.fill(spine, -1);
  1973. for (int i = 0; i < size; i++) {
  1974. insert(objs[i], i);
  1975. }
  1976. }
  1977. /**
  1978. * Increases hash table capacity by lengthening entry arrays.
  1979. */
  1980. private void growEntries() {
  1981. int newLength = (next.length << 1) + 1;
  1982. int[] newNext = new int[newLength];
  1983. System.arraycopy(next, 0, newNext, 0, size);
  1984. next = newNext;
  1985. Object[] newObjs = new Object[newLength];
  1986. System.arraycopy(objs, 0, newObjs, 0, size);
  1987. objs = newObjs;
  1988. }
  1989. /**
  1990. * Returns hash value for given object.
  1991. */
  1992. private int hash(Object obj) {
  1993. return System.identityHashCode(obj) & 0x7FFFFFFF;
  1994. }
  1995. }
  1996. /**
  1997. * Lightweight identity hash table which maps objects to replacement
  1998. * objects.
  1999. */
  2000. private static class ReplaceTable {
  2001. /* maps object -> index */
  2002. private final HandleTable htab;
  2003. /* maps index -> replacement object */
  2004. private Object[] reps;
  2005. /**
  2006. * Creates new ReplaceTable with given capacity and load factor.
  2007. */
  2008. ReplaceTable(int initialCapacity, float loadFactor) {
  2009. htab = new HandleTable(initialCapacity, loadFactor);
  2010. reps = new Object[initialCapacity];
  2011. }
  2012. /**
  2013. * Enters mapping from object to replacement object.
  2014. */
  2015. void assign(Object obj, Object rep) {
  2016. int index = htab.assign(obj);
  2017. while (index >= reps.length) {
  2018. grow();
  2019. }
  2020. reps[index] = rep;
  2021. }
  2022. /**
  2023. * Looks up and returns replacement for given object. If no
  2024. * replacement is found, returns the lookup object itself.
  2025. */
  2026. Object lookup(Object obj) {
  2027. int index = htab.lookup(obj);
  2028. return (index >= 0) ? reps[index] : obj;
  2029. }
  2030. /**
  2031. * Resets table to its initial (empty) state.
  2032. */
  2033. void clear() {
  2034. Arrays.fill(reps, 0, htab.size(), null);
  2035. htab.clear();
  2036. }
  2037. /**
  2038. * Returns the number of mappings currently in table.
  2039. */
  2040. int size() {
  2041. return htab.size();
  2042. }
  2043. /**
  2044. * Increases table capacity.
  2045. */
  2046. private void grow() {
  2047. Object[] newReps = new Object[(reps.length << 1) + 1];
  2048. System.arraycopy(reps, 0, newReps, 0, reps.length);
  2049. reps = newReps;
  2050. }
  2051. }
  2052. }