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