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