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