ObjectStreamClass.java revision 807:408c9c621938
1/* 2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25/* 26 * Licensed Materials - Property of IBM 27 * RMI-IIOP v1.0 28 * Copyright IBM Corp. 1998 2012 All Rights Reserved 29 * 30 */ 31 32package com.sun.corba.se.impl.io; 33 34import java.io.ObjectInputStream; 35import java.io.ObjectOutputStream; 36import java.lang.invoke.MethodHandle; 37import java.security.MessageDigest; 38import java.security.NoSuchAlgorithmException; 39import java.security.DigestOutputStream; 40import java.security.AccessController; 41import java.security.PrivilegedAction; 42 43import java.lang.reflect.Modifier; 44import java.lang.reflect.Field; 45import java.lang.reflect.Member; 46import java.lang.reflect.Method; 47import java.lang.reflect.Constructor; 48import java.lang.reflect.Proxy; 49import java.lang.reflect.InvocationTargetException; 50 51import java.io.IOException; 52import java.io.DataOutputStream; 53import java.io.ByteArrayOutputStream; 54import java.io.InvalidClassException; 55import java.io.Externalizable; 56import java.io.Serializable; 57 58import java.util.Arrays; 59import java.util.Comparator; 60 61import com.sun.corba.se.impl.util.RepositoryId; 62 63import org.omg.CORBA.ValueMember; 64 65import sun.corba.Bridge; 66 67/** 68 * An ObjectStreamClass describes a class that can be serialized to a stream 69 * or a class that was serialized to a stream. It contains the name 70 * and the serialVersionUID of the class. 71 * <br> 72 * The ObjectStreamClass for a specific class loaded in this Java VM can 73 * be found using the lookup method. 74 * 75 * @author Roger Riggs 76 * @since JDK1.1 77 */ 78public class ObjectStreamClass implements java.io.Serializable { 79 private static final boolean DEBUG_SVUID = false ; 80 81 public static final long kDefaultUID = -1; 82 83 /** true if represents enum type */ 84 private boolean isEnum; 85 86 private static final Bridge bridge = 87 AccessController.doPrivileged( 88 new PrivilegedAction<Bridge>() { 89 public Bridge run() { 90 return Bridge.get() ; 91 } 92 } 93 ) ; 94 95 /** Find the descriptor for a class that can be serialized. Null 96 * is returned if the specified class does not implement 97 * java.io.Serializable or java.io.Externalizable. 98 */ 99 static final ObjectStreamClass lookup(Class<?> cl) 100 { 101 ObjectStreamClass desc = lookupInternal(cl); 102 if (desc.isSerializable() || desc.isExternalizable()) 103 return desc; 104 return null; 105 } 106 107 /* 108 * Find the class descriptor for the specified class. 109 * Package access only so it can be called from ObjectIn/OutStream. 110 */ 111 static ObjectStreamClass lookupInternal(Class<?> cl) 112 { 113 /* Synchronize on the hashtable so no two threads will do 114 * this at the same time. 115 */ 116 ObjectStreamClass desc = null; 117 synchronized (descriptorFor) { 118 /* Find the matching descriptor if it already known */ 119 desc = findDescriptorFor(cl); 120 if (desc == null) { 121 /* Check if it's serializable */ 122 boolean serializable = Serializable.class.isAssignableFrom(cl); 123 124 /* If the class is only Serializable, 125 * lookup the descriptor for the superclass. 126 */ 127 ObjectStreamClass superdesc = null; 128 if (serializable) { 129 Class<?> superclass = cl.getSuperclass(); 130 if (superclass != null) 131 superdesc = lookup(superclass); 132 } 133 134 /* Check if its' externalizable. 135 * If it's Externalizable, clear the serializable flag. 136 * Only one or the other may be set in the protocol. 137 */ 138 boolean externalizable = false; 139 if (serializable) { 140 externalizable = 141 ((superdesc != null) && superdesc.isExternalizable()) || 142 Externalizable.class.isAssignableFrom(cl); 143 if (externalizable) { 144 serializable = false; 145 } 146 } 147 148 /* Create a new version descriptor, 149 * it put itself in the known table. 150 */ 151 desc = new ObjectStreamClass(cl, superdesc, 152 serializable, externalizable); 153 } 154 // Must always call init. See bug 4488137. This code was 155 // incorrectly changed to return immediately on a non-null 156 // cache result. That allowed threads to gain access to 157 // unintialized instances. 158 // 159 // History: Note, the following init() call was originally within 160 // the synchronization block, as it currently is now. Later, the 161 // init() call was moved outside the synchronization block, and 162 // the init() method used a private member variable lock, to 163 // avoid performance problems. See bug 4165204. But that lead to 164 // a deadlock situation, see bug 5104239. Hence, the init() method 165 // has now been moved back into the synchronization block. The 166 // right approach to solving these problems would be to rewrite 167 // this class, based on the latest java.io.ObjectStreamClass. 168 desc.init(); 169 } 170 return desc; 171 } 172 173 /** 174 * The name of the class described by this descriptor. 175 */ 176 public final String getName() { 177 return name; 178 } 179 180 /** 181 * Return the serialVersionUID for this class. 182 * The serialVersionUID defines a set of classes all with the same name 183 * that have evolved from a common root class and agree to be serialized 184 * and deserialized using a common format. 185 */ 186 public static final long getSerialVersionUID( java.lang.Class<?> clazz) { 187 ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz ); 188 if( theosc != null ) 189 { 190 return theosc.getSerialVersionUID( ); 191 } 192 return 0; 193 } 194 195 /** 196 * Return the serialVersionUID for this class. 197 * The serialVersionUID defines a set of classes all with the same name 198 * that have evolved from a common root class and agree to be serialized 199 * and deserialized using a common format. 200 */ 201 public final long getSerialVersionUID() { 202 return suid; 203 } 204 205 /** 206 * Return the serialVersionUID string for this class. 207 * The serialVersionUID defines a set of classes all with the same name 208 * that have evolved from a common root class and agree to be serialized 209 * and deserialized using a common format. 210 */ 211 public final String getSerialVersionUIDStr() { 212 if (suidStr == null) 213 suidStr = Long.toHexString(suid).toUpperCase(); 214 return suidStr; 215 } 216 217 /** 218 * Return the actual (computed) serialVersionUID for this class. 219 */ 220 public static final long getActualSerialVersionUID( java.lang.Class<?> clazz ) 221 { 222 ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz ); 223 if( theosc != null ) 224 { 225 return theosc.getActualSerialVersionUID( ); 226 } 227 return 0; 228 } 229 230 /** 231 * Return the actual (computed) serialVersionUID for this class. 232 */ 233 public final long getActualSerialVersionUID() { 234 return actualSuid; 235 } 236 237 /** 238 * Return the actual (computed) serialVersionUID for this class. 239 */ 240 public final String getActualSerialVersionUIDStr() { 241 if (actualSuidStr == null) 242 actualSuidStr = Long.toHexString(actualSuid).toUpperCase(); 243 return actualSuidStr; 244 } 245 246 /** 247 * Return the class in the local VM that this version is mapped to. 248 * Null is returned if there is no corresponding local class. 249 */ 250 public final Class<?> forClass() { 251 return ofClass; 252 } 253 254 /** 255 * Return an array of the fields of this serializable class. 256 * @return an array containing an element for each persistent 257 * field of this class. Returns an array of length zero if 258 * there are no fields. 259 * @since JDK1.2 260 */ 261 public ObjectStreamField[] getFields() { 262 // Return a copy so the caller can't change the fields. 263 if (fields.length > 0) { 264 ObjectStreamField[] dup = new ObjectStreamField[fields.length]; 265 System.arraycopy(fields, 0, dup, 0, fields.length); 266 return dup; 267 } else { 268 return fields; 269 } 270 } 271 272 public boolean hasField(ValueMember field) 273 { 274 try { 275 for (int i = 0; i < fields.length; i++) { 276 if (fields[i].getName().equals(field.name)) { 277 if (fields[i].getSignature().equals( 278 ValueUtility.getSignature(field))) 279 return true; 280 } 281 } 282 } catch (Exception exc) { 283 // Ignore this; all we want to do is return false 284 // Note that ValueUtility.getSignature can throw checked exceptions. 285 } 286 287 return false; 288 } 289 290 /* Avoid unnecessary allocations. */ 291 final ObjectStreamField[] getFieldsNoCopy() { 292 return fields; 293 } 294 295 /** 296 * Get the field of this class by name. 297 * @return The ObjectStreamField object of the named field or null if there 298 * is no such named field. 299 */ 300 public final ObjectStreamField getField(String name) { 301 /* Binary search of fields by name. 302 */ 303 for (int i = fields.length-1; i >= 0; i--) { 304 if (name.equals(fields[i].getName())) { 305 return fields[i]; 306 } 307 } 308 return null; 309 } 310 311 public final boolean invokeWriteObject(Object obj, ObjectOutputStream ois) throws InvocationTargetException { 312 if (!hasWriteObject()) { 313 return false; 314 } 315 try { 316 writeObjectMethod.invoke(obj, ois); 317 } catch (Throwable t) { 318 throw new InvocationTargetException(t, "writeObject"); 319 } 320 return true; 321 } 322 323 public final boolean invokeReadObject(Object obj, ObjectInputStream ois) throws InvocationTargetException { 324 if (hasReadObject()) { 325 try { 326 readObjectMethod.invoke(obj, ois); 327 return true; 328 } catch (Throwable t) { 329 throw new InvocationTargetException(t, "readObject"); 330 } 331 } else { 332 return false; 333 } 334 } 335 336 public Serializable writeReplace(Serializable value) { 337 if (writeReplaceObjectMethod != null) { 338 try { 339 return (Serializable) writeReplaceObjectMethod.invoke(value); 340 } catch (Throwable t) { 341 throw new InternalError("unexpected error", t); 342 } 343 } 344 else return value; 345 } 346 347 public Object readResolve(Object value) { 348 if (readResolveObjectMethod != null) { 349 try { 350 return readResolveObjectMethod.invoke(value); 351 } catch (Throwable t) { 352 throw new InternalError("unexpected error", t); 353 } 354 } 355 else return value; 356 } 357 358 /** 359 * Return a string describing this ObjectStreamClass. 360 */ 361 public final String toString() { 362 StringBuffer sb = new StringBuffer(); 363 364 sb.append(name); 365 sb.append(": static final long serialVersionUID = "); 366 sb.append(Long.toString(suid)); 367 sb.append("L;"); 368 return sb.toString(); 369 } 370 371 /* 372 * Create a new ObjectStreamClass from a loaded class. 373 * Don't call this directly, call lookup instead. 374 */ 375 private ObjectStreamClass(java.lang.Class<?> cl, ObjectStreamClass superdesc, 376 boolean serial, boolean extern) 377 { 378 ofClass = cl; /* created from this class */ 379 380 if (Proxy.isProxyClass(cl)) { 381 forProxyClass = true; 382 } 383 384 name = cl.getName(); 385 isEnum = Enum.class.isAssignableFrom(cl); 386 superclass = superdesc; 387 serializable = serial; 388 if (!forProxyClass) { 389 // proxy classes are never externalizable 390 externalizable = extern; 391 } 392 393 /* 394 * Enter this class in the table of known descriptors. 395 * Otherwise, when the fields are read it may recurse 396 * trying to find the descriptor for itself. 397 */ 398 insertDescriptorFor(this); 399 400 /* 401 * The remainder of initialization occurs in init(), which is called 402 * after the lock on the global class descriptor table has been 403 * released. 404 */ 405 } 406 407 static final class PersistentFieldsValue 408 extends ClassValue<ObjectStreamField[]> { 409 PersistentFieldsValue() { } 410 411 protected ObjectStreamField[] computeValue(Class<?> type) { 412 try { 413 bridge.ensureClassInitialized(type); 414 Field pf = type.getDeclaredField("serialPersistentFields"); 415 int mods = pf.getModifiers(); 416 if (Modifier.isPrivate(mods) && Modifier.isStatic(mods) && 417 Modifier.isFinal(mods)) { 418 long offset = bridge.staticFieldOffset(pf); 419 java.io.ObjectStreamField[] fields = 420 (java.io.ObjectStreamField[])bridge.getObject(type, offset); 421 return translateFields(fields); 422 } 423 } catch (NoSuchFieldException | 424 IllegalArgumentException | ClassCastException e) { 425 } 426 return null; 427 } 428 429 private static ObjectStreamField[] translateFields(java.io.ObjectStreamField[] fields) { 430 if (fields == null) { 431 return null; 432 } 433 ObjectStreamField[] translation = 434 new ObjectStreamField[fields.length]; 435 for (int i = 0; i < fields.length; i++) { 436 translation[i] = new ObjectStreamField(fields[i].getName(), 437 fields[i].getType()); 438 } 439 return translation; 440 } 441 } 442 443 private static final PersistentFieldsValue persistentFieldsValue = 444 new PersistentFieldsValue(); 445 446 /* 447 * Initialize class descriptor. This method is only invoked on class 448 * descriptors created via calls to lookupInternal(). This method is kept 449 * separate from the ObjectStreamClass constructor so that lookupInternal 450 * does not have to hold onto a global class descriptor table lock while the 451 * class descriptor is being initialized (see bug 4165204). 452 */ 453 454 455 private void init() { 456 synchronized (lock) { 457 458 // See description at definition of initialized. 459 if (initialized) 460 return; 461 462 final Class<?> cl = ofClass; 463 464 if (!serializable || 465 externalizable || 466 forProxyClass || 467 name.equals("java.lang.String")){ 468 fields = NO_FIELDS; 469 } else if (serializable) { 470 /* Ask for permission to override field access checks. 471 */ 472 AccessController.doPrivileged(new PrivilegedAction() { 473 public Object run() { 474 /* Fill in the list of persistent fields. 475 * If it is declared, use the declared serialPersistentFields. 476 * Otherwise, extract the fields from the class itself. 477 */ 478 fields = persistentFieldsValue.get(cl); 479 480 if (fields == null) { 481 /* Get all of the declared fields for this Class. 482 * Create a temporary ObjectStreamField array to hold each 483 * non-static, non-transient field. Then copy the 484 * temporary array into an array of the correct 485 * size once the number of fields is known. 486 */ 487 Field[] actualfields = cl.getDeclaredFields(); 488 489 int numFields = 0; 490 ObjectStreamField[] tempFields = 491 new ObjectStreamField[actualfields.length]; 492 for (int i = 0; i < actualfields.length; i++) { 493 Field fld = actualfields[i] ; 494 int modifiers = fld.getModifiers(); 495 if (!Modifier.isStatic(modifiers) && 496 !Modifier.isTransient(modifiers)) { 497 tempFields[numFields++] = new ObjectStreamField(fld); 498 } 499 } 500 501 fields = new ObjectStreamField[numFields]; 502 System.arraycopy(tempFields, 0, fields, 0, numFields); 503 504 } else { 505 // For each declared persistent field, look for an actual 506 // reflected Field. If there is one, make sure it's the correct 507 // type and cache it in the ObjectStreamClass for that field. 508 for (int j = fields.length-1; j >= 0; j--) { 509 try { 510 Field reflField = cl.getDeclaredField(fields[j].getName()); 511 if (fields[j].getType() == reflField.getType()) { 512 fields[j].setField(reflField); 513 } 514 } catch (NoSuchFieldException e) { 515 // Nothing to do 516 } 517 } 518 } 519 return null; 520 } 521 }); 522 523 if (fields.length > 1) 524 Arrays.sort(fields); 525 526 /* Set up field data for use while writing using the API api. */ 527 computeFieldInfo(); 528 } 529 530 /* Get the serialVersionUID from the class. 531 * It uses the access override mechanism so make sure 532 * the field objects is only used here. 533 * 534 * NonSerializable classes have a serialVerisonUID of 0L. 535 */ 536 if (isNonSerializable() || isEnum) { 537 suid = 0L; 538 } else { 539 // Lookup special Serializable members using reflection. 540 AccessController.doPrivileged(new PrivilegedAction() { 541 public Object run() { 542 if (forProxyClass) { 543 // proxy classes always have serialVersionUID of 0L 544 suid = 0L; 545 } else { 546 try { 547 final Field f = cl.getDeclaredField("serialVersionUID"); 548 int mods = f.getModifiers(); 549 // SerialBug 5: static final SUID should be read 550 if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) { 551 long offset = bridge.staticFieldOffset(f); 552 suid = bridge.getLong(cl, offset); 553 // SerialBug 2: should be computed after writeObject 554 // actualSuid = computeStructuralUID(cl); 555 } else { 556 suid = _computeSerialVersionUID(cl); 557 // SerialBug 2: should be computed after writeObject 558 // actualSuid = computeStructuralUID(cl); 559 } 560 } catch (NoSuchFieldException ex) { 561 suid = _computeSerialVersionUID(cl); 562 // SerialBug 2: should be computed after writeObject 563 // actualSuid = computeStructuralUID(cl); 564 } 565 } 566 567 writeReplaceObjectMethod = bridge.writeReplaceForSerialization(cl); 568 569 readResolveObjectMethod = bridge.readResolveForSerialization(cl); 570 571 if (externalizable) 572 cons = getExternalizableConstructor(cl) ; 573 else 574 cons = getSerializableConstructor(cl) ; 575 576 if (serializable && !forProxyClass) { 577 writeObjectMethod = bridge.writeObjectForSerialization(cl) ; 578 readObjectMethod = bridge.readObjectForSerialization(cl); 579 } 580 return null; 581 } 582 }); 583 } 584 585 // This call depends on a lot of information computed above! 586 actualSuid = ObjectStreamClass.computeStructuralUID(this, cl); 587 588 // If we have a write object method, precompute the 589 // RMI-IIOP stream format version 2 optional data 590 // repository ID. 591 if (hasWriteObject()) 592 rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId(); 593 594 // This must be done last. 595 initialized = true; 596 } 597 } 598 599 // Specific to RMI-IIOP 600 /** 601 * Java to IDL ptc-02-01-12 1.5.1 602 * 603 * "The rep_id string passed to the start_value method must be 604 * 'RMI:org.omg.custom.class:hashcode:suid' where class is the 605 * fully-qualified name of the class whose writeObject method 606 * is being invoked and hashcode and suid are the class's hashcode 607 * and SUID." 608 */ 609 private String computeRMIIIOPOptionalDataRepId() { 610 611 StringBuffer sbuf = new StringBuffer("RMI:org.omg.custom."); 612 sbuf.append(RepositoryId.convertToISOLatin1(this.getName())); 613 sbuf.append(':'); 614 sbuf.append(this.getActualSerialVersionUIDStr()); 615 sbuf.append(':'); 616 sbuf.append(this.getSerialVersionUIDStr()); 617 618 return sbuf.toString(); 619 } 620 621 /** 622 * This will return null if there is no writeObject method. 623 */ 624 public final String getRMIIIOPOptionalDataRepId() { 625 return rmiiiopOptionalDataRepId; 626 } 627 628 /* 629 * Create an empty ObjectStreamClass for a class about to be read. 630 * This is separate from read so ObjectInputStream can assign the 631 * wire handle early, before any nested ObjectStreamClass might 632 * be read. 633 */ 634 ObjectStreamClass(String n, long s) { 635 name = n; 636 suid = s; 637 superclass = null; 638 } 639 640 641 /* 642 * Set the class this version descriptor matches. 643 * The base class name and serializable hash must match. 644 * Fill in the reflected Fields that will be used 645 * for reading. 646 */ 647 final void setClass(Class<?> cl) throws InvalidClassException { 648 649 if (cl == null) { 650 localClassDesc = null; 651 ofClass = null; 652 computeFieldInfo(); 653 return; 654 } 655 656 localClassDesc = lookupInternal(cl); 657 if (localClassDesc == null) 658 // XXX I18N, logging needed 659 throw new InvalidClassException(cl.getName(), 660 "Local class not compatible"); 661 if (suid != localClassDesc.suid) { 662 663 /* Check for exceptional cases that allow mismatched suid. */ 664 665 /* Allow adding Serializable or Externalizable 666 * to a later release of the class. 667 */ 668 boolean addedSerialOrExtern = 669 isNonSerializable() || localClassDesc.isNonSerializable(); 670 671 /* Disregard the serialVersionUID of an array 672 * when name and cl.Name differ. If resolveClass() returns 673 * an array with a different package name, 674 * the serialVersionUIDs will not match since the fully 675 * qualified array class is used in the 676 * computation of the array's serialVersionUID. There is 677 * no way to set a permanent serialVersionUID for an array type. 678 */ 679 680 boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name)); 681 682 if (! arraySUID && ! addedSerialOrExtern ) { 683 // XXX I18N, logging needed 684 throw new InvalidClassException(cl.getName(), 685 "Local class not compatible:" + 686 " stream classdesc serialVersionUID=" + suid + 687 " local class serialVersionUID=" + localClassDesc.suid); 688 } 689 } 690 691 /* compare the class names, stripping off package names. */ 692 if (! compareClassNames(name, cl.getName(), '.')) 693 // XXX I18N, logging needed 694 throw new InvalidClassException(cl.getName(), 695 "Incompatible local class name. " + 696 "Expected class name compatible with " + 697 name); 698 699 /* 700 * Test that both implement either serializable or externalizable. 701 */ 702 703 // The next check is more generic, since it covers the 704 // Proxy case, the JDK 1.3 serialization code has 705 // both checks 706 //if ((serializable && localClassDesc.externalizable) || 707 // (externalizable && localClassDesc.serializable)) 708 // throw new InvalidClassException(localCl.getName(), 709 // "Serializable is incompatible with Externalizable"); 710 711 if ((serializable != localClassDesc.serializable) || 712 (externalizable != localClassDesc.externalizable) || 713 (!serializable && !externalizable)) 714 715 // XXX I18N, logging needed 716 throw new InvalidClassException(cl.getName(), 717 "Serialization incompatible with Externalization"); 718 719 /* Set up the reflected Fields in the class where the value of each 720 * field in this descriptor should be stored. 721 * Each field in this ObjectStreamClass (the source) is located (by 722 * name) in the ObjectStreamClass of the class(the destination). 723 * In the usual (non-versioned case) the field is in both 724 * descriptors and the types match, so the reflected Field is copied. 725 * If the type does not match, a InvalidClass exception is thrown. 726 * If the field is not present in the class, the reflected Field 727 * remains null so the field will be read but discarded. 728 * If extra fields are present in the class they are ignored. Their 729 * values will be set to the default value by the object allocator. 730 * Both the src and dest field list are sorted by type and name. 731 */ 732 733 ObjectStreamField[] destfield = 734 (ObjectStreamField[])localClassDesc.fields; 735 ObjectStreamField[] srcfield = 736 (ObjectStreamField[])fields; 737 738 int j = 0; 739 nextsrc: 740 for (int i = 0; i < srcfield.length; i++ ) { 741 /* Find this field in the dest*/ 742 for (int k = j; k < destfield.length; k++) { 743 if (srcfield[i].getName().equals(destfield[k].getName())) { 744 /* found match */ 745 if (srcfield[i].isPrimitive() && 746 !srcfield[i].typeEquals(destfield[k])) { 747 // XXX I18N, logging needed 748 throw new InvalidClassException(cl.getName(), 749 "The type of field " + 750 srcfield[i].getName() + 751 " of class " + name + 752 " is incompatible."); 753 } 754 755 /* Skip over any fields in the dest that are not in the src */ 756 j = k; 757 758 srcfield[i].setField(destfield[j].getField()); 759 // go on to the next source field 760 continue nextsrc; 761 } 762 } 763 } 764 765 /* Set up field data for use while reading from the input stream. */ 766 computeFieldInfo(); 767 768 /* Remember the class this represents */ 769 ofClass = cl; 770 771 /* get the cache of these methods from the local class 772 * implementation. 773 */ 774 readObjectMethod = localClassDesc.readObjectMethod; 775 readResolveObjectMethod = localClassDesc.readResolveObjectMethod; 776 } 777 778 /* Compare the base class names of streamName and localName. 779 * 780 * @return Return true iff the base class name compare. 781 * @param streamName Fully qualified class name. 782 * @param localName Fully qualified class name. 783 * @param pkgSeparator class names use either '.' or '/'. 784 * 785 * Only compare base class name to allow package renaming. 786 */ 787 static boolean compareClassNames(String streamName, 788 String localName, 789 char pkgSeparator) { 790 /* compare the class names, stripping off package names. */ 791 int streamNameIndex = streamName.lastIndexOf(pkgSeparator); 792 if (streamNameIndex < 0) 793 streamNameIndex = 0; 794 795 int localNameIndex = localName.lastIndexOf(pkgSeparator); 796 if (localNameIndex < 0) 797 localNameIndex = 0; 798 799 return streamName.regionMatches(false, streamNameIndex, 800 localName, localNameIndex, 801 streamName.length() - streamNameIndex); 802 } 803 804 /* 805 * Compare the types of two class descriptors. 806 * They match if they have the same class name and suid 807 */ 808 final boolean typeEquals(ObjectStreamClass other) { 809 return (suid == other.suid) && 810 compareClassNames(name, other.name, '.'); 811 } 812 813 /* 814 * Return the superclass descriptor of this descriptor. 815 */ 816 final void setSuperclass(ObjectStreamClass s) { 817 superclass = s; 818 } 819 820 /* 821 * Return the superclass descriptor of this descriptor. 822 */ 823 final ObjectStreamClass getSuperclass() { 824 return superclass; 825 } 826 827 /** 828 * Return whether the class has a readObject method 829 */ 830 final boolean hasReadObject() { 831 return readObjectMethod != null; 832 } 833 834 /* 835 * Return whether the class has a writeObject method 836 */ 837 final boolean hasWriteObject() { 838 return writeObjectMethod != null ; 839 } 840 841 /** 842 * Returns true if represented class is serializable or externalizable and 843 * defines a conformant writeReplace method. Otherwise, returns false. 844 */ 845 boolean hasWriteReplaceMethod() { 846 return (writeReplaceObjectMethod != null); 847 } 848 849 /** 850 * Returns true if represented class is serializable or externalizable and 851 * defines a conformant readResolve method. Otherwise, returns false. 852 */ 853 boolean hasReadResolveMethod() { 854 return (readResolveObjectMethod != null); 855 } 856 857 /** 858 * Returns when or not this class should be custom 859 * marshaled (use chunking). This should happen if 860 * it is Externalizable OR if it or 861 * any of its superclasses has a writeObject method, 862 */ 863 final boolean isCustomMarshaled() { 864 return (hasWriteObject() || isExternalizable()) 865 || (superclass != null && superclass.isCustomMarshaled()); 866 } 867 868 /* 869 * Return true if all instances of 'this' Externalizable class 870 * are written in block-data mode from the stream that 'this' was read 871 * from. <p> 872 * 873 * In JDK 1.1, all Externalizable instances are not written 874 * in block-data mode. 875 * In JDK 1.2, all Externalizable instances, by default, are written 876 * in block-data mode and the Externalizable instance is terminated with 877 * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable 878 * instances. 879 * 880 * IMPLEMENTATION NOTE: 881 * This should have been a mode maintained per stream; however, 882 * for compatibility reasons, it was only possible to record 883 * this change per class. All Externalizable classes within 884 * a given stream should either have this mode enabled or 885 * disabled. This is enforced by not allowing the PROTOCOL_VERSION 886 * of a stream to he changed after any objects have been written. 887 * 888 * @see ObjectOutputStream#useProtocolVersion 889 * @see ObjectStreamConstants#PROTOCOL_VERSION_1 890 * @see ObjectStreamConstants#PROTOCOL_VERSION_2 891 * 892 * @since JDK 1.2 893 */ 894 boolean hasExternalizableBlockDataMode() { 895 return hasExternalizableBlockData; 896 } 897 898 /** 899 * Creates a new instance of the represented class. If the class is 900 * externalizable, invokes its public no-arg constructor; otherwise, if the 901 * class is serializable, invokes the no-arg constructor of the first 902 * non-serializable superclass. Throws UnsupportedOperationException if 903 * this class descriptor is not associated with a class, if the associated 904 * class is non-serializable or if the appropriate no-arg constructor is 905 * inaccessible/unavailable. 906 */ 907 Object newInstance() 908 throws InstantiationException, InvocationTargetException, 909 UnsupportedOperationException 910 { 911 if (cons != null) { 912 try { 913 return cons.newInstance(); 914 } catch (IllegalAccessException ex) { 915 // should not occur, as access checks have been suppressed 916 InternalError ie = new InternalError(); 917 ie.initCause( ex ) ; 918 throw ie ; 919 } 920 } else { 921 throw new UnsupportedOperationException("no constructor for " + ofClass); 922 } 923 } 924 925 /** 926 * Returns public no-arg constructor of given class, or null if none found. 927 * Access checks are disabled on the returned constructor (if any), since 928 * the defining class may still be non-public. 929 */ 930 private static Constructor<?> getExternalizableConstructor(Class<?> cl) { 931 return bridge.newConstructorForExternalization(cl); 932 } 933 934 /** 935 * Returns subclass-accessible no-arg constructor of first non-serializable 936 * superclass, or null if none found. Access checks are disabled on the 937 * returned constructor (if any). 938 */ 939 private static Constructor<?> getSerializableConstructor(Class<?> cl) { 940 return bridge.newConstructorForSerialization(cl); 941 } 942 943 /* 944 * Return the ObjectStreamClass of the local class this one is based on. 945 */ 946 final ObjectStreamClass localClassDescriptor() { 947 return localClassDesc; 948 } 949 950 /* 951 * Get the Serializability of the class. 952 */ 953 boolean isSerializable() { 954 return serializable; 955 } 956 957 /* 958 * Get the externalizability of the class. 959 */ 960 boolean isExternalizable() { 961 return externalizable; 962 } 963 964 boolean isNonSerializable() { 965 return ! (externalizable || serializable); 966 } 967 968 /* 969 * Calculate the size of the array needed to store primitive data and the 970 * number of object references to read when reading from the input 971 * stream. 972 */ 973 private void computeFieldInfo() { 974 primBytes = 0; 975 objFields = 0; 976 977 for (int i = 0; i < fields.length; i++ ) { 978 switch (fields[i].getTypeCode()) { 979 case 'B': 980 case 'Z': 981 primBytes += 1; 982 break; 983 case 'C': 984 case 'S': 985 primBytes += 2; 986 break; 987 988 case 'I': 989 case 'F': 990 primBytes += 4; 991 break; 992 case 'J': 993 case 'D' : 994 primBytes += 8; 995 break; 996 997 case 'L': 998 case '[': 999 objFields += 1; 1000 break; 1001 } 1002 } 1003 } 1004 1005 private static void msg( String str ) 1006 { 1007 System.out.println( str ) ; 1008 } 1009 1010 /* JDK 1.5 has introduced some new modifier bits (such as SYNTHETIC) 1011 * that can affect the SVUID computation (see bug 4897937). These bits 1012 * must be ignored, as otherwise interoperability with ORBs in earlier 1013 * JDK versions can be compromised. I am adding these masks for this 1014 * purpose as discussed in the CCC for this bug (see http://ccc.sfbay/4897937). 1015 */ 1016 1017 public static final int CLASS_MASK = Modifier.PUBLIC | Modifier.FINAL | 1018 Modifier.INTERFACE | Modifier.ABSTRACT ; 1019 public static final int FIELD_MASK = Modifier.PUBLIC | Modifier.PRIVATE | 1020 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | 1021 Modifier.TRANSIENT | Modifier.VOLATILE ; 1022 public static final int METHOD_MASK = Modifier.PUBLIC | Modifier.PRIVATE | 1023 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | 1024 Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT | 1025 Modifier.STRICT ; 1026 1027 /* 1028 * Compute a hash for the specified class. Incrementally add 1029 * items to the hash accumulating in the digest stream. 1030 * Fold the hash into a long. Use the SHA secure hash function. 1031 */ 1032 private static long _computeSerialVersionUID(Class<?> cl) { 1033 if (DEBUG_SVUID) 1034 msg( "Computing SerialVersionUID for " + cl ) ; 1035 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512); 1036 1037 long h = 0; 1038 try { 1039 MessageDigest md = MessageDigest.getInstance("SHA"); 1040 DigestOutputStream mdo = new DigestOutputStream(devnull, md); 1041 DataOutputStream data = new DataOutputStream(mdo); 1042 1043 if (DEBUG_SVUID) 1044 msg( "\twriteUTF( \"" + cl.getName() + "\" )" ) ; 1045 data.writeUTF(cl.getName()); 1046 1047 int classaccess = cl.getModifiers(); 1048 classaccess &= (Modifier.PUBLIC | Modifier.FINAL | 1049 Modifier.INTERFACE | Modifier.ABSTRACT); 1050 1051 /* Workaround for javac bug that only set ABSTRACT for 1052 * interfaces if the interface had some methods. 1053 * The ABSTRACT bit reflects that the number of methods > 0. 1054 * This is required so correct hashes can be computed 1055 * for existing class files. 1056 * Previously this hack was previously present in the VM. 1057 */ 1058 Method[] method = cl.getDeclaredMethods(); 1059 if ((classaccess & Modifier.INTERFACE) != 0) { 1060 classaccess &= (~Modifier.ABSTRACT); 1061 if (method.length > 0) { 1062 classaccess |= Modifier.ABSTRACT; 1063 } 1064 } 1065 1066 // Mask out any post-1.4 attributes 1067 classaccess &= CLASS_MASK ; 1068 1069 if (DEBUG_SVUID) 1070 msg( "\twriteInt( " + classaccess + " ) " ) ; 1071 data.writeInt(classaccess); 1072 1073 /* 1074 * Get the list of interfaces supported, 1075 * Accumulate their names their names in Lexical order 1076 * and add them to the hash 1077 */ 1078 if (!cl.isArray()) { 1079 /* In 1.2fcs, getInterfaces() was modified to return 1080 * {java.lang.Cloneable, java.io.Serializable} when 1081 * called on array classes. These values would upset 1082 * the computation of the hash, so we explicitly omit 1083 * them from its computation. 1084 */ 1085 1086 Class<?> interfaces[] = cl.getInterfaces(); 1087 Arrays.sort(interfaces, compareClassByName); 1088 1089 for (int i = 0; i < interfaces.length; i++) { 1090 if (DEBUG_SVUID) 1091 msg( "\twriteUTF( \"" + interfaces[i].getName() + "\" ) " ) ; 1092 data.writeUTF(interfaces[i].getName()); 1093 } 1094 } 1095 1096 /* Sort the field names to get a deterministic order */ 1097 Field[] field = cl.getDeclaredFields(); 1098 Arrays.sort(field, compareMemberByName); 1099 1100 for (int i = 0; i < field.length; i++) { 1101 Field f = field[i]; 1102 1103 /* Include in the hash all fields except those that are 1104 * private transient and private static. 1105 */ 1106 int m = f.getModifiers(); 1107 if (Modifier.isPrivate(m) && 1108 (Modifier.isTransient(m) || Modifier.isStatic(m))) 1109 continue; 1110 1111 if (DEBUG_SVUID) 1112 msg( "\twriteUTF( \"" + f.getName() + "\" ) " ) ; 1113 data.writeUTF(f.getName()); 1114 1115 // Mask out any post-1.4 bits 1116 m &= FIELD_MASK ; 1117 1118 if (DEBUG_SVUID) 1119 msg( "\twriteInt( " + m + " ) " ) ; 1120 data.writeInt(m); 1121 1122 if (DEBUG_SVUID) 1123 msg( "\twriteUTF( \"" + getSignature(f.getType()) + "\" ) " ) ; 1124 data.writeUTF(getSignature(f.getType())); 1125 } 1126 1127 if (hasStaticInitializer(cl)) { 1128 if (DEBUG_SVUID) 1129 msg( "\twriteUTF( \"<clinit>\" ) " ) ; 1130 data.writeUTF("<clinit>"); 1131 1132 if (DEBUG_SVUID) 1133 msg( "\twriteInt( " + Modifier.STATIC + " )" ) ; 1134 data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have 1135 1136 if (DEBUG_SVUID) 1137 msg( "\twriteUTF( \"()V\" )" ) ; 1138 data.writeUTF("()V"); 1139 } 1140 1141 /* 1142 * Get the list of constructors including name and signature 1143 * Sort lexically, add all except the private constructors 1144 * to the hash with their access flags 1145 */ 1146 1147 MethodSignature[] constructors = 1148 MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors()); 1149 for (int i = 0; i < constructors.length; i++) { 1150 MethodSignature c = constructors[i]; 1151 String mname = "<init>"; 1152 String desc = c.signature; 1153 desc = desc.replace('/', '.'); 1154 if (DEBUG_SVUID) 1155 msg( "\twriteUTF( \"" + mname + "\" )" ) ; 1156 data.writeUTF(mname); 1157 1158 // mask out post-1.4 modifiers 1159 int modifier = c.member.getModifiers() & METHOD_MASK ; 1160 1161 if (DEBUG_SVUID) 1162 msg( "\twriteInt( " + modifier + " ) " ) ; 1163 data.writeInt( modifier ) ; 1164 1165 if (DEBUG_SVUID) 1166 msg( "\twriteUTF( \"" + desc+ "\" )" ) ; 1167 data.writeUTF(desc); 1168 } 1169 1170 /* Include in the hash all methods except those that are 1171 * private transient and private static. 1172 */ 1173 MethodSignature[] methods = 1174 MethodSignature.removePrivateAndSort(method); 1175 for (int i = 0; i < methods.length; i++ ) { 1176 MethodSignature m = methods[i]; 1177 String desc = m.signature; 1178 desc = desc.replace('/', '.'); 1179 1180 if (DEBUG_SVUID) 1181 msg( "\twriteUTF( \"" + m.member.getName()+ "\" )" ) ; 1182 data.writeUTF(m.member.getName()); 1183 1184 // mask out post-1.4 modifiers 1185 int modifier = m.member.getModifiers() & METHOD_MASK ; 1186 1187 if (DEBUG_SVUID) 1188 msg( "\twriteInt( " + modifier + " ) " ) ; 1189 data.writeInt( modifier ) ; 1190 1191 if (DEBUG_SVUID) 1192 msg( "\twriteUTF( \"" + desc + "\" )" ) ; 1193 data.writeUTF(desc); 1194 } 1195 1196 /* Compute the hash value for this class. 1197 * Use only the first 64 bits of the hash. 1198 */ 1199 data.flush(); 1200 byte hasharray[] = md.digest(); 1201 for (int i = 0; i < Math.min(8, hasharray.length); i++) { 1202 h += (long)(hasharray[i] & 255) << (i * 8); 1203 } 1204 } catch (IOException ignore) { 1205 /* can't happen, but be deterministic anyway. */ 1206 h = -1; 1207 } catch (NoSuchAlgorithmException complain) { 1208 SecurityException se = new SecurityException() ; 1209 se.initCause( complain ) ; 1210 throw se ; 1211 } 1212 1213 return h; 1214 } 1215 1216 private static long computeStructuralUID(com.sun.corba.se.impl.io.ObjectStreamClass osc, Class<?> cl) { 1217 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512); 1218 1219 long h = 0; 1220 try { 1221 1222 if ((!java.io.Serializable.class.isAssignableFrom(cl)) || 1223 (cl.isInterface())){ 1224 return 0; 1225 } 1226 1227 if (java.io.Externalizable.class.isAssignableFrom(cl)) { 1228 return 1; 1229 } 1230 1231 MessageDigest md = MessageDigest.getInstance("SHA"); 1232 DigestOutputStream mdo = new DigestOutputStream(devnull, md); 1233 DataOutputStream data = new DataOutputStream(mdo); 1234 1235 // Get SUID of parent 1236 Class<?> parent = cl.getSuperclass(); 1237 if ((parent != null)) 1238 // SerialBug 1; acc. to spec the one for 1239 // java.lang.object 1240 // should be computed and put 1241 // && (parent != java.lang.Object.class)) 1242 { 1243 //data.writeLong(computeSerialVersionUID(null,parent)); 1244 data.writeLong(computeStructuralUID(lookup(parent), parent)); 1245 } 1246 1247 if (osc.hasWriteObject()) 1248 data.writeInt(2); 1249 else 1250 data.writeInt(1); 1251 1252 // CORBA formal 00-11-03 10.6.2: For each field of the 1253 // class that is mapped to IDL, sorted lexicographically 1254 // by Java field name, in increasing order... 1255 ObjectStreamField[] field = osc.getFields(); 1256 if (field.length > 1) { 1257 Arrays.sort(field, compareObjStrFieldsByName); 1258 } 1259 1260 // ...Java field name in UTF encoding, field 1261 // descriptor, as defined by the JVM spec... 1262 for (int i = 0; i < field.length; i++) { 1263 data.writeUTF(field[i].getName()); 1264 data.writeUTF(field[i].getSignature()); 1265 } 1266 1267 /* Compute the hash value for this class. 1268 * Use only the first 64 bits of the hash. 1269 */ 1270 data.flush(); 1271 byte hasharray[] = md.digest(); 1272 // int minimum = Math.min(8, hasharray.length); 1273 // SerialBug 3: SHA computation is wrong; for loop reversed 1274 //for (int i = minimum; i > 0; i--) 1275 for (int i = 0; i < Math.min(8, hasharray.length); i++) { 1276 h += (long)(hasharray[i] & 255) << (i * 8); 1277 } 1278 } catch (IOException ignore) { 1279 /* can't happen, but be deterministic anyway. */ 1280 h = -1; 1281 } catch (NoSuchAlgorithmException complain) { 1282 SecurityException se = new SecurityException(); 1283 se.initCause( complain ) ; 1284 throw se ; 1285 } 1286 return h; 1287 } 1288 1289 /** 1290 * Compute the JVM signature for the class. 1291 */ 1292 static String getSignature(Class<?> clazz) { 1293 String type = null; 1294 if (clazz.isArray()) { 1295 Class<?> cl = clazz; 1296 int dimensions = 0; 1297 while (cl.isArray()) { 1298 dimensions++; 1299 cl = cl.getComponentType(); 1300 } 1301 StringBuffer sb = new StringBuffer(); 1302 for (int i = 0; i < dimensions; i++) { 1303 sb.append("["); 1304 } 1305 sb.append(getSignature(cl)); 1306 type = sb.toString(); 1307 } else if (clazz.isPrimitive()) { 1308 if (clazz == Integer.TYPE) { 1309 type = "I"; 1310 } else if (clazz == Byte.TYPE) { 1311 type = "B"; 1312 } else if (clazz == Long.TYPE) { 1313 type = "J"; 1314 } else if (clazz == Float.TYPE) { 1315 type = "F"; 1316 } else if (clazz == Double.TYPE) { 1317 type = "D"; 1318 } else if (clazz == Short.TYPE) { 1319 type = "S"; 1320 } else if (clazz == Character.TYPE) { 1321 type = "C"; 1322 } else if (clazz == Boolean.TYPE) { 1323 type = "Z"; 1324 } else if (clazz == Void.TYPE) { 1325 type = "V"; 1326 } 1327 } else { 1328 type = "L" + clazz.getName().replace('.', '/') + ";"; 1329 } 1330 return type; 1331 } 1332 1333 /* 1334 * Compute the JVM method descriptor for the method. 1335 */ 1336 static String getSignature(Method meth) { 1337 StringBuffer sb = new StringBuffer(); 1338 1339 sb.append("("); 1340 1341 Class<?>[] params = meth.getParameterTypes(); // avoid clone 1342 for (int j = 0; j < params.length; j++) { 1343 sb.append(getSignature(params[j])); 1344 } 1345 sb.append(")"); 1346 sb.append(getSignature(meth.getReturnType())); 1347 return sb.toString(); 1348 } 1349 1350 /* 1351 * Compute the JVM constructor descriptor for the constructor. 1352 */ 1353 static String getSignature(Constructor cons) { 1354 StringBuffer sb = new StringBuffer(); 1355 1356 sb.append("("); 1357 1358 Class<?>[] params = cons.getParameterTypes(); // avoid clone 1359 for (int j = 0; j < params.length; j++) { 1360 sb.append(getSignature(params[j])); 1361 } 1362 sb.append(")V"); 1363 return sb.toString(); 1364 } 1365 1366 /* 1367 * Cache of Class -> ClassDescriptor Mappings. 1368 */ 1369 static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61]; 1370 1371 /* 1372 * findDescriptorFor a Class. This looks in the cache for a 1373 * mapping from Class -> ObjectStreamClass mappings. The hashCode 1374 * of the Class is used for the lookup since the Class is the key. 1375 * The entries are extended from java.lang.ref.SoftReference so the 1376 * gc will be able to free them if needed. 1377 */ 1378 private static ObjectStreamClass findDescriptorFor(Class<?> cl) { 1379 1380 int hash = cl.hashCode(); 1381 int index = (hash & 0x7FFFFFFF) % descriptorFor.length; 1382 ObjectStreamClassEntry e; 1383 ObjectStreamClassEntry prev; 1384 1385 /* Free any initial entries whose refs have been cleared */ 1386 while ((e = descriptorFor[index]) != null && e.get() == null) { 1387 descriptorFor[index] = e.next; 1388 } 1389 1390 /* Traverse the chain looking for a descriptor with ofClass == cl. 1391 * unlink entries that are unresolved. 1392 */ 1393 prev = e; 1394 while (e != null ) { 1395 ObjectStreamClass desc = (ObjectStreamClass)(e.get()); 1396 if (desc == null) { 1397 // This entry has been cleared, unlink it 1398 prev.next = e.next; 1399 } else { 1400 if (desc.ofClass == cl) 1401 return desc; 1402 prev = e; 1403 } 1404 e = e.next; 1405 } 1406 return null; 1407 } 1408 1409 /* 1410 * insertDescriptorFor a Class -> ObjectStreamClass mapping. 1411 */ 1412 private static void insertDescriptorFor(ObjectStreamClass desc) { 1413 // Make sure not already present 1414 if (findDescriptorFor(desc.ofClass) != null) { 1415 return; 1416 } 1417 1418 int hash = desc.ofClass.hashCode(); 1419 int index = (hash & 0x7FFFFFFF) % descriptorFor.length; 1420 ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc); 1421 e.next = descriptorFor[index]; 1422 descriptorFor[index] = e; 1423 } 1424 1425 private static Field[] getDeclaredFields(final Class<?> clz) { 1426 return (Field[]) AccessController.doPrivileged(new PrivilegedAction() { 1427 public Object run() { 1428 return clz.getDeclaredFields(); 1429 } 1430 }); 1431 } 1432 1433 1434 /* 1435 * The name of this descriptor 1436 */ 1437 private String name; 1438 1439 /* 1440 * The descriptor of the supertype. 1441 */ 1442 private ObjectStreamClass superclass; 1443 1444 /* 1445 * Flags for Serializable and Externalizable. 1446 */ 1447 private boolean serializable; 1448 private boolean externalizable; 1449 1450 /* 1451 * Array of persistent fields of this class, sorted by 1452 * type and name. 1453 */ 1454 private ObjectStreamField[] fields; 1455 1456 /* 1457 * Class that is a descriptor for in this virtual machine. 1458 */ 1459 private Class<?> ofClass; 1460 1461 /* 1462 * True if descriptor for a proxy class. 1463 */ 1464 boolean forProxyClass; 1465 1466 1467 /* 1468 * SerialVersionUID for this class. 1469 */ 1470 private long suid = kDefaultUID; 1471 private String suidStr = null; 1472 1473 /* 1474 * Actual (computed) SerialVersionUID for this class. 1475 */ 1476 private long actualSuid = kDefaultUID; 1477 private String actualSuidStr = null; 1478 1479 /* 1480 * The total number of bytes of primitive fields. 1481 * The total number of object fields. 1482 */ 1483 int primBytes; 1484 int objFields; 1485 1486 /** 1487 * Flag indicating whether or not this instance has 1488 * successfully completed initialization. This is to 1489 * try to fix bug 4373844. Working to move to 1490 * reusing java.io.ObjectStreamClass for JDK 1.5. 1491 */ 1492 private boolean initialized = false; 1493 1494 /* Internal lock object. */ 1495 private Object lock = new Object(); 1496 1497 /* In JDK 1.1, external data was not written in block mode. 1498 * As of JDK 1.2, external data is written in block data mode. This 1499 * flag enables JDK 1.2 to be able to read JDK 1.1 written external data. 1500 * 1501 * @since JDK 1.2 1502 */ 1503 private boolean hasExternalizableBlockData; 1504 private transient MethodHandle writeObjectMethod; 1505 private transient MethodHandle readObjectMethod; 1506 private transient MethodHandle writeReplaceObjectMethod; 1507 private transient MethodHandle readResolveObjectMethod; 1508 private transient Constructor<?> cons; 1509 1510 /** 1511 * Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a 1512 * stream format version 2 which puts a fake valuetype around 1513 * a Serializable's optional custom data. This valuetype has 1514 * a special repository ID made from the Serializable's 1515 * information which we are pre-computing and 1516 * storing here. 1517 */ 1518 private String rmiiiopOptionalDataRepId = null; 1519 1520 /* 1521 * ObjectStreamClass that this one was built from. 1522 */ 1523 private ObjectStreamClass localClassDesc; 1524 1525 /** 1526 * Returns true if the given class defines a static initializer method, 1527 * false otherwise. 1528 */ 1529 private static boolean hasStaticInitializer(Class<?> cl) { 1530 return bridge.hasStaticInitializerForSerialization(cl); 1531 } 1532 1533 1534 /** use serialVersionUID from JDK 1.1. for interoperability */ 1535 private static final long serialVersionUID = -6120832682080437368L; 1536 1537 /** 1538 * Set serialPersistentFields of a Serializable class to this value to 1539 * denote that the class has no Serializable fields. 1540 */ 1541 public static final ObjectStreamField[] NO_FIELDS = 1542 new ObjectStreamField[0]; 1543 1544 /* 1545 * Entries held in the Cache of known ObjectStreamClass objects. 1546 * Entries are chained together with the same hash value (modulo array size). 1547 */ 1548 private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference 1549 { 1550 ObjectStreamClassEntry(ObjectStreamClass c) { 1551 //super(c); 1552 this.c = c; 1553 } 1554 ObjectStreamClassEntry next; 1555 1556 public Object get() 1557 { 1558 return c; 1559 } 1560 private ObjectStreamClass c; 1561 } 1562 1563 /* 1564 * Comparator object for Classes and Interfaces 1565 */ 1566 private static Comparator compareClassByName = 1567 new CompareClassByName(); 1568 1569 private static class CompareClassByName implements Comparator { 1570 public int compare(Object o1, Object o2) { 1571 Class<?> c1 = (Class)o1; 1572 Class<?> c2 = (Class)o2; 1573 return (c1.getName()).compareTo(c2.getName()); 1574 } 1575 } 1576 1577 /** 1578 * Comparator for ObjectStreamFields by name 1579 */ 1580 private final static Comparator compareObjStrFieldsByName 1581 = new CompareObjStrFieldsByName(); 1582 1583 private static class CompareObjStrFieldsByName implements Comparator { 1584 public int compare(Object o1, Object o2) { 1585 ObjectStreamField osf1 = (ObjectStreamField)o1; 1586 ObjectStreamField osf2 = (ObjectStreamField)o2; 1587 1588 return osf1.getName().compareTo(osf2.getName()); 1589 } 1590 } 1591 1592 /* 1593 * Comparator object for Members, Fields, and Methods 1594 */ 1595 private static Comparator compareMemberByName = 1596 new CompareMemberByName(); 1597 1598 private static class CompareMemberByName implements Comparator { 1599 public int compare(Object o1, Object o2) { 1600 String s1 = ((Member)o1).getName(); 1601 String s2 = ((Member)o2).getName(); 1602 1603 if (o1 instanceof Method) { 1604 s1 += getSignature((Method)o1); 1605 s2 += getSignature((Method)o2); 1606 } else if (o1 instanceof Constructor) { 1607 s1 += getSignature((Constructor)o1); 1608 s2 += getSignature((Constructor)o2); 1609 } 1610 return s1.compareTo(s2); 1611 } 1612 } 1613 1614 /* It is expensive to recompute a method or constructor signature 1615 many times, so compute it only once using this data structure. */ 1616 private static class MethodSignature implements Comparator { 1617 Member member; 1618 String signature; // cached parameter signature 1619 1620 /* Given an array of Method or Constructor members, 1621 return a sorted array of the non-private members.*/ 1622 /* A better implementation would be to implement the returned data 1623 structure as an insertion sorted link list.*/ 1624 static MethodSignature[] removePrivateAndSort(Member[] m) { 1625 int numNonPrivate = 0; 1626 for (int i = 0; i < m.length; i++) { 1627 if (! Modifier.isPrivate(m[i].getModifiers())) { 1628 numNonPrivate++; 1629 } 1630 } 1631 MethodSignature[] cm = new MethodSignature[numNonPrivate]; 1632 int cmi = 0; 1633 for (int i = 0; i < m.length; i++) { 1634 if (! Modifier.isPrivate(m[i].getModifiers())) { 1635 cm[cmi] = new MethodSignature(m[i]); 1636 cmi++; 1637 } 1638 } 1639 if (cmi > 0) 1640 Arrays.sort(cm, cm[0]); 1641 return cm; 1642 } 1643 1644 /* Assumes that o1 and o2 are either both methods 1645 or both constructors.*/ 1646 public int compare(Object o1, Object o2) { 1647 /* Arrays.sort calls compare when o1 and o2 are equal.*/ 1648 if (o1 == o2) 1649 return 0; 1650 1651 MethodSignature c1 = (MethodSignature)o1; 1652 MethodSignature c2 = (MethodSignature)o2; 1653 1654 int result; 1655 if (isConstructor()) { 1656 result = c1.signature.compareTo(c2.signature); 1657 } else { // is a Method. 1658 result = c1.member.getName().compareTo(c2.member.getName()); 1659 if (result == 0) 1660 result = c1.signature.compareTo(c2.signature); 1661 } 1662 return result; 1663 } 1664 1665 final private boolean isConstructor() { 1666 return member instanceof Constructor; 1667 } 1668 private MethodSignature(Member m) { 1669 member = m; 1670 if (isConstructor()) { 1671 signature = ObjectStreamClass.getSignature((Constructor)m); 1672 } else { 1673 signature = ObjectStreamClass.getSignature((Method)m); 1674 } 1675 } 1676 } 1677 1678 /** 1679 * Returns non-static, non-abstract method with given signature provided it 1680 * is defined by or accessible (via inheritance) by the given class, or 1681 * null if no match found. Access checks are disabled on the returned 1682 * method (if any). 1683 * 1684 * Copied from the Merlin java.io.ObjectStreamClass. 1685 */ 1686 private static Method getInheritableMethod(Class<?> cl, String name, 1687 Class<?>[] argTypes, 1688 Class<?> returnType) 1689 { 1690 Method meth = null; 1691 Class<?> defCl = cl; 1692 while (defCl != null) { 1693 try { 1694 meth = defCl.getDeclaredMethod(name, argTypes); 1695 break; 1696 } catch (NoSuchMethodException ex) { 1697 defCl = defCl.getSuperclass(); 1698 } 1699 } 1700 1701 if ((meth == null) || (meth.getReturnType() != returnType)) { 1702 return null; 1703 } 1704 int mods = meth.getModifiers(); 1705 if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) { 1706 return null; 1707 } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) { 1708 return meth; 1709 } else if ((mods & Modifier.PRIVATE) != 0) { 1710 return (cl == defCl) ? meth : null; 1711 } else { 1712 return packageEquals(cl, defCl) ? meth : null; 1713 } 1714 } 1715 1716 /** 1717 * Returns true if classes are defined in the same package, false 1718 * otherwise. 1719 * 1720 * Copied from the Merlin java.io.ObjectStreamClass. 1721 */ 1722 private static boolean packageEquals(Class<?> cl1, Class<?> cl2) { 1723 Package pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage(); 1724 return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2)))); 1725 } 1726} 1727