ObjectInputStream.java revision 3d93b50c1e9d8cb12d17a4331edd27ee2a1dc7a9
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.io; 19 20import dalvik.system.VMStack; 21import java.io.EmulatedFields.ObjectSlot; 22import java.lang.reflect.Array; 23import java.lang.reflect.Field; 24import java.lang.reflect.InvocationTargetException; 25import java.lang.reflect.Method; 26import java.lang.reflect.Proxy; 27import java.security.PrivilegedAction; 28import java.util.ArrayList; 29import java.util.Arrays; 30import java.util.HashMap; 31import java.util.List; 32import libcore.util.EmptyArray; 33 34/** 35 * A specialized {@link InputStream} that is able to read (deserialize) Java 36 * objects as well as primitive data types (int, byte, char etc.). The data has 37 * typically been saved using an ObjectOutputStream. 38 * 39 * @see ObjectOutputStream 40 * @see ObjectInput 41 * @see Serializable 42 * @see Externalizable 43 */ 44public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants { 45 46 // TODO: this is non-static to avoid sync contention. Would static be faster? 47 private InputStream emptyStream = new ByteArrayInputStream(EmptyArray.BYTE); 48 49 // To put into objectsRead when reading unsharedObject 50 private static final Object UNSHARED_OBJ = new Object(); // $NON-LOCK-1$ 51 52 // If the receiver has already read & not consumed a TC code 53 private boolean hasPushbackTC; 54 55 // Push back TC code if the variable above is true 56 private byte pushbackTC; 57 58 // How many nested levels to readObject. When we reach 0 we have to validate 59 // the graph then reset it 60 private int nestedLevels; 61 62 // All objects are assigned an ID (integer handle) 63 private int nextHandle; 64 65 // Where we read from 66 private DataInputStream input; 67 68 // Where we read primitive types from 69 private DataInputStream primitiveTypes; 70 71 // Where we keep primitive type data 72 private InputStream primitiveData = emptyStream; 73 74 // Resolve object is a mechanism for replacement 75 private boolean enableResolve; 76 77 /** 78 * All the objects we've read, indexed by their serialization handle (minus the base offset). 79 */ 80 private ArrayList<Object> objectsRead; 81 82 // Used by defaultReadObject 83 private Object currentObject; 84 85 // Used by defaultReadObject 86 private ObjectStreamClass currentClass; 87 88 // All validations to be executed when the complete graph is read. See inner 89 // type below. 90 private InputValidationDesc[] validations; 91 92 // Allows the receiver to decide if it needs to call readObjectOverride 93 private boolean subclassOverridingImplementation; 94 95 // Original caller's class loader, used to perform class lookups 96 private ClassLoader callerClassLoader; 97 98 // false when reading missing fields 99 private boolean mustResolve = true; 100 101 // Handle for the current class descriptor 102 private int descriptorHandle = -1; 103 104 private static final HashMap<String, Class<?>> PRIMITIVE_CLASSES = new HashMap<String, Class<?>>(); 105 static { 106 PRIMITIVE_CLASSES.put("boolean", boolean.class); 107 PRIMITIVE_CLASSES.put("byte", byte.class); 108 PRIMITIVE_CLASSES.put("char", char.class); 109 PRIMITIVE_CLASSES.put("double", double.class); 110 PRIMITIVE_CLASSES.put("float", float.class); 111 PRIMITIVE_CLASSES.put("int", int.class); 112 PRIMITIVE_CLASSES.put("long", long.class); 113 PRIMITIVE_CLASSES.put("short", short.class); 114 PRIMITIVE_CLASSES.put("void", void.class); 115 } 116 117 // Internal type used to keep track of validators & corresponding priority 118 static class InputValidationDesc { 119 ObjectInputValidation validator; 120 121 int priority; 122 } 123 124 /** 125 * GetField is an inner class that provides access to the persistent fields 126 * read from the source stream. 127 */ 128 public abstract static class GetField { 129 /** 130 * Gets the ObjectStreamClass that describes a field. 131 * 132 * @return the descriptor class for a serialized field. 133 */ 134 public abstract ObjectStreamClass getObjectStreamClass(); 135 136 /** 137 * Indicates if the field identified by {@code name} is defaulted. This 138 * means that it has no value in this stream. 139 * 140 * @param name 141 * the name of the field to check. 142 * @return {@code true} if the field is defaulted, {@code false} 143 * otherwise. 144 * @throws IllegalArgumentException 145 * if {@code name} does not identify a serializable field. 146 * @throws IOException 147 * if an error occurs while reading from the source input 148 * stream. 149 */ 150 public abstract boolean defaulted(String name) throws IOException, 151 IllegalArgumentException; 152 153 /** 154 * Gets the value of the boolean field identified by {@code name} from 155 * the persistent field. 156 * 157 * @param name 158 * the name of the field to get. 159 * @param defaultValue 160 * the default value that is used if the field does not have 161 * a value when read from the source stream. 162 * @return the value of the field identified by {@code name}. 163 * @throws IOException 164 * if an error occurs while reading from the source input 165 * stream. 166 * @throws IllegalArgumentException 167 * if the type of the field identified by {@code name} is 168 * not {@code boolean}. 169 */ 170 public abstract boolean get(String name, boolean defaultValue) 171 throws IOException, IllegalArgumentException; 172 173 /** 174 * Gets the value of the character field identified by {@code name} from 175 * the persistent field. 176 * 177 * @param name 178 * the name of the field to get. 179 * @param defaultValue 180 * the default value that is used if the field does not have 181 * a value when read from the source stream. 182 * @return the value of the field identified by {@code name}. 183 * @throws IOException 184 * if an error occurs while reading from the source input 185 * stream. 186 * @throws IllegalArgumentException 187 * if the type of the field identified by {@code name} is 188 * not {@code char}. 189 */ 190 public abstract char get(String name, char defaultValue) 191 throws IOException, IllegalArgumentException; 192 193 /** 194 * Gets the value of the byte field identified by {@code name} from the 195 * persistent field. 196 * 197 * @param name 198 * the name of the field to get. 199 * @param defaultValue 200 * the default value that is used if the field does not have 201 * a value when read from the source stream. 202 * @return the value of the field identified by {@code name}. 203 * @throws IOException 204 * if an error occurs while reading from the source input 205 * stream. 206 * @throws IllegalArgumentException 207 * if the type of the field identified by {@code name} is 208 * not {@code byte}. 209 */ 210 public abstract byte get(String name, byte defaultValue) 211 throws IOException, IllegalArgumentException; 212 213 /** 214 * Gets the value of the short field identified by {@code name} from the 215 * persistent field. 216 * 217 * @param name 218 * the name of the field to get. 219 * @param defaultValue 220 * the default value that is used if the field does not have 221 * a value when read from the source stream. 222 * @return the value of the field identified by {@code name}. 223 * @throws IOException 224 * if an error occurs while reading from the source input 225 * stream. 226 * @throws IllegalArgumentException 227 * if the type of the field identified by {@code name} is 228 * not {@code short}. 229 */ 230 public abstract short get(String name, short defaultValue) 231 throws IOException, IllegalArgumentException; 232 233 /** 234 * Gets the value of the integer field identified by {@code name} from 235 * the persistent field. 236 * 237 * @param name 238 * the name of the field to get. 239 * @param defaultValue 240 * the default value that is used if the field does not have 241 * a value when read from the source stream. 242 * @return the value of the field identified by {@code name}. 243 * @throws IOException 244 * if an error occurs while reading from the source input 245 * stream. 246 * @throws IllegalArgumentException 247 * if the type of the field identified by {@code name} is 248 * not {@code int}. 249 */ 250 public abstract int get(String name, int defaultValue) 251 throws IOException, IllegalArgumentException; 252 253 /** 254 * Gets the value of the long field identified by {@code name} from the 255 * persistent field. 256 * 257 * @param name 258 * the name of the field to get. 259 * @param defaultValue 260 * the default value that is used if the field does not have 261 * a value when read from the source stream. 262 * @return the value of the field identified by {@code name}. 263 * @throws IOException 264 * if an error occurs while reading from the source input 265 * stream. 266 * @throws IllegalArgumentException 267 * if the type of the field identified by {@code name} is 268 * not {@code long}. 269 */ 270 public abstract long get(String name, long defaultValue) 271 throws IOException, IllegalArgumentException; 272 273 /** 274 * Gets the value of the float field identified by {@code name} from the 275 * persistent field. 276 * 277 * @param name 278 * the name of the field to get. 279 * @param defaultValue 280 * the default value that is used if the field does not have 281 * a value when read from the source stream. 282 * @return the value of the field identified by {@code name}. 283 * @throws IOException 284 * if an error occurs while reading from the source input 285 * stream. 286 * @throws IllegalArgumentException 287 * if the type of the field identified by {@code float} is 288 * not {@code char}. 289 */ 290 public abstract float get(String name, float defaultValue) 291 throws IOException, IllegalArgumentException; 292 293 /** 294 * Gets the value of the double field identified by {@code name} from 295 * the persistent field. 296 * 297 * @param name 298 * the name of the field to get. 299 * @param defaultValue 300 * the default value that is used if the field does not have 301 * a value when read from the source stream. 302 * @return the value of the field identified by {@code name}. 303 * @throws IOException 304 * if an error occurs while reading from the source input 305 * stream. 306 * @throws IllegalArgumentException 307 * if the type of the field identified by {@code name} is 308 * not {@code double}. 309 */ 310 public abstract double get(String name, double defaultValue) 311 throws IOException, IllegalArgumentException; 312 313 /** 314 * Gets the value of the object field identified by {@code name} from 315 * the persistent field. 316 * 317 * @param name 318 * the name of the field to get. 319 * @param defaultValue 320 * the default value that is used if the field does not have 321 * a value when read from the source stream. 322 * @return the value of the field identified by {@code name}. 323 * @throws IOException 324 * if an error occurs while reading from the source input 325 * stream. 326 * @throws IllegalArgumentException 327 * if the type of the field identified by {@code name} is 328 * not {@code Object}. 329 */ 330 public abstract Object get(String name, Object defaultValue) 331 throws IOException, IllegalArgumentException; 332 } 333 334 /** 335 * Constructs a new ObjectInputStream. This default constructor can be used 336 * by subclasses that do not want to use the public constructor if it 337 * allocates unneeded data. 338 * 339 * @throws IOException 340 * if an error occurs when creating this stream. 341 */ 342 protected ObjectInputStream() throws IOException { 343 super(); 344 // WARNING - we should throw IOException if not called from a subclass 345 // according to the JavaDoc. Add the test. 346 this.subclassOverridingImplementation = true; 347 } 348 349 /** 350 * Constructs a new ObjectInputStream that reads from the InputStream 351 * {@code input}. 352 * 353 * @param input 354 * the non-null source InputStream to filter reads on. 355 * @throws IOException 356 * if an error occurs while reading the stream header. 357 * @throws StreamCorruptedException 358 * if the source stream does not contain serialized objects that 359 * can be read. 360 */ 361 public ObjectInputStream(InputStream input) throws StreamCorruptedException, IOException { 362 this.input = (input instanceof DataInputStream) 363 ? (DataInputStream) input : new DataInputStream(input); 364 primitiveTypes = new DataInputStream(this); 365 enableResolve = false; 366 this.subclassOverridingImplementation = false; 367 resetState(); 368 nestedLevels = 0; 369 // So read...() methods can be used by 370 // subclasses during readStreamHeader() 371 primitiveData = this.input; 372 // Has to be done here according to the specification 373 readStreamHeader(); 374 primitiveData = emptyStream; 375 } 376 377 @Override 378 public int available() throws IOException { 379 // returns 0 if next data is an object, or N if reading primitive types 380 checkReadPrimitiveTypes(); 381 return primitiveData.available(); 382 } 383 384 /** 385 * Checks to if it is ok to read primitive types from this stream at 386 * this point. One is not supposed to read primitive types when about to 387 * read an object, for example, so an exception has to be thrown. 388 * 389 * @throws IOException 390 * If any IO problem occurred when trying to read primitive type 391 * or if it is illegal to read primitive types 392 */ 393 private void checkReadPrimitiveTypes() throws IOException { 394 // If we still have primitive data, it is ok to read primitive data 395 if (primitiveData == input || primitiveData.available() > 0) { 396 return; 397 } 398 399 // If we got here either we had no Stream previously created or 400 // we no longer have data in that one, so get more bytes 401 do { 402 int next = 0; 403 if (hasPushbackTC) { 404 hasPushbackTC = false; 405 } else { 406 next = input.read(); 407 pushbackTC = (byte) next; 408 } 409 switch (pushbackTC) { 410 case TC_BLOCKDATA: 411 primitiveData = new ByteArrayInputStream(readBlockData()); 412 return; 413 case TC_BLOCKDATALONG: 414 primitiveData = new ByteArrayInputStream(readBlockDataLong()); 415 return; 416 case TC_RESET: 417 resetState(); 418 break; 419 default: 420 if (next != -1) { 421 pushbackTC(); 422 } 423 return; 424 } 425 // Only TC_RESET falls through 426 } while (true); 427 } 428 429 /** 430 * Closes this stream. This implementation closes the source stream. 431 * 432 * @throws IOException 433 * if an error occurs while closing this stream. 434 */ 435 @Override 436 public void close() throws IOException { 437 input.close(); 438 } 439 440 /** 441 * Default method to read objects from this stream. Serializable fields 442 * defined in the object's class and superclasses are read from the source 443 * stream. 444 * 445 * @throws ClassNotFoundException 446 * if the object's class cannot be found. 447 * @throws IOException 448 * if an I/O error occurs while reading the object data. 449 * @throws NotActiveException 450 * if this method is not called from {@code readObject()}. 451 * @see ObjectOutputStream#defaultWriteObject 452 */ 453 public void defaultReadObject() throws IOException, ClassNotFoundException, 454 NotActiveException { 455 if (currentObject != null || !mustResolve) { 456 readFieldValues(currentObject, currentClass); 457 } else { 458 throw new NotActiveException(); 459 } 460 } 461 462 /** 463 * Enables object replacement for this stream. By default this is not 464 * enabled. Only trusted subclasses (loaded with system class loader) are 465 * allowed to change this status. 466 * 467 * @param enable 468 * {@code true} to enable object replacement; {@code false} to 469 * disable it. 470 * @return the previous setting. 471 * @see #resolveObject 472 * @see ObjectOutputStream#enableReplaceObject 473 */ 474 protected boolean enableResolveObject(boolean enable) { 475 boolean originalValue = enableResolve; 476 enableResolve = enable; 477 return originalValue; 478 } 479 480 /** 481 * Return the next {@code int} handle to be used to indicate cyclic 482 * references being loaded from the stream. 483 * 484 * @return the next handle to represent the next cyclic reference 485 */ 486 private int nextHandle() { 487 return nextHandle++; 488 } 489 490 /** 491 * Return the next token code (TC) from the receiver, which indicates what 492 * kind of object follows 493 * 494 * @return the next TC from the receiver 495 * 496 * @throws IOException 497 * If an IO error occurs 498 * 499 * @see ObjectStreamConstants 500 */ 501 private byte nextTC() throws IOException { 502 if (hasPushbackTC) { 503 hasPushbackTC = false; // We are consuming it 504 } else { 505 // Just in case a later call decides to really push it back, 506 // we don't require the caller to pass it as parameter 507 pushbackTC = input.readByte(); 508 } 509 return pushbackTC; 510 } 511 512 /** 513 * Pushes back the last TC code read 514 */ 515 private void pushbackTC() { 516 hasPushbackTC = true; 517 } 518 519 /** 520 * Reads a single byte from the source stream and returns it as an integer 521 * in the range from 0 to 255. Returns -1 if the end of the source stream 522 * has been reached. Blocks if no input is available. 523 * 524 * @return the byte read or -1 if the end of the source stream has been 525 * reached. 526 * @throws IOException 527 * if an error occurs while reading from this stream. 528 */ 529 @Override 530 public int read() throws IOException { 531 checkReadPrimitiveTypes(); 532 return primitiveData.read(); 533 } 534 535 /** 536 * Reads at most {@code length} bytes from the source stream and stores them 537 * in byte array {@code buffer} starting at offset {@code count}. Blocks 538 * until {@code count} bytes have been read, the end of the source stream is 539 * detected or an exception is thrown. 540 * 541 * @param buffer 542 * the array in which to store the bytes read. 543 * @param offset 544 * the initial position in {@code buffer} to store the bytes 545 * read from the source stream. 546 * @param length 547 * the maximum number of bytes to store in {@code buffer}. 548 * @return the number of bytes read or -1 if the end of the source input 549 * stream has been reached. 550 * @throws IndexOutOfBoundsException 551 * if {@code offset < 0} or {@code length < 0}, or if 552 * {@code offset + length} is greater than the length of 553 * {@code buffer}. 554 * @throws IOException 555 * if an error occurs while reading from this stream. 556 * @throws NullPointerException 557 * if {@code buffer} is {@code null}. 558 */ 559 @Override 560 public int read(byte[] buffer, int offset, int length) throws IOException { 561 Arrays.checkOffsetAndCount(buffer.length, offset, length); 562 if (length == 0) { 563 return 0; 564 } 565 checkReadPrimitiveTypes(); 566 return primitiveData.read(buffer, offset, length); 567 } 568 569 /** 570 * Reads and returns an array of raw bytes with primitive data. The array 571 * will have up to 255 bytes. The primitive data will be in the format 572 * described by {@code DataOutputStream}. 573 * 574 * @return The primitive data read, as raw bytes 575 * 576 * @throws IOException 577 * If an IO exception happened when reading the primitive data. 578 */ 579 private byte[] readBlockData() throws IOException { 580 byte[] result = new byte[input.readByte() & 0xff]; 581 input.readFully(result); 582 return result; 583 } 584 585 /** 586 * Reads and returns an array of raw bytes with primitive data. The array 587 * will have more than 255 bytes. The primitive data will be in the format 588 * described by {@code DataOutputStream}. 589 * 590 * @return The primitive data read, as raw bytes 591 * 592 * @throws IOException 593 * If an IO exception happened when reading the primitive data. 594 */ 595 private byte[] readBlockDataLong() throws IOException { 596 byte[] result = new byte[input.readInt()]; 597 input.readFully(result); 598 return result; 599 } 600 601 /** 602 * Reads a boolean from the source stream. 603 * 604 * @return the boolean value read from the source stream. 605 * @throws EOFException 606 * if the end of the input is reached before the read 607 * request can be satisfied. 608 * @throws IOException 609 * if an error occurs while reading from the source stream. 610 */ 611 public boolean readBoolean() throws IOException { 612 return primitiveTypes.readBoolean(); 613 } 614 615 /** 616 * Reads a byte (8 bit) from the source stream. 617 * 618 * @return the byte value read from the source stream. 619 * @throws EOFException 620 * if the end of the input is reached before the read 621 * request can be satisfied. 622 * @throws IOException 623 * if an error occurs while reading from the source stream. 624 */ 625 public byte readByte() throws IOException { 626 return primitiveTypes.readByte(); 627 } 628 629 /** 630 * Reads a character (16 bit) from the source stream. 631 * 632 * @return the char value read from the source stream. 633 * @throws EOFException 634 * if the end of the input is reached before the read 635 * request can be satisfied. 636 * @throws IOException 637 * if an error occurs while reading from the source stream. 638 */ 639 public char readChar() throws IOException { 640 return primitiveTypes.readChar(); 641 } 642 643 /** 644 * Reads and discards block data and objects until TC_ENDBLOCKDATA is found. 645 * 646 * @throws IOException 647 * If an IO exception happened when reading the optional class 648 * annotation. 649 * @throws ClassNotFoundException 650 * If the class corresponding to the class descriptor could not 651 * be found. 652 */ 653 private void discardData() throws ClassNotFoundException, IOException { 654 primitiveData = emptyStream; 655 boolean resolve = mustResolve; 656 mustResolve = false; 657 do { 658 byte tc = nextTC(); 659 if (tc == TC_ENDBLOCKDATA) { 660 mustResolve = resolve; 661 return; // End of annotation 662 } 663 readContent(tc); 664 } while (true); 665 } 666 667 /** 668 * Reads a class descriptor (an {@code ObjectStreamClass}) from the 669 * stream. 670 * 671 * @return the class descriptor read from the stream 672 * 673 * @throws IOException 674 * If an IO exception happened when reading the class 675 * descriptor. 676 * @throws ClassNotFoundException 677 * If the class corresponding to the class descriptor could not 678 * be found. 679 */ 680 private ObjectStreamClass readClassDesc() throws ClassNotFoundException, IOException { 681 byte tc = nextTC(); 682 switch (tc) { 683 case TC_CLASSDESC: 684 return readNewClassDesc(false); 685 case TC_PROXYCLASSDESC: 686 Class<?> proxyClass = readNewProxyClassDesc(); 687 ObjectStreamClass streamClass = ObjectStreamClass.lookup(proxyClass); 688 streamClass.setLoadFields(ObjectStreamClass.NO_FIELDS); 689 registerObjectRead(streamClass, nextHandle(), false); 690 checkedSetSuperClassDesc(streamClass, readClassDesc()); 691 return streamClass; 692 case TC_REFERENCE: 693 return (ObjectStreamClass) readCyclicReference(); 694 case TC_NULL: 695 return null; 696 default: 697 throw corruptStream(tc); 698 } 699 } 700 701 private StreamCorruptedException corruptStream(byte tc) throws StreamCorruptedException { 702 throw new StreamCorruptedException("Wrong format: " + Integer.toHexString(tc & 0xff)); 703 } 704 705 /** 706 * Reads the content of the receiver based on the previously read token 707 * {@code tc}. 708 * 709 * @param tc 710 * The token code for the next item in the stream 711 * @return the object read from the stream 712 * 713 * @throws IOException 714 * If an IO exception happened when reading the class 715 * descriptor. 716 * @throws ClassNotFoundException 717 * If the class corresponding to the object being read could not 718 * be found. 719 */ 720 private Object readContent(byte tc) throws ClassNotFoundException, 721 IOException { 722 switch (tc) { 723 case TC_BLOCKDATA: 724 return readBlockData(); 725 case TC_BLOCKDATALONG: 726 return readBlockDataLong(); 727 case TC_CLASS: 728 return readNewClass(false); 729 case TC_CLASSDESC: 730 return readNewClassDesc(false); 731 case TC_ARRAY: 732 return readNewArray(false); 733 case TC_OBJECT: 734 return readNewObject(false); 735 case TC_STRING: 736 return readNewString(false); 737 case TC_LONGSTRING: 738 return readNewLongString(false); 739 case TC_REFERENCE: 740 return readCyclicReference(); 741 case TC_NULL: 742 return null; 743 case TC_EXCEPTION: 744 Exception exc = readException(); 745 throw new WriteAbortedException("Read an exception", exc); 746 case TC_RESET: 747 resetState(); 748 return null; 749 default: 750 throw corruptStream(tc); 751 } 752 } 753 754 /** 755 * Reads the content of the receiver based on the previously read token 756 * {@code tc}. Primitive data content is considered an error. 757 * 758 * @param unshared 759 * read the object unshared 760 * @return the object read from the stream 761 * 762 * @throws IOException 763 * If an IO exception happened when reading the class 764 * descriptor. 765 * @throws ClassNotFoundException 766 * If the class corresponding to the object being read could not 767 * be found. 768 */ 769 private Object readNonPrimitiveContent(boolean unshared) 770 throws ClassNotFoundException, IOException { 771 checkReadPrimitiveTypes(); 772 if (primitiveData.available() > 0) { 773 OptionalDataException e = new OptionalDataException(); 774 e.length = primitiveData.available(); 775 throw e; 776 } 777 778 do { 779 byte tc = nextTC(); 780 switch (tc) { 781 case TC_CLASS: 782 return readNewClass(unshared); 783 case TC_CLASSDESC: 784 return readNewClassDesc(unshared); 785 case TC_ARRAY: 786 return readNewArray(unshared); 787 case TC_OBJECT: 788 return readNewObject(unshared); 789 case TC_STRING: 790 return readNewString(unshared); 791 case TC_LONGSTRING: 792 return readNewLongString(unshared); 793 case TC_ENUM: 794 return readEnum(unshared); 795 case TC_REFERENCE: 796 if (unshared) { 797 readNewHandle(); 798 throw new InvalidObjectException("Unshared read of back reference"); 799 } 800 return readCyclicReference(); 801 case TC_NULL: 802 return null; 803 case TC_EXCEPTION: 804 Exception exc = readException(); 805 throw new WriteAbortedException("Read an exception", exc); 806 case TC_RESET: 807 resetState(); 808 break; 809 case TC_ENDBLOCKDATA: // Can occur reading class annotation 810 pushbackTC(); 811 OptionalDataException e = new OptionalDataException(); 812 e.eof = true; 813 throw e; 814 default: 815 throw corruptStream(tc); 816 } 817 // Only TC_RESET falls through 818 } while (true); 819 } 820 821 /** 822 * Reads the next item from the stream assuming it is a cyclic reference to 823 * an object previously read. Return the actual object previously read. 824 * 825 * @return the object previously read from the stream 826 * 827 * @throws IOException 828 * If an IO exception happened when reading the class 829 * descriptor. 830 * @throws InvalidObjectException 831 * If the cyclic reference is not valid. 832 */ 833 private Object readCyclicReference() throws InvalidObjectException, IOException { 834 return registeredObjectRead(readNewHandle()); 835 } 836 837 /** 838 * Reads a double (64 bit) from the source stream. 839 * 840 * @return the double value read from the source stream. 841 * @throws EOFException 842 * if the end of the input is reached before the read 843 * request can be satisfied. 844 * @throws IOException 845 * if an error occurs while reading from the source stream. 846 */ 847 public double readDouble() throws IOException { 848 return primitiveTypes.readDouble(); 849 } 850 851 /** 852 * Read the next item assuming it is an exception. The exception is not a 853 * regular instance in the object graph, but the exception instance that 854 * happened (if any) when dumping the original object graph. The set of seen 855 * objects will be reset just before and just after loading this exception 856 * object. 857 * <p> 858 * When exceptions are found normally in the object graph, they are loaded 859 * as a regular object, and not by this method. In that case, the set of 860 * "known objects" is not reset. 861 * 862 * @return the exception read 863 * 864 * @throws IOException 865 * If an IO exception happened when reading the exception 866 * object. 867 * @throws ClassNotFoundException 868 * If a class could not be found when reading the object graph 869 * for the exception 870 * @throws OptionalDataException 871 * If optional data could not be found when reading the 872 * exception graph 873 * @throws WriteAbortedException 874 * If another exception was caused when dumping this exception 875 */ 876 private Exception readException() throws WriteAbortedException, 877 OptionalDataException, ClassNotFoundException, IOException { 878 879 resetSeenObjects(); 880 881 // Now we read the Throwable object that was saved 882 // WARNING - the grammar says it is a Throwable, but the 883 // WriteAbortedException constructor takes an Exception. So, we read an 884 // Exception from the stream 885 Exception exc = (Exception) readObject(); 886 887 // We reset the receiver's state (the grammar has "reset" in normal 888 // font) 889 resetSeenObjects(); 890 return exc; 891 } 892 893 /** 894 * Reads a collection of field descriptors (name, type name, etc) for the 895 * class descriptor {@code cDesc} (an {@code ObjectStreamClass}) 896 * 897 * @param cDesc 898 * The class descriptor (an {@code ObjectStreamClass}) 899 * for which to write field information 900 * 901 * @throws IOException 902 * If an IO exception happened when reading the field 903 * descriptors. 904 * @throws ClassNotFoundException 905 * If a class for one of the field types could not be found 906 * 907 * @see #readObject() 908 */ 909 private void readFieldDescriptors(ObjectStreamClass cDesc) 910 throws ClassNotFoundException, IOException { 911 short numFields = input.readShort(); 912 ObjectStreamField[] fields = new ObjectStreamField[numFields]; 913 914 // We set it now, but each element will be inserted in the array further 915 // down 916 cDesc.setLoadFields(fields); 917 918 // Check ObjectOutputStream.writeFieldDescriptors 919 for (short i = 0; i < numFields; i++) { 920 char typecode = (char) input.readByte(); 921 String fieldName = input.readUTF(); 922 boolean isPrimType = ObjectStreamClass.isPrimitiveType(typecode); 923 String classSig; 924 if (isPrimType) { 925 classSig = String.valueOf(typecode); 926 } else { 927 // The spec says it is a UTF, but experience shows they dump 928 // this String using writeObject (unlike the field name, which 929 // is saved with writeUTF). 930 // And if resolveObject is enabled, the classSig may be modified 931 // so that the original class descriptor cannot be read 932 // properly, so it is disabled. 933 boolean old = enableResolve; 934 try { 935 enableResolve = false; 936 classSig = (String) readObject(); 937 } finally { 938 enableResolve = old; 939 } 940 } 941 942 classSig = formatClassSig(classSig); 943 ObjectStreamField f = new ObjectStreamField(classSig, fieldName); 944 fields[i] = f; 945 } 946 } 947 948 /* 949 * Format the class signature for ObjectStreamField, for example, 950 * "[L[Ljava.lang.String;;" is converted to "[Ljava.lang.String;" 951 */ 952 private static String formatClassSig(String classSig) { 953 int start = 0; 954 int end = classSig.length(); 955 956 if (end <= 0) { 957 return classSig; 958 } 959 960 while (classSig.startsWith("[L", start) 961 && classSig.charAt(end - 1) == ';') { 962 start += 2; 963 end--; 964 } 965 966 if (start > 0) { 967 start -= 2; 968 end++; 969 return classSig.substring(start, end); 970 } 971 return classSig; 972 } 973 974 /** 975 * Reads the persistent fields of the object that is currently being read 976 * from the source stream. The values read are stored in a GetField object 977 * that provides access to the persistent fields. This GetField object is 978 * then returned. 979 * 980 * @return the GetField object from which persistent fields can be accessed 981 * by name. 982 * @throws ClassNotFoundException 983 * if the class of an object being deserialized can not be 984 * found. 985 * @throws IOException 986 * if an error occurs while reading from this stream. 987 * @throws NotActiveException 988 * if this stream is currently not reading an object. 989 */ 990 public GetField readFields() throws IOException, ClassNotFoundException, NotActiveException { 991 if (currentObject == null) { 992 throw new NotActiveException(); 993 } 994 EmulatedFieldsForLoading result = new EmulatedFieldsForLoading(currentClass); 995 readFieldValues(result); 996 return result; 997 } 998 999 /** 1000 * Reads a collection of field values for the emulated fields 1001 * {@code emulatedFields} 1002 * 1003 * @param emulatedFields 1004 * an {@code EmulatedFieldsForLoading}, concrete subclass 1005 * of {@code GetField} 1006 * 1007 * @throws IOException 1008 * If an IO exception happened when reading the field values. 1009 * @throws InvalidClassException 1010 * If an incompatible type is being assigned to an emulated 1011 * field. 1012 * @throws OptionalDataException 1013 * If optional data could not be found when reading the 1014 * exception graph 1015 * 1016 * @see #readFields 1017 * @see #readObject() 1018 */ 1019 private void readFieldValues(EmulatedFieldsForLoading emulatedFields) 1020 throws OptionalDataException, InvalidClassException, IOException { 1021 EmulatedFields.ObjectSlot[] slots = emulatedFields.emulatedFields().slots(); 1022 for (ObjectSlot element : slots) { 1023 element.defaulted = false; 1024 Class<?> type = element.field.getType(); 1025 if (type == int.class) { 1026 element.fieldValue = input.readInt(); 1027 } else if (type == byte.class) { 1028 element.fieldValue = input.readByte(); 1029 } else if (type == char.class) { 1030 element.fieldValue = input.readChar(); 1031 } else if (type == short.class) { 1032 element.fieldValue = input.readShort(); 1033 } else if (type == boolean.class) { 1034 element.fieldValue = input.readBoolean(); 1035 } else if (type == long.class) { 1036 element.fieldValue = input.readLong(); 1037 } else if (type == float.class) { 1038 element.fieldValue = input.readFloat(); 1039 } else if (type == double.class) { 1040 element.fieldValue = input.readDouble(); 1041 } else { 1042 // Either array or Object 1043 try { 1044 element.fieldValue = readObject(); 1045 } catch (ClassNotFoundException cnf) { 1046 // WARNING- Not sure this is the right thing to do. Write 1047 // test case. 1048 throw new InvalidClassException(cnf.toString()); 1049 } 1050 } 1051 } 1052 } 1053 1054 /** 1055 * Reads a collection of field values for the class descriptor 1056 * {@code classDesc} (an {@code ObjectStreamClass}). The 1057 * values will be used to set instance fields in object {@code obj}. 1058 * This is the default mechanism, when emulated fields (an 1059 * {@code GetField}) are not used. Actual values to load are stored 1060 * directly into the object {@code obj}. 1061 * 1062 * @param obj 1063 * Instance in which the fields will be set. 1064 * @param classDesc 1065 * A class descriptor (an {@code ObjectStreamClass}) 1066 * defining which fields should be loaded. 1067 * 1068 * @throws IOException 1069 * If an IO exception happened when reading the field values. 1070 * @throws InvalidClassException 1071 * If an incompatible type is being assigned to an emulated 1072 * field. 1073 * @throws OptionalDataException 1074 * If optional data could not be found when reading the 1075 * exception graph 1076 * @throws ClassNotFoundException 1077 * If a class of an object being de-serialized can not be found 1078 * 1079 * @see #readFields 1080 * @see #readObject() 1081 */ 1082 private void readFieldValues(Object obj, ObjectStreamClass classDesc) throws OptionalDataException, ClassNotFoundException, IOException { 1083 // Now we must read all fields and assign them to the receiver 1084 ObjectStreamField[] fields = classDesc.getLoadFields(); 1085 fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields; 1086 Class<?> declaringClass = classDesc.forClass(); 1087 if (declaringClass == null && mustResolve) { 1088 throw new ClassNotFoundException(classDesc.getName()); 1089 } 1090 1091 for (ObjectStreamField fieldDesc : fields) { 1092 Field field = classDesc.getReflectionField(fieldDesc); 1093 // We may not have been able to find the field, but we still need to read the value 1094 // and do the other checking, so there's no null check on 'field' here. 1095 try { 1096 Class<?> type = fieldDesc.getTypeInternal(); 1097 if (type == byte.class) { 1098 byte b = input.readByte(); 1099 if (field != null) { 1100 field.setByte(obj, b); 1101 } 1102 } else if (type == char.class) { 1103 char c = input.readChar(); 1104 if (field != null) { 1105 field.setChar(obj, c); 1106 } 1107 } else if (type == double.class) { 1108 double d = input.readDouble(); 1109 if (field != null) { 1110 field.setDouble(obj, d); 1111 } 1112 } else if (type == float.class) { 1113 float f = input.readFloat(); 1114 if (field != null) { 1115 field.setFloat(obj, f); 1116 } 1117 } else if (type == int.class) { 1118 int i = input.readInt(); 1119 if (field != null) { 1120 field.setInt(obj, i); 1121 } 1122 } else if (type == long.class) { 1123 long j = input.readLong(); 1124 if (field != null) { 1125 field.setLong(obj, j); 1126 } 1127 } else if (type == short.class) { 1128 short s = input.readShort(); 1129 if (field != null) { 1130 field.setShort(obj, s); 1131 } 1132 } else if (type == boolean.class) { 1133 boolean z = input.readBoolean(); 1134 if (field != null) { 1135 field.setBoolean(obj, z); 1136 } 1137 } else { 1138 Object toSet = fieldDesc.isUnshared() ? readUnshared() : readObject(); 1139 if (toSet != null) { 1140 // Get the field type from the local field rather than 1141 // from the stream's supplied data. That's the field 1142 // we'll be setting, so that's the one that needs to be 1143 // validated. 1144 String fieldName = fieldDesc.getName(); 1145 ObjectStreamField localFieldDesc = classDesc.getField(fieldName); 1146 Class<?> fieldType = localFieldDesc.getTypeInternal(); 1147 Class<?> valueType = toSet.getClass(); 1148 if (!fieldType.isAssignableFrom(valueType)) { 1149 throw new ClassCastException(classDesc.getName() + "." + fieldName + " - " + fieldType + " not compatible with " + valueType); 1150 } 1151 if (field != null) { 1152 field.set(obj, toSet); 1153 } 1154 } 1155 } 1156 } catch (IllegalAccessException iae) { 1157 // ObjectStreamField should have called setAccessible(true). 1158 throw new AssertionError(iae); 1159 } catch (NoSuchFieldError ignored) { 1160 } 1161 } 1162 } 1163 1164 /** 1165 * Reads a float (32 bit) from the source stream. 1166 * 1167 * @return the float value read from the source stream. 1168 * @throws EOFException 1169 * if the end of the input is reached before the read 1170 * request can be satisfied. 1171 * @throws IOException 1172 * if an error occurs while reading from the source stream. 1173 */ 1174 public float readFloat() throws IOException { 1175 return primitiveTypes.readFloat(); 1176 } 1177 1178 /** 1179 * Reads bytes from the source stream into the byte array {@code dst}. 1180 * This method will block until {@code dst.length} bytes have been read. 1181 * 1182 * @param dst 1183 * the array in which to store the bytes read. 1184 * @throws EOFException 1185 * if the end of the input is reached before the read 1186 * request can be satisfied. 1187 * @throws IOException 1188 * if an error occurs while reading from the source stream. 1189 */ 1190 public void readFully(byte[] dst) throws IOException { 1191 primitiveTypes.readFully(dst); 1192 } 1193 1194 /** 1195 * Reads {@code byteCount} bytes from the source stream into the byte array {@code dst}. 1196 * 1197 * @param dst 1198 * the byte array in which to store the bytes read. 1199 * @param offset 1200 * the initial position in {@code dst} to store the bytes 1201 * read from the source stream. 1202 * @param byteCount 1203 * the number of bytes to read. 1204 * @throws EOFException 1205 * if the end of the input is reached before the read 1206 * request can be satisfied. 1207 * @throws IOException 1208 * if an error occurs while reading from the source stream. 1209 */ 1210 public void readFully(byte[] dst, int offset, int byteCount) throws IOException { 1211 primitiveTypes.readFully(dst, offset, byteCount); 1212 } 1213 1214 /** 1215 * Walks the hierarchy of classes described by class descriptor 1216 * {@code classDesc} and reads the field values corresponding to 1217 * fields declared by the corresponding class descriptor. The instance to 1218 * store field values into is {@code object}. If the class 1219 * (corresponding to class descriptor {@code classDesc}) defines 1220 * private instance method {@code readObject} it will be used to load 1221 * field values. 1222 * 1223 * @param object 1224 * Instance into which stored field values loaded. 1225 * @param classDesc 1226 * A class descriptor (an {@code ObjectStreamClass}) 1227 * defining which fields should be loaded. 1228 * 1229 * @throws IOException 1230 * If an IO exception happened when reading the field values in 1231 * the hierarchy. 1232 * @throws ClassNotFoundException 1233 * If a class for one of the field types could not be found 1234 * @throws NotActiveException 1235 * If {@code defaultReadObject} is called from the wrong 1236 * context. 1237 * 1238 * @see #defaultReadObject 1239 * @see #readObject() 1240 */ 1241 private void readHierarchy(Object object, ObjectStreamClass classDesc) 1242 throws IOException, ClassNotFoundException, NotActiveException { 1243 if (object == null && mustResolve) { 1244 throw new NotActiveException(); 1245 } 1246 1247 List<ObjectStreamClass> streamClassList = classDesc.getHierarchy(); 1248 if (object == null) { 1249 for (ObjectStreamClass objectStreamClass : streamClassList) { 1250 readObjectForClass(null, objectStreamClass); 1251 } 1252 } else { 1253 List<Class<?>> superclasses = cachedSuperclasses.get(object.getClass()); 1254 if (superclasses == null) { 1255 superclasses = cacheSuperclassesFor(object.getClass()); 1256 } 1257 1258 int lastIndex = 0; 1259 for (int i = 0, end = superclasses.size(); i < end; ++i) { 1260 Class<?> superclass = superclasses.get(i); 1261 int index = findStreamSuperclass(superclass, streamClassList, lastIndex); 1262 if (index == -1) { 1263 readObjectNoData(object, superclass, 1264 ObjectStreamClass.lookupStreamClass(superclass)); 1265 } else { 1266 for (int j = lastIndex; j <= index; j++) { 1267 readObjectForClass(object, streamClassList.get(j)); 1268 } 1269 lastIndex = index + 1; 1270 } 1271 } 1272 } 1273 } 1274 1275 private HashMap<Class<?>, List<Class<?>>> cachedSuperclasses = new HashMap<Class<?>, List<Class<?>>>(); 1276 1277 private List<Class<?>> cacheSuperclassesFor(Class<?> c) { 1278 ArrayList<Class<?>> result = new ArrayList<Class<?>>(); 1279 Class<?> nextClass = c; 1280 while (nextClass != null) { 1281 Class<?> testClass = nextClass.getSuperclass(); 1282 if (testClass != null) { 1283 result.add(0, nextClass); 1284 } 1285 nextClass = testClass; 1286 } 1287 cachedSuperclasses.put(c, result); 1288 return result; 1289 } 1290 1291 private int findStreamSuperclass(Class<?> cl, List<ObjectStreamClass> classList, int lastIndex) { 1292 for (int i = lastIndex, end = classList.size(); i < end; i++) { 1293 ObjectStreamClass objCl = classList.get(i); 1294 String forName = objCl.forClass().getName(); 1295 1296 if (objCl.getName().equals(forName)) { 1297 if (cl.getName().equals(objCl.getName())) { 1298 return i; 1299 } 1300 } else { 1301 // there was a class replacement 1302 if (cl.getName().equals(forName)) { 1303 return i; 1304 } 1305 } 1306 } 1307 return -1; 1308 } 1309 1310 private void readObjectNoData(Object object, Class<?> cl, ObjectStreamClass classDesc) 1311 throws ObjectStreamException { 1312 if (!classDesc.isSerializable()) { 1313 return; 1314 } 1315 if (classDesc.hasMethodReadObjectNoData()){ 1316 final Method readMethod = classDesc.getMethodReadObjectNoData(); 1317 try { 1318 readMethod.invoke(object); 1319 } catch (InvocationTargetException e) { 1320 Throwable ex = e.getTargetException(); 1321 if (ex instanceof RuntimeException) { 1322 throw (RuntimeException) ex; 1323 } else if (ex instanceof Error) { 1324 throw (Error) ex; 1325 } 1326 throw (ObjectStreamException) ex; 1327 } catch (IllegalAccessException e) { 1328 throw new RuntimeException(e.toString()); 1329 } 1330 } 1331 1332 } 1333 1334 private void readObjectForClass(Object object, ObjectStreamClass classDesc) 1335 throws IOException, ClassNotFoundException, NotActiveException { 1336 // Have to do this before calling defaultReadObject or anything that 1337 // calls defaultReadObject 1338 currentObject = object; 1339 currentClass = classDesc; 1340 1341 boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) != 0; 1342 Class<?> targetClass = classDesc.forClass(); 1343 1344 final Method readMethod; 1345 if (targetClass == null || !mustResolve) { 1346 readMethod = null; 1347 } else { 1348 readMethod = classDesc.getMethodReadObject(); 1349 } 1350 try { 1351 if (readMethod != null) { 1352 // We have to be able to fetch its value, even if it is private 1353 readMethod.setAccessible(true); 1354 try { 1355 readMethod.invoke(object, this); 1356 } catch (InvocationTargetException e) { 1357 Throwable ex = e.getTargetException(); 1358 if (ex instanceof ClassNotFoundException) { 1359 throw (ClassNotFoundException) ex; 1360 } else if (ex instanceof RuntimeException) { 1361 throw (RuntimeException) ex; 1362 } else if (ex instanceof Error) { 1363 throw (Error) ex; 1364 } 1365 throw (IOException) ex; 1366 } catch (IllegalAccessException e) { 1367 throw new RuntimeException(e.toString()); 1368 } 1369 } else { 1370 defaultReadObject(); 1371 } 1372 if (hadWriteMethod) { 1373 discardData(); 1374 } 1375 } finally { 1376 // Cleanup, needs to run always so that we can later detect invalid 1377 // calls to defaultReadObject 1378 currentObject = null; // We did not set this, so we do not need to 1379 // clean it 1380 currentClass = null; 1381 } 1382 } 1383 1384 /** 1385 * Reads an integer (32 bit) from the source stream. 1386 * 1387 * @return the integer value read from the source stream. 1388 * @throws EOFException 1389 * if the end of the input is reached before the read 1390 * request can be satisfied. 1391 * @throws IOException 1392 * if an error occurs while reading from the source stream. 1393 */ 1394 public int readInt() throws IOException { 1395 return primitiveTypes.readInt(); 1396 } 1397 1398 /** 1399 * Reads the next line from the source stream. Lines are terminated by 1400 * {@code '\r'}, {@code '\n'}, {@code "\r\n"} or an {@code EOF}. 1401 * 1402 * @return the string read from the source stream. 1403 * @throws IOException 1404 * if an error occurs while reading from the source stream. 1405 * @deprecated Use {@link BufferedReader} 1406 */ 1407 @Deprecated 1408 public String readLine() throws IOException { 1409 return primitiveTypes.readLine(); 1410 } 1411 1412 /** 1413 * Reads a long (64 bit) from the source stream. 1414 * 1415 * @return the long value read from the source stream. 1416 * @throws EOFException 1417 * if the end of the input is reached before the read 1418 * request can be satisfied. 1419 * @throws IOException 1420 * if an error occurs while reading from the source stream. 1421 */ 1422 public long readLong() throws IOException { 1423 return primitiveTypes.readLong(); 1424 } 1425 1426 /** 1427 * Read a new array from the receiver. It is assumed the array has not been 1428 * read yet (not a cyclic reference). Return the array read. 1429 * 1430 * @param unshared 1431 * read the object unshared 1432 * @return the array read 1433 * 1434 * @throws IOException 1435 * If an IO exception happened when reading the array. 1436 * @throws ClassNotFoundException 1437 * If a class for one of the objects could not be found 1438 * @throws OptionalDataException 1439 * If optional data could not be found when reading the array. 1440 */ 1441 private Object readNewArray(boolean unshared) throws OptionalDataException, 1442 ClassNotFoundException, IOException { 1443 ObjectStreamClass classDesc = readClassDesc(); 1444 1445 if (classDesc == null) { 1446 throw missingClassDescriptor(); 1447 } 1448 1449 int newHandle = nextHandle(); 1450 1451 // Array size 1452 int size = input.readInt(); 1453 Class<?> arrayClass = classDesc.forClass(); 1454 Class<?> componentType = arrayClass.getComponentType(); 1455 Object result = Array.newInstance(componentType, size); 1456 1457 registerObjectRead(result, newHandle, unshared); 1458 1459 // Now we have code duplication just because Java is typed. We have to 1460 // read N elements and assign to array positions, but we must typecast 1461 // the array first, and also call different methods depending on the 1462 // elements. 1463 if (componentType.isPrimitive()) { 1464 if (componentType == int.class) { 1465 int[] intArray = (int[]) result; 1466 for (int i = 0; i < size; i++) { 1467 intArray[i] = input.readInt(); 1468 } 1469 } else if (componentType == byte.class) { 1470 byte[] byteArray = (byte[]) result; 1471 input.readFully(byteArray, 0, size); 1472 } else if (componentType == char.class) { 1473 char[] charArray = (char[]) result; 1474 for (int i = 0; i < size; i++) { 1475 charArray[i] = input.readChar(); 1476 } 1477 } else if (componentType == short.class) { 1478 short[] shortArray = (short[]) result; 1479 for (int i = 0; i < size; i++) { 1480 shortArray[i] = input.readShort(); 1481 } 1482 } else if (componentType == boolean.class) { 1483 boolean[] booleanArray = (boolean[]) result; 1484 for (int i = 0; i < size; i++) { 1485 booleanArray[i] = input.readBoolean(); 1486 } 1487 } else if (componentType == long.class) { 1488 long[] longArray = (long[]) result; 1489 for (int i = 0; i < size; i++) { 1490 longArray[i] = input.readLong(); 1491 } 1492 } else if (componentType == float.class) { 1493 float[] floatArray = (float[]) result; 1494 for (int i = 0; i < size; i++) { 1495 floatArray[i] = input.readFloat(); 1496 } 1497 } else if (componentType == double.class) { 1498 double[] doubleArray = (double[]) result; 1499 for (int i = 0; i < size; i++) { 1500 doubleArray[i] = input.readDouble(); 1501 } 1502 } else { 1503 throw new ClassNotFoundException("Wrong base type in " + classDesc.getName()); 1504 } 1505 } else { 1506 // Array of Objects 1507 Object[] objectArray = (Object[]) result; 1508 for (int i = 0; i < size; i++) { 1509 // TODO: This place is the opportunity for enhancement 1510 // We can implement writing elements through fast-path, 1511 // without setting up the context (see readObject()) for 1512 // each element with public API 1513 objectArray[i] = readObject(); 1514 } 1515 } 1516 if (enableResolve) { 1517 result = resolveObject(result); 1518 registerObjectRead(result, newHandle, false); 1519 } 1520 return result; 1521 } 1522 1523 /** 1524 * Reads a new class from the receiver. It is assumed the class has not been 1525 * read yet (not a cyclic reference). Return the class read. 1526 * 1527 * @param unshared 1528 * read the object unshared 1529 * @return The {@code java.lang.Class} read from the stream. 1530 * 1531 * @throws IOException 1532 * If an IO exception happened when reading the class. 1533 * @throws ClassNotFoundException 1534 * If a class for one of the objects could not be found 1535 */ 1536 private Class<?> readNewClass(boolean unshared) throws ClassNotFoundException, IOException { 1537 ObjectStreamClass classDesc = readClassDesc(); 1538 if (classDesc == null) { 1539 throw missingClassDescriptor(); 1540 } 1541 Class<?> localClass = classDesc.forClass(); 1542 if (localClass != null) { 1543 registerObjectRead(localClass, nextHandle(), unshared); 1544 } 1545 return localClass; 1546 } 1547 1548 /* 1549 * read class type for Enum, note there's difference between enum and normal 1550 * classes 1551 */ 1552 private ObjectStreamClass readEnumDesc() throws IOException, 1553 ClassNotFoundException { 1554 byte tc = nextTC(); 1555 switch (tc) { 1556 case TC_CLASSDESC: 1557 return readEnumDescInternal(); 1558 case TC_REFERENCE: 1559 return (ObjectStreamClass) readCyclicReference(); 1560 case TC_NULL: 1561 return null; 1562 default: 1563 throw corruptStream(tc); 1564 } 1565 } 1566 1567 private ObjectStreamClass readEnumDescInternal() throws IOException, ClassNotFoundException { 1568 ObjectStreamClass classDesc; 1569 primitiveData = input; 1570 int oldHandle = descriptorHandle; 1571 descriptorHandle = nextHandle(); 1572 classDesc = readClassDescriptor(); 1573 registerObjectRead(classDesc, descriptorHandle, false); 1574 descriptorHandle = oldHandle; 1575 primitiveData = emptyStream; 1576 classDesc.setClass(resolveClass(classDesc)); 1577 // Consume unread class annotation data and TC_ENDBLOCKDATA 1578 discardData(); 1579 ObjectStreamClass superClass = readClassDesc(); 1580 checkedSetSuperClassDesc(classDesc, superClass); 1581 // Check SUIDs, note all SUID for Enum is 0L 1582 if (0L != classDesc.getSerialVersionUID() || 0L != superClass.getSerialVersionUID()) { 1583 throw new InvalidClassException(superClass.getName(), 1584 "Incompatible class (SUID): " + superClass + " but expected " + superClass); 1585 } 1586 byte tc = nextTC(); 1587 // discard TC_ENDBLOCKDATA after classDesc if any 1588 if (tc == TC_ENDBLOCKDATA) { 1589 // read next parent class. For enum, it may be null 1590 superClass.setSuperclass(readClassDesc()); 1591 } else { 1592 // not TC_ENDBLOCKDATA, push back for next read 1593 pushbackTC(); 1594 } 1595 return classDesc; 1596 } 1597 1598 @SuppressWarnings("unchecked")// For the Enum.valueOf call 1599 private Object readEnum(boolean unshared) throws OptionalDataException, 1600 ClassNotFoundException, IOException { 1601 // read classdesc for Enum first 1602 ObjectStreamClass classDesc = readEnumDesc(); 1603 int newHandle = nextHandle(); 1604 // read name after class desc 1605 String name; 1606 byte tc = nextTC(); 1607 switch (tc) { 1608 case TC_REFERENCE: 1609 if (unshared) { 1610 readNewHandle(); 1611 throw new InvalidObjectException("Unshared read of back reference"); 1612 } 1613 name = (String) readCyclicReference(); 1614 break; 1615 case TC_STRING: 1616 name = (String) readNewString(unshared); 1617 break; 1618 default: 1619 throw corruptStream(tc); 1620 } 1621 1622 Enum<?> result = Enum.valueOf((Class) classDesc.forClass(), name); 1623 registerObjectRead(result, newHandle, unshared); 1624 1625 return result; 1626 } 1627 1628 /** 1629 * Reads a new class descriptor from the receiver. It is assumed the class 1630 * descriptor has not been read yet (not a cyclic reference). Return the 1631 * class descriptor read. 1632 * 1633 * @param unshared 1634 * read the object unshared 1635 * @return The {@code ObjectStreamClass} read from the stream. 1636 * 1637 * @throws IOException 1638 * If an IO exception happened when reading the class 1639 * descriptor. 1640 * @throws ClassNotFoundException 1641 * If a class for one of the objects could not be found 1642 */ 1643 private ObjectStreamClass readNewClassDesc(boolean unshared) 1644 throws ClassNotFoundException, IOException { 1645 // So read...() methods can be used by 1646 // subclasses during readClassDescriptor() 1647 primitiveData = input; 1648 int oldHandle = descriptorHandle; 1649 descriptorHandle = nextHandle(); 1650 ObjectStreamClass newClassDesc = readClassDescriptor(); 1651 registerObjectRead(newClassDesc, descriptorHandle, unshared); 1652 descriptorHandle = oldHandle; 1653 primitiveData = emptyStream; 1654 1655 // We need to map classDesc to class. 1656 try { 1657 newClassDesc.setClass(resolveClass(newClassDesc)); 1658 // Check SUIDs & base name of the class 1659 verifyAndInit(newClassDesc); 1660 } catch (ClassNotFoundException e) { 1661 if (mustResolve) { 1662 throw e; 1663 // Just continue, the class may not be required 1664 } 1665 } 1666 1667 // Resolve the field signatures using the class loader of the 1668 // resolved class 1669 ObjectStreamField[] fields = newClassDesc.getLoadFields(); 1670 fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields; 1671 ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader 1672 : newClassDesc.forClass().getClassLoader(); 1673 for (ObjectStreamField element : fields) { 1674 element.resolve(loader); 1675 } 1676 1677 // Consume unread class annotation data and TC_ENDBLOCKDATA 1678 discardData(); 1679 checkedSetSuperClassDesc(newClassDesc, readClassDesc()); 1680 return newClassDesc; 1681 } 1682 1683 /** 1684 * Reads a new proxy class descriptor from the receiver. It is assumed the 1685 * proxy class descriptor has not been read yet (not a cyclic reference). 1686 * Return the proxy class descriptor read. 1687 * 1688 * @return The {@code Class} read from the stream. 1689 * 1690 * @throws IOException 1691 * If an IO exception happened when reading the class 1692 * descriptor. 1693 * @throws ClassNotFoundException 1694 * If a class for one of the objects could not be found 1695 */ 1696 private Class<?> readNewProxyClassDesc() throws ClassNotFoundException, 1697 IOException { 1698 int count = input.readInt(); 1699 String[] interfaceNames = new String[count]; 1700 for (int i = 0; i < count; i++) { 1701 interfaceNames[i] = input.readUTF(); 1702 } 1703 Class<?> proxy = resolveProxyClass(interfaceNames); 1704 // Consume unread class annotation data and TC_ENDBLOCKDATA 1705 discardData(); 1706 return proxy; 1707 } 1708 1709 /** 1710 * Reads a class descriptor from the source stream. 1711 * 1712 * @return the class descriptor read from the source stream. 1713 * @throws ClassNotFoundException 1714 * if a class for one of the objects cannot be found. 1715 * @throws IOException 1716 * if an error occurs while reading from the source stream. 1717 */ 1718 protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { 1719 ObjectStreamClass newClassDesc = new ObjectStreamClass(); 1720 String name = input.readUTF(); 1721 if (name.length() == 0) { 1722 throw new IOException("The stream is corrupted"); 1723 } 1724 newClassDesc.setName(name); 1725 newClassDesc.setSerialVersionUID(input.readLong()); 1726 newClassDesc.setFlags(input.readByte()); 1727 1728 /* 1729 * We must register the class descriptor before reading field 1730 * descriptors. If called outside of readObject, the descriptorHandle 1731 * might be unset. 1732 */ 1733 if (descriptorHandle == -1) { 1734 descriptorHandle = nextHandle(); 1735 } 1736 registerObjectRead(newClassDesc, descriptorHandle, false); 1737 1738 readFieldDescriptors(newClassDesc); 1739 return newClassDesc; 1740 } 1741 1742 /** 1743 * Creates the proxy class that implements the interfaces specified in 1744 * {@code interfaceNames}. 1745 * 1746 * @param interfaceNames 1747 * the interfaces used to create the proxy class. 1748 * @return the proxy class. 1749 * @throws ClassNotFoundException 1750 * if the proxy class or any of the specified interfaces cannot 1751 * be created. 1752 * @throws IOException 1753 * if an error occurs while reading from the source stream. 1754 * @see ObjectOutputStream#annotateProxyClass(Class) 1755 */ 1756 protected Class<?> resolveProxyClass(String[] interfaceNames) 1757 throws IOException, ClassNotFoundException { 1758 // TODO: This method is opportunity for performance enhancement 1759 // We can cache the classloader and recently used interfaces. 1760 ClassLoader loader = ClassLoader.getSystemClassLoader(); 1761 Class<?>[] interfaces = new Class<?>[interfaceNames.length]; 1762 for (int i = 0; i < interfaceNames.length; i++) { 1763 interfaces[i] = Class.forName(interfaceNames[i], false, loader); 1764 } 1765 try { 1766 return Proxy.getProxyClass(loader, interfaces); 1767 } catch (IllegalArgumentException e) { 1768 throw new ClassNotFoundException(e.toString(), e); 1769 } 1770 } 1771 1772 private int readNewHandle() throws IOException { 1773 return input.readInt(); 1774 } 1775 1776 /** 1777 * Read a new object from the stream. It is assumed the object has not been 1778 * loaded yet (not a cyclic reference). Return the object read. 1779 * 1780 * If the object implements <code>Externalizable</code> its 1781 * <code>readExternal</code> is called. Otherwise, all fields described by 1782 * the class hierarchy are loaded. Each class can define how its declared 1783 * instance fields are loaded by defining a private method 1784 * <code>readObject</code> 1785 * 1786 * @param unshared 1787 * read the object unshared 1788 * @return the object read 1789 * 1790 * @throws IOException 1791 * If an IO exception happened when reading the object. 1792 * @throws OptionalDataException 1793 * If optional data could not be found when reading the object 1794 * graph 1795 * @throws ClassNotFoundException 1796 * If a class for one of the objects could not be found 1797 */ 1798 private Object readNewObject(boolean unshared) 1799 throws OptionalDataException, ClassNotFoundException, IOException { 1800 ObjectStreamClass classDesc = readClassDesc(); 1801 1802 if (classDesc == null) { 1803 throw missingClassDescriptor(); 1804 } 1805 1806 int newHandle = nextHandle(); 1807 Class<?> objectClass = classDesc.forClass(); 1808 Object result = null; 1809 Object registeredResult = null; 1810 if (objectClass != null) { 1811 // Now we know which class to instantiate and which constructor to 1812 // run. We are allowed to run the constructor. 1813 result = classDesc.newInstance(objectClass); 1814 registerObjectRead(result, newHandle, unshared); 1815 registeredResult = result; 1816 } else { 1817 result = null; 1818 } 1819 1820 try { 1821 // This is how we know what to do in defaultReadObject. And it is 1822 // also used by defaultReadObject to check if it was called from an 1823 // invalid place. It also allows readExternal to call 1824 // defaultReadObject and have it work. 1825 currentObject = result; 1826 currentClass = classDesc; 1827 1828 // If Externalizable, just let the object read itself 1829 // Note that this value comes from the Stream, and in fact it could be 1830 // that the classes have been changed so that the info below now 1831 // conflicts with the newer class 1832 boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) != 0; 1833 if (wasExternalizable) { 1834 boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) != 0; 1835 if (!blockData) { 1836 primitiveData = input; 1837 } 1838 if (mustResolve) { 1839 Externalizable extern = (Externalizable) result; 1840 extern.readExternal(this); 1841 } 1842 if (blockData) { 1843 // Similar to readHierarchy. Anything not read by 1844 // readExternal has to be consumed here 1845 discardData(); 1846 } else { 1847 primitiveData = emptyStream; 1848 } 1849 } else { 1850 // If we got here, it is Serializable but not Externalizable. 1851 // Walk the hierarchy reading each class' slots 1852 readHierarchy(result, classDesc); 1853 } 1854 } finally { 1855 // Cleanup, needs to run always so that we can later detect invalid 1856 // calls to defaultReadObject 1857 currentObject = null; 1858 currentClass = null; 1859 } 1860 1861 if (objectClass != null) { 1862 1863 if (classDesc.hasMethodReadResolve()){ 1864 Method methodReadResolve = classDesc.getMethodReadResolve(); 1865 try { 1866 result = methodReadResolve.invoke(result, (Object[]) null); 1867 } catch (IllegalAccessException ignored) { 1868 } catch (InvocationTargetException ite) { 1869 Throwable target = ite.getTargetException(); 1870 if (target instanceof ObjectStreamException) { 1871 throw (ObjectStreamException) target; 1872 } else if (target instanceof Error) { 1873 throw (Error) target; 1874 } else { 1875 throw (RuntimeException) target; 1876 } 1877 } 1878 1879 } 1880 } 1881 // We get here either if class-based replacement was not needed or if it 1882 // was needed but produced the same object or if it could not be 1883 // computed. 1884 1885 // The object to return is the one we instantiated or a replacement for 1886 // it 1887 if (result != null && enableResolve) { 1888 result = resolveObject(result); 1889 } 1890 if (registeredResult != result) { 1891 registerObjectRead(result, newHandle, unshared); 1892 } 1893 return result; 1894 } 1895 1896 private InvalidClassException missingClassDescriptor() throws InvalidClassException { 1897 throw new InvalidClassException("Read null attempting to read class descriptor for object"); 1898 } 1899 1900 /** 1901 * Read a string encoded in {@link DataInput modified UTF-8} from the 1902 * receiver. Return the string read. 1903 * 1904 * @param unshared 1905 * read the object unshared 1906 * @return the string just read. 1907 * @throws IOException 1908 * If an IO exception happened when reading the String. 1909 */ 1910 private Object readNewString(boolean unshared) throws IOException { 1911 Object result = input.readUTF(); 1912 if (enableResolve) { 1913 result = resolveObject(result); 1914 } 1915 registerObjectRead(result, nextHandle(), unshared); 1916 1917 return result; 1918 } 1919 1920 /** 1921 * Read a new String in UTF format from the receiver. Return the string 1922 * read. 1923 * 1924 * @param unshared 1925 * read the object unshared 1926 * @return the string just read. 1927 * 1928 * @throws IOException 1929 * If an IO exception happened when reading the String. 1930 */ 1931 private Object readNewLongString(boolean unshared) throws IOException { 1932 long length = input.readLong(); 1933 Object result = input.decodeUTF((int) length); 1934 if (enableResolve) { 1935 result = resolveObject(result); 1936 } 1937 registerObjectRead(result, nextHandle(), unshared); 1938 1939 return result; 1940 } 1941 1942 /** 1943 * Reads the next object from the source stream. 1944 * 1945 * @return the object read from the source stream. 1946 * @throws ClassNotFoundException 1947 * if the class of one of the objects in the object graph cannot 1948 * be found. 1949 * @throws IOException 1950 * if an error occurs while reading from the source stream. 1951 * @throws OptionalDataException 1952 * if primitive data types were found instead of an object. 1953 * @see ObjectOutputStream#writeObject(Object) 1954 */ 1955 public final Object readObject() throws OptionalDataException, 1956 ClassNotFoundException, IOException { 1957 return readObject(false); 1958 } 1959 1960 /** 1961 * Reads the next unshared object from the source stream. 1962 * 1963 * @return the new object read. 1964 * @throws ClassNotFoundException 1965 * if the class of one of the objects in the object graph cannot 1966 * be found. 1967 * @throws IOException 1968 * if an error occurs while reading from the source stream. 1969 * @see ObjectOutputStream#writeUnshared 1970 */ 1971 public Object readUnshared() throws IOException, ClassNotFoundException { 1972 return readObject(true); 1973 } 1974 1975 private Object readObject(boolean unshared) throws OptionalDataException, 1976 ClassNotFoundException, IOException { 1977 boolean restoreInput = (primitiveData == input); 1978 if (restoreInput) { 1979 primitiveData = emptyStream; 1980 } 1981 1982 // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow 1983 // behavior overriding. 1984 if (subclassOverridingImplementation && !unshared) { 1985 return readObjectOverride(); 1986 } 1987 1988 // If we still had primitive types to read, should we discard them 1989 // (reset the primitiveTypes stream) or leave as is, so that attempts to 1990 // read primitive types won't read 'past data' ??? 1991 Object result; 1992 try { 1993 // We need this so we can tell when we are returning to the 1994 // original/outside caller 1995 if (++nestedLevels == 1) { 1996 // Remember the caller's class loader 1997 callerClassLoader = getClosestUserClassLoader(); 1998 } 1999 2000 result = readNonPrimitiveContent(unshared); 2001 if (restoreInput) { 2002 primitiveData = input; 2003 } 2004 } finally { 2005 // We need this so we can tell when we are returning to the 2006 // original/outside caller 2007 if (--nestedLevels == 0) { 2008 // We are going to return to the original caller, perform 2009 // cleanups. 2010 // No more need to remember the caller's class loader 2011 callerClassLoader = null; 2012 } 2013 } 2014 2015 // Done reading this object. Is it time to return to the original 2016 // caller? If so we need to perform validations first. 2017 if (nestedLevels == 0 && validations != null) { 2018 // We are going to return to the original caller. If validation is 2019 // enabled we need to run them now and then cleanup the validation 2020 // collection 2021 try { 2022 for (InputValidationDesc element : validations) { 2023 element.validator.validateObject(); 2024 } 2025 } finally { 2026 // Validations have to be renewed, since they are only called 2027 // from readObject 2028 validations = null; 2029 } 2030 } 2031 return result; 2032 } 2033 2034 private static final ClassLoader bootstrapLoader = Object.class.getClassLoader(); 2035 private static final ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); 2036 2037 /** 2038 * Searches up the call stack to find the closest user-defined class loader. 2039 * 2040 * @return a user-defined class loader or null if one isn't found 2041 */ 2042 private static ClassLoader getClosestUserClassLoader() { 2043 Class<?>[] stackClasses = VMStack.getClasses(-1); 2044 for (Class<?> stackClass : stackClasses) { 2045 ClassLoader loader = stackClass.getClassLoader(); 2046 if (loader != null && loader != bootstrapLoader 2047 && loader != systemLoader) { 2048 return loader; 2049 } 2050 } 2051 return null; 2052 } 2053 2054 /** 2055 * Method to be overridden by subclasses to read the next object from the 2056 * source stream. 2057 * 2058 * @return the object read from the source stream. 2059 * @throws ClassNotFoundException 2060 * if the class of one of the objects in the object graph cannot 2061 * be found. 2062 * @throws IOException 2063 * if an error occurs while reading from the source stream. 2064 * @throws OptionalDataException 2065 * if primitive data types were found instead of an object. 2066 * @see ObjectOutputStream#writeObjectOverride 2067 */ 2068 protected Object readObjectOverride() throws OptionalDataException, 2069 ClassNotFoundException, IOException { 2070 if (input == null) { 2071 return null; 2072 } 2073 // Subclasses must override. 2074 throw new IOException(); 2075 } 2076 2077 /** 2078 * Reads a short (16 bit) from the source stream. 2079 * 2080 * @return the short value read from the source stream. 2081 * @throws IOException 2082 * if an error occurs while reading from the source stream. 2083 */ 2084 public short readShort() throws IOException { 2085 return primitiveTypes.readShort(); 2086 } 2087 2088 /** 2089 * Reads and validates the ObjectInputStream header from the source stream. 2090 * 2091 * @throws IOException 2092 * if an error occurs while reading from the source stream. 2093 * @throws StreamCorruptedException 2094 * if the source stream does not contain readable serialized 2095 * objects. 2096 */ 2097 protected void readStreamHeader() throws IOException, 2098 StreamCorruptedException { 2099 if (input.readShort() == STREAM_MAGIC 2100 && input.readShort() == STREAM_VERSION) { 2101 return; 2102 } 2103 throw new StreamCorruptedException(); 2104 } 2105 2106 /** 2107 * Reads an unsigned byte (8 bit) from the source stream. 2108 * 2109 * @return the unsigned byte value read from the source stream packaged in 2110 * an integer. 2111 * @throws EOFException 2112 * if the end of the input is reached before the read 2113 * request can be satisfied. 2114 * @throws IOException 2115 * if an error occurs while reading from the source stream. 2116 */ 2117 public int readUnsignedByte() throws IOException { 2118 return primitiveTypes.readUnsignedByte(); 2119 } 2120 2121 /** 2122 * Reads an unsigned short (16 bit) from the source stream. 2123 * 2124 * @return the unsigned short value read from the source stream packaged in 2125 * an integer. 2126 * @throws EOFException 2127 * if the end of the input is reached before the read 2128 * request can be satisfied. 2129 * @throws IOException 2130 * if an error occurs while reading from the source stream. 2131 */ 2132 public int readUnsignedShort() throws IOException { 2133 return primitiveTypes.readUnsignedShort(); 2134 } 2135 2136 /** 2137 * Reads a string encoded in {@link DataInput modified UTF-8} from the 2138 * source stream. 2139 * 2140 * @return the string encoded in {@link DataInput modified UTF-8} read from 2141 * the source stream. 2142 * @throws EOFException 2143 * if the end of the input is reached before the read 2144 * request can be satisfied. 2145 * @throws IOException 2146 * if an error occurs while reading from the source stream. 2147 */ 2148 public String readUTF() throws IOException { 2149 return primitiveTypes.readUTF(); 2150 } 2151 2152 /** 2153 * Returns the previously-read object corresponding to the given serialization handle. 2154 * @throws InvalidObjectException 2155 * If there is no previously-read object with this handle 2156 */ 2157 private Object registeredObjectRead(int handle) throws InvalidObjectException { 2158 Object res = objectsRead.get(handle - ObjectStreamConstants.baseWireHandle); 2159 if (res == UNSHARED_OBJ) { 2160 throw new InvalidObjectException("Cannot read back reference to unshared object"); 2161 } 2162 return res; 2163 } 2164 2165 /** 2166 * Associates a read object with the its serialization handle. 2167 */ 2168 private void registerObjectRead(Object obj, int handle, boolean unshared) throws IOException { 2169 if (unshared) { 2170 obj = UNSHARED_OBJ; 2171 } 2172 int index = handle - ObjectStreamConstants.baseWireHandle; 2173 int size = objectsRead.size(); 2174 // ObjectOutputStream sometimes wastes a handle. I've compared hex dumps of the RI 2175 // and it seems like that's a 'feature'. Look for calls to objectsWritten.put that 2176 // are guarded by !unshared tests. 2177 while (index > size) { 2178 objectsRead.add(null); 2179 ++size; 2180 } 2181 if (index == size) { 2182 objectsRead.add(obj); 2183 } else { 2184 objectsRead.set(index, obj); 2185 } 2186 } 2187 2188 /** 2189 * Registers a callback for post-deserialization validation of objects. It 2190 * allows to perform additional consistency checks before the {@code 2191 * readObject()} method of this class returns its result to the caller. This 2192 * method can only be called from within the {@code readObject()} method of 2193 * a class that implements "special" deserialization rules. It can be called 2194 * multiple times. Validation callbacks are then done in order of decreasing 2195 * priority, defined by {@code priority}. 2196 * 2197 * @param object 2198 * an object that can validate itself by receiving a callback. 2199 * @param priority 2200 * the validator's priority. 2201 * @throws InvalidObjectException 2202 * if {@code object} is {@code null}. 2203 * @throws NotActiveException 2204 * if this stream is currently not reading objects. In that 2205 * case, calling this method is not allowed. 2206 * @see ObjectInputValidation#validateObject() 2207 */ 2208 public synchronized void registerValidation(ObjectInputValidation object, 2209 int priority) throws NotActiveException, InvalidObjectException { 2210 // Validation can only be registered when inside readObject calls 2211 Object instanceBeingRead = this.currentObject; 2212 2213 if (instanceBeingRead == null && nestedLevels == 0) { 2214 throw new NotActiveException(); 2215 } 2216 if (object == null) { 2217 throw new InvalidObjectException("Callback object cannot be null"); 2218 } 2219 // From now on it is just insertion in a SortedCollection. Since 2220 // the Java class libraries don't provide that, we have to 2221 // implement it from scratch here. 2222 InputValidationDesc desc = new InputValidationDesc(); 2223 desc.validator = object; 2224 desc.priority = priority; 2225 // No need for this, validateObject does not take a parameter 2226 // desc.toValidate = instanceBeingRead; 2227 if (validations == null) { 2228 validations = new InputValidationDesc[1]; 2229 validations[0] = desc; 2230 } else { 2231 int i = 0; 2232 for (; i < validations.length; i++) { 2233 InputValidationDesc validation = validations[i]; 2234 // Sorted, higher priority first. 2235 if (priority >= validation.priority) { 2236 break; // Found the index where to insert 2237 } 2238 } 2239 InputValidationDesc[] oldValidations = validations; 2240 int currentSize = oldValidations.length; 2241 validations = new InputValidationDesc[currentSize + 1]; 2242 System.arraycopy(oldValidations, 0, validations, 0, i); 2243 System.arraycopy(oldValidations, i, validations, i + 1, currentSize 2244 - i); 2245 validations[i] = desc; 2246 } 2247 } 2248 2249 /** 2250 * Reset the collection of objects already loaded by the receiver. 2251 */ 2252 private void resetSeenObjects() { 2253 objectsRead = new ArrayList<Object>(); 2254 nextHandle = baseWireHandle; 2255 primitiveData = emptyStream; 2256 } 2257 2258 /** 2259 * Reset the receiver. The collection of objects already read by the 2260 * receiver is reset, and internal structures are also reset so that the 2261 * receiver knows it is in a fresh clean state. 2262 */ 2263 private void resetState() { 2264 resetSeenObjects(); 2265 hasPushbackTC = false; 2266 pushbackTC = 0; 2267 // nestedLevels = 0; 2268 } 2269 2270 /** 2271 * Loads the Java class corresponding to the class descriptor {@code 2272 * osClass} that has just been read from the source stream. 2273 * 2274 * @param osClass 2275 * an ObjectStreamClass read from the source stream. 2276 * @return a Class corresponding to the descriptor {@code osClass}. 2277 * @throws ClassNotFoundException 2278 * if the class for an object cannot be found. 2279 * @throws IOException 2280 * if an I/O error occurs while creating the class. 2281 * @see ObjectOutputStream#annotateClass(Class) 2282 */ 2283 protected Class<?> resolveClass(ObjectStreamClass osClass) 2284 throws IOException, ClassNotFoundException { 2285 // fastpath: obtain cached value 2286 Class<?> cls = osClass.forClass(); 2287 if (cls == null) { 2288 // slowpath: resolve the class 2289 String className = osClass.getName(); 2290 2291 // if it is primitive class, for example, long.class 2292 cls = PRIMITIVE_CLASSES.get(className); 2293 2294 if (cls == null) { 2295 // not primitive class 2296 // Use the first non-null ClassLoader on the stack. If null, use 2297 // the system class loader 2298 cls = Class.forName(className, true, callerClassLoader); 2299 } 2300 } 2301 return cls; 2302 } 2303 2304 /** 2305 * Allows trusted subclasses to substitute the specified original {@code 2306 * object} with a new object. Object substitution has to be activated first 2307 * with calling {@code enableResolveObject(true)}. This implementation just 2308 * returns {@code object}. 2309 * 2310 * @param object 2311 * the original object for which a replacement may be defined. 2312 * @return the replacement object for {@code object}. 2313 * @throws IOException 2314 * if any I/O error occurs while creating the replacement 2315 * object. 2316 * @see #enableResolveObject 2317 * @see ObjectOutputStream#enableReplaceObject 2318 * @see ObjectOutputStream#replaceObject 2319 */ 2320 protected Object resolveObject(Object object) throws IOException { 2321 // By default no object replacement. Subclasses can override 2322 return object; 2323 } 2324 2325 /** 2326 * Skips {@code length} bytes on the source stream. This method should not 2327 * be used to skip bytes at any arbitrary position, just when reading 2328 * primitive data types (int, char etc). 2329 * 2330 * @param length 2331 * the number of bytes to skip. 2332 * @return the number of bytes actually skipped. 2333 * @throws IOException 2334 * if an error occurs while skipping bytes on the source stream. 2335 * @throws NullPointerException 2336 * if the source stream is {@code null}. 2337 */ 2338 public int skipBytes(int length) throws IOException { 2339 // To be used with available. Ok to call if reading primitive buffer 2340 if (input == null) { 2341 throw new NullPointerException(); 2342 } 2343 2344 int offset = 0; 2345 while (offset < length) { 2346 checkReadPrimitiveTypes(); 2347 long skipped = primitiveData.skip(length - offset); 2348 if (skipped == 0) { 2349 return offset; 2350 } 2351 offset += (int) skipped; 2352 } 2353 return length; 2354 } 2355 2356 /** 2357 * Verify if the SUID & the base name for descriptor 2358 * <code>loadedStreamClass</code>matches 2359 * the SUID & the base name of the corresponding loaded class and 2360 * init private fields. 2361 * 2362 * @param loadedStreamClass 2363 * An ObjectStreamClass that was loaded from the stream. 2364 * 2365 * @throws InvalidClassException 2366 * If the SUID of the stream class does not match the VM class 2367 */ 2368 private void verifyAndInit(ObjectStreamClass loadedStreamClass) 2369 throws InvalidClassException { 2370 2371 Class<?> localClass = loadedStreamClass.forClass(); 2372 ObjectStreamClass localStreamClass = ObjectStreamClass 2373 .lookupStreamClass(localClass); 2374 2375 if (loadedStreamClass.getSerialVersionUID() != localStreamClass 2376 .getSerialVersionUID()) { 2377 throw new InvalidClassException(loadedStreamClass.getName(), 2378 "Incompatible class (SUID): " + loadedStreamClass + 2379 " but expected " + localStreamClass); 2380 } 2381 2382 String loadedClassBaseName = getBaseName(loadedStreamClass.getName()); 2383 String localClassBaseName = getBaseName(localStreamClass.getName()); 2384 2385 if (!loadedClassBaseName.equals(localClassBaseName)) { 2386 throw new InvalidClassException(loadedStreamClass.getName(), 2387 String.format("Incompatible class (base name): %s but expected %s", 2388 loadedClassBaseName, localClassBaseName)); 2389 } 2390 2391 loadedStreamClass.initPrivateFields(localStreamClass); 2392 } 2393 2394 private static String getBaseName(String fullName) { 2395 int k = fullName.lastIndexOf('.'); 2396 2397 if (k == -1 || k == (fullName.length() - 1)) { 2398 return fullName; 2399 } 2400 return fullName.substring(k + 1); 2401 } 2402 2403 // Avoid recursive defining. 2404 private static void checkedSetSuperClassDesc(ObjectStreamClass desc, 2405 ObjectStreamClass superDesc) throws StreamCorruptedException { 2406 if (desc.equals(superDesc)) { 2407 throw new StreamCorruptedException(); 2408 } 2409 desc.setSuperclass(superDesc); 2410 } 2411} 2412