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