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