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.Modifier; 27import java.lang.reflect.Proxy; 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 // 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 if (field != null && Modifier.isTransient(field.getModifiers())) { 1093 field = null; // No setting transient fields! (http://b/4471249) 1094 } 1095 // We may not have been able to find the field, or it may be transient, but we still 1096 // need to read the value and do the other checking... 1097 try { 1098 Class<?> type = fieldDesc.getTypeInternal(); 1099 if (type == byte.class) { 1100 byte b = input.readByte(); 1101 if (field != null) { 1102 field.setByte(obj, b); 1103 } 1104 } else if (type == char.class) { 1105 char c = input.readChar(); 1106 if (field != null) { 1107 field.setChar(obj, c); 1108 } 1109 } else if (type == double.class) { 1110 double d = input.readDouble(); 1111 if (field != null) { 1112 field.setDouble(obj, d); 1113 } 1114 } else if (type == float.class) { 1115 float f = input.readFloat(); 1116 if (field != null) { 1117 field.setFloat(obj, f); 1118 } 1119 } else if (type == int.class) { 1120 int i = input.readInt(); 1121 if (field != null) { 1122 field.setInt(obj, i); 1123 } 1124 } else if (type == long.class) { 1125 long j = input.readLong(); 1126 if (field != null) { 1127 field.setLong(obj, j); 1128 } 1129 } else if (type == short.class) { 1130 short s = input.readShort(); 1131 if (field != null) { 1132 field.setShort(obj, s); 1133 } 1134 } else if (type == boolean.class) { 1135 boolean z = input.readBoolean(); 1136 if (field != null) { 1137 field.setBoolean(obj, z); 1138 } 1139 } else { 1140 Object toSet = fieldDesc.isUnshared() ? readUnshared() : readObject(); 1141 if (toSet != null) { 1142 // Get the field type from the local field rather than 1143 // from the stream's supplied data. That's the field 1144 // we'll be setting, so that's the one that needs to be 1145 // validated. 1146 String fieldName = fieldDesc.getName(); 1147 ObjectStreamField localFieldDesc = classDesc.getField(fieldName); 1148 Class<?> fieldType = localFieldDesc.getTypeInternal(); 1149 Class<?> valueType = toSet.getClass(); 1150 if (!fieldType.isAssignableFrom(valueType)) { 1151 throw new ClassCastException(classDesc.getName() + "." + fieldName + " - " + fieldType + " not compatible with " + valueType); 1152 } 1153 if (field != null) { 1154 field.set(obj, toSet); 1155 } 1156 } 1157 } 1158 } catch (IllegalAccessException iae) { 1159 // ObjectStreamField should have called setAccessible(true). 1160 throw new AssertionError(iae); 1161 } catch (NoSuchFieldError ignored) { 1162 } 1163 } 1164 } 1165 1166 /** 1167 * Reads a float (32 bit) from the source stream. 1168 * 1169 * @return the float value read from the source stream. 1170 * @throws EOFException 1171 * if the end of the input is reached before the read 1172 * request can be satisfied. 1173 * @throws IOException 1174 * if an error occurs while reading from the source stream. 1175 */ 1176 public float readFloat() throws IOException { 1177 return primitiveTypes.readFloat(); 1178 } 1179 1180 /** 1181 * Reads bytes from the source stream into the byte array {@code dst}. 1182 * This method will block until {@code dst.length} bytes have been read. 1183 * 1184 * @param dst 1185 * the array in which to store the bytes read. 1186 * @throws EOFException 1187 * if the end of the input is reached before the read 1188 * request can be satisfied. 1189 * @throws IOException 1190 * if an error occurs while reading from the source stream. 1191 */ 1192 public void readFully(byte[] dst) throws IOException { 1193 primitiveTypes.readFully(dst); 1194 } 1195 1196 /** 1197 * Reads {@code byteCount} bytes from the source stream into the byte array {@code dst}. 1198 * 1199 * @param dst 1200 * the byte array in which to store the bytes read. 1201 * @param offset 1202 * the initial position in {@code dst} to store the bytes 1203 * read from the source stream. 1204 * @param byteCount 1205 * the number of bytes to read. 1206 * @throws EOFException 1207 * if the end of the input is reached before the read 1208 * request can be satisfied. 1209 * @throws IOException 1210 * if an error occurs while reading from the source stream. 1211 */ 1212 public void readFully(byte[] dst, int offset, int byteCount) throws IOException { 1213 primitiveTypes.readFully(dst, offset, byteCount); 1214 } 1215 1216 /** 1217 * Walks the hierarchy of classes described by class descriptor 1218 * {@code classDesc} and reads the field values corresponding to 1219 * fields declared by the corresponding class descriptor. The instance to 1220 * store field values into is {@code object}. If the class 1221 * (corresponding to class descriptor {@code classDesc}) defines 1222 * private instance method {@code readObject} it will be used to load 1223 * field values. 1224 * 1225 * @param object 1226 * Instance into which stored field values loaded. 1227 * @param classDesc 1228 * A class descriptor (an {@code ObjectStreamClass}) 1229 * defining which fields should be loaded. 1230 * 1231 * @throws IOException 1232 * If an IO exception happened when reading the field values in 1233 * the hierarchy. 1234 * @throws ClassNotFoundException 1235 * If a class for one of the field types could not be found 1236 * @throws NotActiveException 1237 * If {@code defaultReadObject} is called from the wrong 1238 * context. 1239 * 1240 * @see #defaultReadObject 1241 * @see #readObject() 1242 */ 1243 private void readHierarchy(Object object, ObjectStreamClass classDesc) 1244 throws IOException, ClassNotFoundException, NotActiveException { 1245 if (object == null && mustResolve) { 1246 throw new NotActiveException(); 1247 } 1248 1249 List<ObjectStreamClass> streamClassList = classDesc.getHierarchy(); 1250 if (object == null) { 1251 for (ObjectStreamClass objectStreamClass : streamClassList) { 1252 readObjectForClass(null, objectStreamClass); 1253 } 1254 } else { 1255 List<Class<?>> superclasses = cachedSuperclasses.get(object.getClass()); 1256 if (superclasses == null) { 1257 superclasses = cacheSuperclassesFor(object.getClass()); 1258 } 1259 1260 int lastIndex = 0; 1261 for (int i = 0, end = superclasses.size(); i < end; ++i) { 1262 Class<?> superclass = superclasses.get(i); 1263 int index = findStreamSuperclass(superclass, streamClassList, lastIndex); 1264 if (index == -1) { 1265 readObjectNoData(object, superclass, 1266 ObjectStreamClass.lookupStreamClass(superclass)); 1267 } else { 1268 for (int j = lastIndex; j <= index; j++) { 1269 readObjectForClass(object, streamClassList.get(j)); 1270 } 1271 lastIndex = index + 1; 1272 } 1273 } 1274 } 1275 } 1276 1277 private HashMap<Class<?>, List<Class<?>>> cachedSuperclasses = new HashMap<Class<?>, List<Class<?>>>(); 1278 1279 private List<Class<?>> cacheSuperclassesFor(Class<?> c) { 1280 ArrayList<Class<?>> result = new ArrayList<Class<?>>(); 1281 Class<?> nextClass = c; 1282 while (nextClass != null) { 1283 Class<?> testClass = nextClass.getSuperclass(); 1284 if (testClass != null) { 1285 result.add(0, nextClass); 1286 } 1287 nextClass = testClass; 1288 } 1289 cachedSuperclasses.put(c, result); 1290 return result; 1291 } 1292 1293 private int findStreamSuperclass(Class<?> cl, List<ObjectStreamClass> classList, int lastIndex) { 1294 for (int i = lastIndex, end = classList.size(); i < end; i++) { 1295 ObjectStreamClass objCl = classList.get(i); 1296 String forName = objCl.forClass().getName(); 1297 1298 if (objCl.getName().equals(forName)) { 1299 if (cl.getName().equals(objCl.getName())) { 1300 return i; 1301 } 1302 } else { 1303 // there was a class replacement 1304 if (cl.getName().equals(forName)) { 1305 return i; 1306 } 1307 } 1308 } 1309 return -1; 1310 } 1311 1312 private void readObjectNoData(Object object, Class<?> cl, ObjectStreamClass classDesc) 1313 throws ObjectStreamException { 1314 if (!classDesc.isSerializable()) { 1315 return; 1316 } 1317 if (classDesc.hasMethodReadObjectNoData()){ 1318 final Method readMethod = classDesc.getMethodReadObjectNoData(); 1319 try { 1320 readMethod.invoke(object); 1321 } catch (InvocationTargetException e) { 1322 Throwable ex = e.getTargetException(); 1323 if (ex instanceof RuntimeException) { 1324 throw (RuntimeException) ex; 1325 } else if (ex instanceof Error) { 1326 throw (Error) ex; 1327 } 1328 throw (ObjectStreamException) ex; 1329 } catch (IllegalAccessException e) { 1330 throw new RuntimeException(e.toString()); 1331 } 1332 } 1333 1334 } 1335 1336 private void readObjectForClass(Object object, ObjectStreamClass classDesc) 1337 throws IOException, ClassNotFoundException, NotActiveException { 1338 // Have to do this before calling defaultReadObject or anything that 1339 // calls defaultReadObject 1340 currentObject = object; 1341 currentClass = classDesc; 1342 1343 boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) != 0; 1344 Class<?> targetClass = classDesc.forClass(); 1345 1346 final Method readMethod; 1347 if (targetClass == null || !mustResolve) { 1348 readMethod = null; 1349 } else { 1350 readMethod = classDesc.getMethodReadObject(); 1351 } 1352 try { 1353 if (readMethod != null) { 1354 // We have to be able to fetch its value, even if it is private 1355 readMethod.setAccessible(true); 1356 try { 1357 readMethod.invoke(object, this); 1358 } catch (InvocationTargetException e) { 1359 Throwable ex = e.getTargetException(); 1360 if (ex instanceof ClassNotFoundException) { 1361 throw (ClassNotFoundException) ex; 1362 } else if (ex instanceof RuntimeException) { 1363 throw (RuntimeException) ex; 1364 } else if (ex instanceof Error) { 1365 throw (Error) ex; 1366 } 1367 throw (IOException) ex; 1368 } catch (IllegalAccessException e) { 1369 throw new RuntimeException(e.toString()); 1370 } 1371 } else { 1372 defaultReadObject(); 1373 } 1374 if (hadWriteMethod) { 1375 discardData(); 1376 } 1377 } finally { 1378 // Cleanup, needs to run always so that we can later detect invalid 1379 // calls to defaultReadObject 1380 currentObject = null; // We did not set this, so we do not need to 1381 // clean it 1382 currentClass = null; 1383 } 1384 } 1385 1386 /** 1387 * Reads an integer (32 bit) from the source stream. 1388 * 1389 * @return the integer value read from the source stream. 1390 * @throws EOFException 1391 * if the end of the input is reached before the read 1392 * request can be satisfied. 1393 * @throws IOException 1394 * if an error occurs while reading from the source stream. 1395 */ 1396 public int readInt() throws IOException { 1397 return primitiveTypes.readInt(); 1398 } 1399 1400 /** 1401 * Reads the next line from the source stream. Lines are terminated by 1402 * {@code '\r'}, {@code '\n'}, {@code "\r\n"} or an {@code EOF}. 1403 * 1404 * @return the string read from the source stream. 1405 * @throws IOException 1406 * if an error occurs while reading from the source stream. 1407 * @deprecated Use {@link BufferedReader} 1408 */ 1409 @Deprecated 1410 public String readLine() throws IOException { 1411 return primitiveTypes.readLine(); 1412 } 1413 1414 /** 1415 * Reads a long (64 bit) from the source stream. 1416 * 1417 * @return the long value read from the source stream. 1418 * @throws EOFException 1419 * if the end of the input is reached before the read 1420 * request can be satisfied. 1421 * @throws IOException 1422 * if an error occurs while reading from the source stream. 1423 */ 1424 public long readLong() throws IOException { 1425 return primitiveTypes.readLong(); 1426 } 1427 1428 /** 1429 * Read a new array from the receiver. It is assumed the array has not been 1430 * read yet (not a cyclic reference). Return the array read. 1431 * 1432 * @param unshared 1433 * read the object unshared 1434 * @return the array read 1435 * 1436 * @throws IOException 1437 * If an IO exception happened when reading the array. 1438 * @throws ClassNotFoundException 1439 * If a class for one of the objects could not be found 1440 * @throws OptionalDataException 1441 * If optional data could not be found when reading the array. 1442 */ 1443 private Object readNewArray(boolean unshared) throws OptionalDataException, 1444 ClassNotFoundException, IOException { 1445 ObjectStreamClass classDesc = readClassDesc(); 1446 1447 if (classDesc == null) { 1448 throw missingClassDescriptor(); 1449 } 1450 1451 int newHandle = nextHandle(); 1452 1453 // Array size 1454 int size = input.readInt(); 1455 Class<?> arrayClass = classDesc.forClass(); 1456 Class<?> componentType = arrayClass.getComponentType(); 1457 Object result = Array.newInstance(componentType, size); 1458 1459 registerObjectRead(result, newHandle, unshared); 1460 1461 // Now we have code duplication just because Java is typed. We have to 1462 // read N elements and assign to array positions, but we must typecast 1463 // the array first, and also call different methods depending on the 1464 // elements. 1465 if (componentType.isPrimitive()) { 1466 if (componentType == int.class) { 1467 int[] intArray = (int[]) result; 1468 for (int i = 0; i < size; i++) { 1469 intArray[i] = input.readInt(); 1470 } 1471 } else if (componentType == byte.class) { 1472 byte[] byteArray = (byte[]) result; 1473 input.readFully(byteArray, 0, size); 1474 } else if (componentType == char.class) { 1475 char[] charArray = (char[]) result; 1476 for (int i = 0; i < size; i++) { 1477 charArray[i] = input.readChar(); 1478 } 1479 } else if (componentType == short.class) { 1480 short[] shortArray = (short[]) result; 1481 for (int i = 0; i < size; i++) { 1482 shortArray[i] = input.readShort(); 1483 } 1484 } else if (componentType == boolean.class) { 1485 boolean[] booleanArray = (boolean[]) result; 1486 for (int i = 0; i < size; i++) { 1487 booleanArray[i] = input.readBoolean(); 1488 } 1489 } else if (componentType == long.class) { 1490 long[] longArray = (long[]) result; 1491 for (int i = 0; i < size; i++) { 1492 longArray[i] = input.readLong(); 1493 } 1494 } else if (componentType == float.class) { 1495 float[] floatArray = (float[]) result; 1496 for (int i = 0; i < size; i++) { 1497 floatArray[i] = input.readFloat(); 1498 } 1499 } else if (componentType == double.class) { 1500 double[] doubleArray = (double[]) result; 1501 for (int i = 0; i < size; i++) { 1502 doubleArray[i] = input.readDouble(); 1503 } 1504 } else { 1505 throw new ClassNotFoundException("Wrong base type in " + classDesc.getName()); 1506 } 1507 } else { 1508 // Array of Objects 1509 Object[] objectArray = (Object[]) result; 1510 for (int i = 0; i < size; i++) { 1511 // TODO: This place is the opportunity for enhancement 1512 // We can implement writing elements through fast-path, 1513 // without setting up the context (see readObject()) for 1514 // each element with public API 1515 objectArray[i] = readObject(); 1516 } 1517 } 1518 if (enableResolve) { 1519 result = resolveObject(result); 1520 registerObjectRead(result, newHandle, false); 1521 } 1522 return result; 1523 } 1524 1525 /** 1526 * Reads a new class from the receiver. It is assumed the class has not been 1527 * read yet (not a cyclic reference). Return the class read. 1528 * 1529 * @param unshared 1530 * read the object unshared 1531 * @return The {@code java.lang.Class} read from the stream. 1532 * 1533 * @throws IOException 1534 * If an IO exception happened when reading the class. 1535 * @throws ClassNotFoundException 1536 * If a class for one of the objects could not be found 1537 */ 1538 private Class<?> readNewClass(boolean unshared) throws ClassNotFoundException, IOException { 1539 ObjectStreamClass classDesc = readClassDesc(); 1540 if (classDesc == null) { 1541 throw missingClassDescriptor(); 1542 } 1543 Class<?> localClass = classDesc.forClass(); 1544 if (localClass != null) { 1545 registerObjectRead(localClass, nextHandle(), unshared); 1546 } 1547 return localClass; 1548 } 1549 1550 /* 1551 * read class type for Enum, note there's difference between enum and normal 1552 * classes 1553 */ 1554 private ObjectStreamClass readEnumDesc() throws IOException, 1555 ClassNotFoundException { 1556 byte tc = nextTC(); 1557 switch (tc) { 1558 case TC_CLASSDESC: 1559 return readEnumDescInternal(); 1560 case TC_REFERENCE: 1561 return (ObjectStreamClass) readCyclicReference(); 1562 case TC_NULL: 1563 return null; 1564 default: 1565 throw corruptStream(tc); 1566 } 1567 } 1568 1569 private ObjectStreamClass readEnumDescInternal() throws IOException, ClassNotFoundException { 1570 ObjectStreamClass classDesc; 1571 primitiveData = input; 1572 int oldHandle = descriptorHandle; 1573 descriptorHandle = nextHandle(); 1574 classDesc = readClassDescriptor(); 1575 registerObjectRead(classDesc, descriptorHandle, false); 1576 descriptorHandle = oldHandle; 1577 primitiveData = emptyStream; 1578 classDesc.setClass(resolveClass(classDesc)); 1579 // Consume unread class annotation data and TC_ENDBLOCKDATA 1580 discardData(); 1581 ObjectStreamClass superClass = readClassDesc(); 1582 checkedSetSuperClassDesc(classDesc, superClass); 1583 // Check SUIDs, note all SUID for Enum is 0L 1584 if (0L != classDesc.getSerialVersionUID() || 0L != superClass.getSerialVersionUID()) { 1585 throw new InvalidClassException(superClass.getName(), 1586 "Incompatible class (SUID): " + superClass + " but expected " + superClass); 1587 } 1588 byte tc = nextTC(); 1589 // discard TC_ENDBLOCKDATA after classDesc if any 1590 if (tc == TC_ENDBLOCKDATA) { 1591 // read next parent class. For enum, it may be null 1592 superClass.setSuperclass(readClassDesc()); 1593 } else { 1594 // not TC_ENDBLOCKDATA, push back for next read 1595 pushbackTC(); 1596 } 1597 return classDesc; 1598 } 1599 1600 @SuppressWarnings("unchecked")// For the Enum.valueOf call 1601 private Object readEnum(boolean unshared) throws OptionalDataException, 1602 ClassNotFoundException, IOException { 1603 // read classdesc for Enum first 1604 ObjectStreamClass classDesc = readEnumDesc(); 1605 int newHandle = nextHandle(); 1606 // read name after class desc 1607 String name; 1608 byte tc = nextTC(); 1609 switch (tc) { 1610 case TC_REFERENCE: 1611 if (unshared) { 1612 readNewHandle(); 1613 throw new InvalidObjectException("Unshared read of back reference"); 1614 } 1615 name = (String) readCyclicReference(); 1616 break; 1617 case TC_STRING: 1618 name = (String) readNewString(unshared); 1619 break; 1620 default: 1621 throw corruptStream(tc); 1622 } 1623 1624 Enum<?> result; 1625 try { 1626 result = Enum.valueOf((Class) classDesc.forClass(), name); 1627 } catch (IllegalArgumentException e) { 1628 throw new InvalidObjectException(e.getMessage()); 1629 } 1630 registerObjectRead(result, newHandle, unshared); 1631 return result; 1632 } 1633 1634 /** 1635 * Reads a new class descriptor from the receiver. It is assumed the class 1636 * descriptor has not been read yet (not a cyclic reference). Return the 1637 * class descriptor read. 1638 * 1639 * @param unshared 1640 * read the object unshared 1641 * @return The {@code ObjectStreamClass} read from the stream. 1642 * 1643 * @throws IOException 1644 * If an IO exception happened when reading the class 1645 * descriptor. 1646 * @throws ClassNotFoundException 1647 * If a class for one of the objects could not be found 1648 */ 1649 private ObjectStreamClass readNewClassDesc(boolean unshared) 1650 throws ClassNotFoundException, IOException { 1651 // So read...() methods can be used by 1652 // subclasses during readClassDescriptor() 1653 primitiveData = input; 1654 int oldHandle = descriptorHandle; 1655 descriptorHandle = nextHandle(); 1656 ObjectStreamClass newClassDesc = readClassDescriptor(); 1657 registerObjectRead(newClassDesc, descriptorHandle, unshared); 1658 descriptorHandle = oldHandle; 1659 primitiveData = emptyStream; 1660 1661 // We need to map classDesc to class. 1662 try { 1663 newClassDesc.setClass(resolveClass(newClassDesc)); 1664 // Check SUIDs & base name of the class 1665 verifyAndInit(newClassDesc); 1666 } catch (ClassNotFoundException e) { 1667 if (mustResolve) { 1668 throw e; 1669 // Just continue, the class may not be required 1670 } 1671 } 1672 1673 // Resolve the field signatures using the class loader of the 1674 // resolved class 1675 ObjectStreamField[] fields = newClassDesc.getLoadFields(); 1676 fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields; 1677 ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader 1678 : newClassDesc.forClass().getClassLoader(); 1679 for (ObjectStreamField element : fields) { 1680 element.resolve(loader); 1681 } 1682 1683 // Consume unread class annotation data and TC_ENDBLOCKDATA 1684 discardData(); 1685 checkedSetSuperClassDesc(newClassDesc, readClassDesc()); 1686 return newClassDesc; 1687 } 1688 1689 /** 1690 * Reads a new proxy class descriptor from the receiver. It is assumed the 1691 * proxy class descriptor has not been read yet (not a cyclic reference). 1692 * Return the proxy class descriptor read. 1693 * 1694 * @return The {@code Class} read from the stream. 1695 * 1696 * @throws IOException 1697 * If an IO exception happened when reading the class 1698 * descriptor. 1699 * @throws ClassNotFoundException 1700 * If a class for one of the objects could not be found 1701 */ 1702 private Class<?> readNewProxyClassDesc() throws ClassNotFoundException, 1703 IOException { 1704 int count = input.readInt(); 1705 String[] interfaceNames = new String[count]; 1706 for (int i = 0; i < count; i++) { 1707 interfaceNames[i] = input.readUTF(); 1708 } 1709 Class<?> proxy = resolveProxyClass(interfaceNames); 1710 // Consume unread class annotation data and TC_ENDBLOCKDATA 1711 discardData(); 1712 return proxy; 1713 } 1714 1715 /** 1716 * Reads a class descriptor from the source stream. 1717 * 1718 * @return the class descriptor read from the source stream. 1719 * @throws ClassNotFoundException 1720 * if a class for one of the objects cannot be found. 1721 * @throws IOException 1722 * if an error occurs while reading from the source stream. 1723 */ 1724 protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { 1725 ObjectStreamClass newClassDesc = new ObjectStreamClass(); 1726 String name = input.readUTF(); 1727 if (name.length() == 0) { 1728 throw new IOException("The stream is corrupted"); 1729 } 1730 newClassDesc.setName(name); 1731 newClassDesc.setSerialVersionUID(input.readLong()); 1732 newClassDesc.setFlags(input.readByte()); 1733 1734 /* 1735 * We must register the class descriptor before reading field 1736 * descriptors. If called outside of readObject, the descriptorHandle 1737 * might be unset. 1738 */ 1739 if (descriptorHandle == -1) { 1740 descriptorHandle = nextHandle(); 1741 } 1742 registerObjectRead(newClassDesc, descriptorHandle, false); 1743 1744 readFieldDescriptors(newClassDesc); 1745 return newClassDesc; 1746 } 1747 1748 /** 1749 * Creates the proxy class that implements the interfaces specified in 1750 * {@code interfaceNames}. 1751 * 1752 * @param interfaceNames 1753 * the interfaces used to create the proxy class. 1754 * @return the proxy class. 1755 * @throws ClassNotFoundException 1756 * if the proxy class or any of the specified interfaces cannot 1757 * be created. 1758 * @throws IOException 1759 * if an error occurs while reading from the source stream. 1760 * @see ObjectOutputStream#annotateProxyClass(Class) 1761 */ 1762 protected Class<?> resolveProxyClass(String[] interfaceNames) 1763 throws IOException, ClassNotFoundException { 1764 // TODO: This method is opportunity for performance enhancement 1765 // We can cache the classloader and recently used interfaces. 1766 ClassLoader loader = ClassLoader.getSystemClassLoader(); 1767 Class<?>[] interfaces = new Class<?>[interfaceNames.length]; 1768 for (int i = 0; i < interfaceNames.length; i++) { 1769 interfaces[i] = Class.forName(interfaceNames[i], false, loader); 1770 } 1771 try { 1772 return Proxy.getProxyClass(loader, interfaces); 1773 } catch (IllegalArgumentException e) { 1774 throw new ClassNotFoundException(e.toString(), e); 1775 } 1776 } 1777 1778 private int readNewHandle() throws IOException { 1779 return input.readInt(); 1780 } 1781 1782 /** 1783 * Read a new object from the stream. It is assumed the object has not been 1784 * loaded yet (not a cyclic reference). Return the object read. 1785 * 1786 * If the object implements <code>Externalizable</code> its 1787 * <code>readExternal</code> is called. Otherwise, all fields described by 1788 * the class hierarchy are loaded. Each class can define how its declared 1789 * instance fields are loaded by defining a private method 1790 * <code>readObject</code> 1791 * 1792 * @param unshared 1793 * read the object unshared 1794 * @return the object read 1795 * 1796 * @throws IOException 1797 * If an IO exception happened when reading the object. 1798 * @throws OptionalDataException 1799 * If optional data could not be found when reading the object 1800 * graph 1801 * @throws ClassNotFoundException 1802 * If a class for one of the objects could not be found 1803 */ 1804 private Object readNewObject(boolean unshared) 1805 throws OptionalDataException, ClassNotFoundException, IOException { 1806 ObjectStreamClass classDesc = readClassDesc(); 1807 1808 if (classDesc == null) { 1809 throw missingClassDescriptor(); 1810 } 1811 1812 int newHandle = nextHandle(); 1813 Class<?> objectClass = classDesc.forClass(); 1814 Object result = null; 1815 Object registeredResult = null; 1816 if (objectClass != null) { 1817 // Now we know which class to instantiate and which constructor to 1818 // run. We are allowed to run the constructor. 1819 result = classDesc.newInstance(objectClass); 1820 registerObjectRead(result, newHandle, unshared); 1821 registeredResult = result; 1822 } else { 1823 result = null; 1824 } 1825 1826 try { 1827 // This is how we know what to do in defaultReadObject. And it is 1828 // also used by defaultReadObject to check if it was called from an 1829 // invalid place. It also allows readExternal to call 1830 // defaultReadObject and have it work. 1831 currentObject = result; 1832 currentClass = classDesc; 1833 1834 // If Externalizable, just let the object read itself 1835 // Note that this value comes from the Stream, and in fact it could be 1836 // that the classes have been changed so that the info below now 1837 // conflicts with the newer class 1838 boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) != 0; 1839 if (wasExternalizable) { 1840 boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) != 0; 1841 if (!blockData) { 1842 primitiveData = input; 1843 } 1844 if (mustResolve) { 1845 Externalizable extern = (Externalizable) result; 1846 extern.readExternal(this); 1847 } 1848 if (blockData) { 1849 // Similar to readHierarchy. Anything not read by 1850 // readExternal has to be consumed here 1851 discardData(); 1852 } else { 1853 primitiveData = emptyStream; 1854 } 1855 } else { 1856 // If we got here, it is Serializable but not Externalizable. 1857 // Walk the hierarchy reading each class' slots 1858 readHierarchy(result, classDesc); 1859 } 1860 } finally { 1861 // Cleanup, needs to run always so that we can later detect invalid 1862 // calls to defaultReadObject 1863 currentObject = null; 1864 currentClass = null; 1865 } 1866 1867 if (objectClass != null) { 1868 1869 if (classDesc.hasMethodReadResolve()){ 1870 Method methodReadResolve = classDesc.getMethodReadResolve(); 1871 try { 1872 result = methodReadResolve.invoke(result, (Object[]) null); 1873 } catch (IllegalAccessException ignored) { 1874 } catch (InvocationTargetException ite) { 1875 Throwable target = ite.getTargetException(); 1876 if (target instanceof ObjectStreamException) { 1877 throw (ObjectStreamException) target; 1878 } else if (target instanceof Error) { 1879 throw (Error) target; 1880 } else { 1881 throw (RuntimeException) target; 1882 } 1883 } 1884 1885 } 1886 } 1887 // We get here either if class-based replacement was not needed or if it 1888 // was needed but produced the same object or if it could not be 1889 // computed. 1890 1891 // The object to return is the one we instantiated or a replacement for 1892 // it 1893 if (result != null && enableResolve) { 1894 result = resolveObject(result); 1895 } 1896 if (registeredResult != result) { 1897 registerObjectRead(result, newHandle, unshared); 1898 } 1899 return result; 1900 } 1901 1902 private InvalidClassException missingClassDescriptor() throws InvalidClassException { 1903 throw new InvalidClassException("Read null attempting to read class descriptor for object"); 1904 } 1905 1906 /** 1907 * Read a string encoded in {@link DataInput modified UTF-8} from the 1908 * receiver. Return the string read. 1909 * 1910 * @param unshared 1911 * read the object unshared 1912 * @return the string just read. 1913 * @throws IOException 1914 * If an IO exception happened when reading the String. 1915 */ 1916 private Object readNewString(boolean unshared) throws IOException { 1917 Object result = input.readUTF(); 1918 if (enableResolve) { 1919 result = resolveObject(result); 1920 } 1921 registerObjectRead(result, nextHandle(), unshared); 1922 1923 return result; 1924 } 1925 1926 /** 1927 * Read a new String in UTF format from the receiver. Return the string 1928 * read. 1929 * 1930 * @param unshared 1931 * read the object unshared 1932 * @return the string just read. 1933 * 1934 * @throws IOException 1935 * If an IO exception happened when reading the String. 1936 */ 1937 private Object readNewLongString(boolean unshared) throws IOException { 1938 long length = input.readLong(); 1939 Object result = input.decodeUTF((int) length); 1940 if (enableResolve) { 1941 result = resolveObject(result); 1942 } 1943 registerObjectRead(result, nextHandle(), unshared); 1944 1945 return result; 1946 } 1947 1948 /** 1949 * Reads the next object from the source stream. 1950 * 1951 * @return the object read from the source stream. 1952 * @throws ClassNotFoundException 1953 * if the class of one of the objects in the object graph cannot 1954 * be found. 1955 * @throws IOException 1956 * if an error occurs while reading from the source stream. 1957 * @throws OptionalDataException 1958 * if primitive data types were found instead of an object. 1959 * @see ObjectOutputStream#writeObject(Object) 1960 */ 1961 public final Object readObject() throws OptionalDataException, 1962 ClassNotFoundException, IOException { 1963 return readObject(false); 1964 } 1965 1966 /** 1967 * Reads the next unshared object from the source stream. 1968 * 1969 * @return the new object read. 1970 * @throws ClassNotFoundException 1971 * if the class of one of the objects in the object graph cannot 1972 * be found. 1973 * @throws IOException 1974 * if an error occurs while reading from the source stream. 1975 * @see ObjectOutputStream#writeUnshared 1976 */ 1977 public Object readUnshared() throws IOException, ClassNotFoundException { 1978 return readObject(true); 1979 } 1980 1981 private Object readObject(boolean unshared) throws OptionalDataException, 1982 ClassNotFoundException, IOException { 1983 boolean restoreInput = (primitiveData == input); 1984 if (restoreInput) { 1985 primitiveData = emptyStream; 1986 } 1987 1988 // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow 1989 // behavior overriding. 1990 if (subclassOverridingImplementation && !unshared) { 1991 return readObjectOverride(); 1992 } 1993 1994 // If we still had primitive types to read, should we discard them 1995 // (reset the primitiveTypes stream) or leave as is, so that attempts to 1996 // read primitive types won't read 'past data' ??? 1997 Object result; 1998 try { 1999 // We need this so we can tell when we are returning to the 2000 // original/outside caller 2001 if (++nestedLevels == 1) { 2002 // Remember the caller's class loader 2003 callerClassLoader = getClosestUserClassLoader(); 2004 } 2005 2006 result = readNonPrimitiveContent(unshared); 2007 if (restoreInput) { 2008 primitiveData = input; 2009 } 2010 } finally { 2011 // We need this so we can tell when we are returning to the 2012 // original/outside caller 2013 if (--nestedLevels == 0) { 2014 // We are going to return to the original caller, perform 2015 // cleanups. 2016 // No more need to remember the caller's class loader 2017 callerClassLoader = null; 2018 } 2019 } 2020 2021 // Done reading this object. Is it time to return to the original 2022 // caller? If so we need to perform validations first. 2023 if (nestedLevels == 0 && validations != null) { 2024 // We are going to return to the original caller. If validation is 2025 // enabled we need to run them now and then cleanup the validation 2026 // collection 2027 try { 2028 for (InputValidationDesc element : validations) { 2029 element.validator.validateObject(); 2030 } 2031 } finally { 2032 // Validations have to be renewed, since they are only called 2033 // from readObject 2034 validations = null; 2035 } 2036 } 2037 return result; 2038 } 2039 2040 private static final ClassLoader bootstrapLoader = Object.class.getClassLoader(); 2041 private static final ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); 2042 2043 /** 2044 * Searches up the call stack to find the closest user-defined class loader. 2045 * 2046 * @return a user-defined class loader or null if one isn't found 2047 */ 2048 private static ClassLoader getClosestUserClassLoader() { 2049 Class<?>[] stackClasses = VMStack.getClasses(-1); 2050 for (Class<?> stackClass : stackClasses) { 2051 ClassLoader loader = stackClass.getClassLoader(); 2052 if (loader != null && loader != bootstrapLoader 2053 && loader != systemLoader) { 2054 return loader; 2055 } 2056 } 2057 return null; 2058 } 2059 2060 /** 2061 * Method to be overridden by subclasses to read the next object from the 2062 * source stream. 2063 * 2064 * @return the object read from the source stream. 2065 * @throws ClassNotFoundException 2066 * if the class of one of the objects in the object graph cannot 2067 * be found. 2068 * @throws IOException 2069 * if an error occurs while reading from the source stream. 2070 * @throws OptionalDataException 2071 * if primitive data types were found instead of an object. 2072 * @see ObjectOutputStream#writeObjectOverride 2073 */ 2074 protected Object readObjectOverride() throws OptionalDataException, 2075 ClassNotFoundException, IOException { 2076 if (input == null) { 2077 return null; 2078 } 2079 // Subclasses must override. 2080 throw new IOException(); 2081 } 2082 2083 /** 2084 * Reads a short (16 bit) from the source stream. 2085 * 2086 * @return the short value read from the source stream. 2087 * @throws IOException 2088 * if an error occurs while reading from the source stream. 2089 */ 2090 public short readShort() throws IOException { 2091 return primitiveTypes.readShort(); 2092 } 2093 2094 /** 2095 * Reads and validates the ObjectInputStream header from the source stream. 2096 * 2097 * @throws IOException 2098 * if an error occurs while reading from the source stream. 2099 * @throws StreamCorruptedException 2100 * if the source stream does not contain readable serialized 2101 * objects. 2102 */ 2103 protected void readStreamHeader() throws IOException, 2104 StreamCorruptedException { 2105 if (input.readShort() == STREAM_MAGIC 2106 && input.readShort() == STREAM_VERSION) { 2107 return; 2108 } 2109 throw new StreamCorruptedException(); 2110 } 2111 2112 /** 2113 * Reads an unsigned byte (8 bit) from the source stream. 2114 * 2115 * @return the unsigned byte value read from the source stream packaged in 2116 * an integer. 2117 * @throws EOFException 2118 * if the end of the input is reached before the read 2119 * request can be satisfied. 2120 * @throws IOException 2121 * if an error occurs while reading from the source stream. 2122 */ 2123 public int readUnsignedByte() throws IOException { 2124 return primitiveTypes.readUnsignedByte(); 2125 } 2126 2127 /** 2128 * Reads an unsigned short (16 bit) from the source stream. 2129 * 2130 * @return the unsigned short value read from the source stream packaged in 2131 * an integer. 2132 * @throws EOFException 2133 * if the end of the input is reached before the read 2134 * request can be satisfied. 2135 * @throws IOException 2136 * if an error occurs while reading from the source stream. 2137 */ 2138 public int readUnsignedShort() throws IOException { 2139 return primitiveTypes.readUnsignedShort(); 2140 } 2141 2142 /** 2143 * Reads a string encoded in {@link DataInput modified UTF-8} from the 2144 * source stream. 2145 * 2146 * @return the string encoded in {@link DataInput modified UTF-8} read from 2147 * the source stream. 2148 * @throws EOFException 2149 * if the end of the input is reached before the read 2150 * request can be satisfied. 2151 * @throws IOException 2152 * if an error occurs while reading from the source stream. 2153 */ 2154 public String readUTF() throws IOException { 2155 return primitiveTypes.readUTF(); 2156 } 2157 2158 /** 2159 * Returns the previously-read object corresponding to the given serialization handle. 2160 * @throws InvalidObjectException 2161 * If there is no previously-read object with this handle 2162 */ 2163 private Object registeredObjectRead(int handle) throws InvalidObjectException { 2164 Object res = objectsRead.get(handle - ObjectStreamConstants.baseWireHandle); 2165 if (res == UNSHARED_OBJ) { 2166 throw new InvalidObjectException("Cannot read back reference to unshared object"); 2167 } 2168 return res; 2169 } 2170 2171 /** 2172 * Associates a read object with the its serialization handle. 2173 */ 2174 private void registerObjectRead(Object obj, int handle, boolean unshared) throws IOException { 2175 if (unshared) { 2176 obj = UNSHARED_OBJ; 2177 } 2178 int index = handle - ObjectStreamConstants.baseWireHandle; 2179 int size = objectsRead.size(); 2180 // ObjectOutputStream sometimes wastes a handle. I've compared hex dumps of the RI 2181 // and it seems like that's a 'feature'. Look for calls to objectsWritten.put that 2182 // are guarded by !unshared tests. 2183 while (index > size) { 2184 objectsRead.add(null); 2185 ++size; 2186 } 2187 if (index == size) { 2188 objectsRead.add(obj); 2189 } else { 2190 objectsRead.set(index, obj); 2191 } 2192 } 2193 2194 /** 2195 * Registers a callback for post-deserialization validation of objects. It 2196 * allows to perform additional consistency checks before the {@code 2197 * readObject()} method of this class returns its result to the caller. This 2198 * method can only be called from within the {@code readObject()} method of 2199 * a class that implements "special" deserialization rules. It can be called 2200 * multiple times. Validation callbacks are then done in order of decreasing 2201 * priority, defined by {@code priority}. 2202 * 2203 * @param object 2204 * an object that can validate itself by receiving a callback. 2205 * @param priority 2206 * the validator's priority. 2207 * @throws InvalidObjectException 2208 * if {@code object} is {@code null}. 2209 * @throws NotActiveException 2210 * if this stream is currently not reading objects. In that 2211 * case, calling this method is not allowed. 2212 * @see ObjectInputValidation#validateObject() 2213 */ 2214 public synchronized void registerValidation(ObjectInputValidation object, 2215 int priority) throws NotActiveException, InvalidObjectException { 2216 // Validation can only be registered when inside readObject calls 2217 Object instanceBeingRead = this.currentObject; 2218 2219 if (instanceBeingRead == null && nestedLevels == 0) { 2220 throw new NotActiveException(); 2221 } 2222 if (object == null) { 2223 throw new InvalidObjectException("Callback object cannot be null"); 2224 } 2225 // From now on it is just insertion in a SortedCollection. Since 2226 // the Java class libraries don't provide that, we have to 2227 // implement it from scratch here. 2228 InputValidationDesc desc = new InputValidationDesc(); 2229 desc.validator = object; 2230 desc.priority = priority; 2231 // No need for this, validateObject does not take a parameter 2232 // desc.toValidate = instanceBeingRead; 2233 if (validations == null) { 2234 validations = new InputValidationDesc[1]; 2235 validations[0] = desc; 2236 } else { 2237 int i = 0; 2238 for (; i < validations.length; i++) { 2239 InputValidationDesc validation = validations[i]; 2240 // Sorted, higher priority first. 2241 if (priority >= validation.priority) { 2242 break; // Found the index where to insert 2243 } 2244 } 2245 InputValidationDesc[] oldValidations = validations; 2246 int currentSize = oldValidations.length; 2247 validations = new InputValidationDesc[currentSize + 1]; 2248 System.arraycopy(oldValidations, 0, validations, 0, i); 2249 System.arraycopy(oldValidations, i, validations, i + 1, currentSize 2250 - i); 2251 validations[i] = desc; 2252 } 2253 } 2254 2255 /** 2256 * Reset the collection of objects already loaded by the receiver. 2257 */ 2258 private void resetSeenObjects() { 2259 objectsRead = new ArrayList<Object>(); 2260 nextHandle = baseWireHandle; 2261 primitiveData = emptyStream; 2262 } 2263 2264 /** 2265 * Reset the receiver. The collection of objects already read by the 2266 * receiver is reset, and internal structures are also reset so that the 2267 * receiver knows it is in a fresh clean state. 2268 */ 2269 private void resetState() { 2270 resetSeenObjects(); 2271 hasPushbackTC = false; 2272 pushbackTC = 0; 2273 // nestedLevels = 0; 2274 } 2275 2276 /** 2277 * Loads the Java class corresponding to the class descriptor {@code 2278 * osClass} that has just been read from the source stream. 2279 * 2280 * @param osClass 2281 * an ObjectStreamClass read from the source stream. 2282 * @return a Class corresponding to the descriptor {@code osClass}. 2283 * @throws ClassNotFoundException 2284 * if the class for an object cannot be found. 2285 * @throws IOException 2286 * if an I/O error occurs while creating the class. 2287 * @see ObjectOutputStream#annotateClass(Class) 2288 */ 2289 protected Class<?> resolveClass(ObjectStreamClass osClass) 2290 throws IOException, ClassNotFoundException { 2291 // fastpath: obtain cached value 2292 Class<?> cls = osClass.forClass(); 2293 if (cls == null) { 2294 // slowpath: resolve the class 2295 String className = osClass.getName(); 2296 2297 // if it is primitive class, for example, long.class 2298 cls = PRIMITIVE_CLASSES.get(className); 2299 2300 if (cls == null) { 2301 // not primitive class 2302 // Use the first non-null ClassLoader on the stack. If null, use 2303 // the system class loader 2304 cls = Class.forName(className, true, callerClassLoader); 2305 } 2306 } 2307 return cls; 2308 } 2309 2310 /** 2311 * Allows trusted subclasses to substitute the specified original {@code 2312 * object} with a new object. Object substitution has to be activated first 2313 * with calling {@code enableResolveObject(true)}. This implementation just 2314 * returns {@code object}. 2315 * 2316 * @param object 2317 * the original object for which a replacement may be defined. 2318 * @return the replacement object for {@code object}. 2319 * @throws IOException 2320 * if any I/O error occurs while creating the replacement 2321 * object. 2322 * @see #enableResolveObject 2323 * @see ObjectOutputStream#enableReplaceObject 2324 * @see ObjectOutputStream#replaceObject 2325 */ 2326 protected Object resolveObject(Object object) throws IOException { 2327 // By default no object replacement. Subclasses can override 2328 return object; 2329 } 2330 2331 /** 2332 * Skips {@code length} bytes on the source stream. This method should not 2333 * be used to skip bytes at any arbitrary position, just when reading 2334 * primitive data types (int, char etc). 2335 * 2336 * @param length 2337 * the number of bytes to skip. 2338 * @return the number of bytes actually skipped. 2339 * @throws IOException 2340 * if an error occurs while skipping bytes on the source stream. 2341 * @throws NullPointerException 2342 * if the source stream is {@code null}. 2343 */ 2344 public int skipBytes(int length) throws IOException { 2345 // To be used with available. Ok to call if reading primitive buffer 2346 if (input == null) { 2347 throw new NullPointerException("source stream is null"); 2348 } 2349 2350 int offset = 0; 2351 while (offset < length) { 2352 checkReadPrimitiveTypes(); 2353 long skipped = primitiveData.skip(length - offset); 2354 if (skipped == 0) { 2355 return offset; 2356 } 2357 offset += (int) skipped; 2358 } 2359 return length; 2360 } 2361 2362 /** 2363 * Verify if the SUID & the base name for descriptor 2364 * <code>loadedStreamClass</code>matches 2365 * the SUID & the base name of the corresponding loaded class and 2366 * init private fields. 2367 * 2368 * @param loadedStreamClass 2369 * An ObjectStreamClass that was loaded from the stream. 2370 * 2371 * @throws InvalidClassException 2372 * If the SUID of the stream class does not match the VM class 2373 */ 2374 private void verifyAndInit(ObjectStreamClass loadedStreamClass) 2375 throws InvalidClassException { 2376 2377 Class<?> localClass = loadedStreamClass.forClass(); 2378 ObjectStreamClass localStreamClass = ObjectStreamClass 2379 .lookupStreamClass(localClass); 2380 2381 if (loadedStreamClass.getSerialVersionUID() != localStreamClass 2382 .getSerialVersionUID()) { 2383 throw new InvalidClassException(loadedStreamClass.getName(), 2384 "Incompatible class (SUID): " + loadedStreamClass + 2385 " but expected " + localStreamClass); 2386 } 2387 2388 String loadedClassBaseName = getBaseName(loadedStreamClass.getName()); 2389 String localClassBaseName = getBaseName(localStreamClass.getName()); 2390 2391 if (!loadedClassBaseName.equals(localClassBaseName)) { 2392 throw new InvalidClassException(loadedStreamClass.getName(), 2393 String.format("Incompatible class (base name): %s but expected %s", 2394 loadedClassBaseName, localClassBaseName)); 2395 } 2396 2397 loadedStreamClass.initPrivateFields(localStreamClass); 2398 } 2399 2400 private static String getBaseName(String fullName) { 2401 int k = fullName.lastIndexOf('.'); 2402 2403 if (k == -1 || k == (fullName.length() - 1)) { 2404 return fullName; 2405 } 2406 return fullName.substring(k + 1); 2407 } 2408 2409 // Avoid recursive defining. 2410 private static void checkedSetSuperClassDesc(ObjectStreamClass desc, 2411 ObjectStreamClass superDesc) throws StreamCorruptedException { 2412 if (desc.equals(superDesc)) { 2413 throw new StreamCorruptedException(); 2414 } 2415 desc.setSuperclass(superDesc); 2416 } 2417} 2418