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