1 /* 2 * Copyright (c) 2001, 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 1999 All Rights Reserved 29 * 30 */ 31 32 package com.sun.corba.se.impl.orbutil; 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.Serializable; 56 import java.io.Externalizable; 57 58 import java.util.Arrays; 59 import java.util.Comparator; 60 import java.util.Hashtable; 61 62 import org.omg.CORBA.ValueMember; 63 64 import com.sun.corba.se.impl.io.ValueUtility; 65 import com.sun.corba.se.impl.io.ObjectStreamClass; 66 67 /** 68 * This is duplicated here to preserve the JDK 1.3.1FCS behavior 69 * of calculating the OMG hash code incorrectly when serialPersistentFields 70 * is used, but some of the fields no longer exist in the class itself. 71 * 72 * We have to duplicate it since we aren't allowed to modify the 73 * com.sun.corba.se.impl.io version further, and can't make it 74 * public outside of its package for security reasons. 75 */ 76 /** 77 * A ObjectStreamClass_1_3_1 describes a class that can be serialized to a stream 78 * or a class that was serialized to a stream. It contains the name 79 * and the serialVersionUID of the class. 80 * <br> 81 * The ObjectStreamClass_1_3_1 for a specific class loaded in this Java VM can 82 * be found using the lookup method. 83 * 84 * @author Roger Riggs 85 * @since 1.1 86 */ 87 public class ObjectStreamClass_1_3_1 implements java.io.Serializable { 88 89 public static final long kDefaultUID = -1; 90 91 private static Object noArgsList[] = {}; 92 private static Class<?> noTypesList[] = {}; 93 94 private static Hashtable translatedFields; 95 96 /** Find the descriptor for a class that can be serialized. Null 97 * is returned if the specified class does not implement 98 * java.io.Serializable or java.io.Externalizable. 99 */ 100 static final ObjectStreamClass_1_3_1 lookup(Class<?> cl) 101 { 102 ObjectStreamClass_1_3_1 desc = lookupInternal(cl); 103 if (desc.isSerializable() || desc.isExternalizable()) 104 return desc; 105 return null; 106 } 107 108 /* 109 * Find the class descriptor for the specified class. 110 * Package access only so it can be called from ObjectIn/OutStream. 111 */ 112 static ObjectStreamClass_1_3_1 lookupInternal(Class<?> cl) 113 { 114 /* Synchronize on the hashtable so no two threads will do 115 * this at the same time. 116 */ 117 ObjectStreamClass_1_3_1 desc = null; 118 synchronized (descriptorFor) { 119 /* Find the matching descriptor if it already known */ 120 desc = findDescriptorFor(cl); 121 if (desc != null) { 122 return desc; 123 } 124 125 /* Check if it's serializable */ 126 boolean serializable = Serializable.class.isAssignableFrom(cl); 127 /* If the class is only Serializable, 128 * lookup the descriptor for the superclass. 129 */ 130 ObjectStreamClass_1_3_1 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_1_3_1(cl, superdesc, 155 serializable, externalizable); 156 } 157 desc.init(); 158 return desc; 159 } 160 161 /** 162 * The name of the class described by this descriptor. 163 */ 164 public final String getName() { 165 return name; 166 } 167 168 /** 169 * Return the serialVersionUID for this class. 170 * The serialVersionUID defines a set of classes all with the same name 171 * that have evolved from a common root class and agree to be serialized 172 * and deserialized using a common format. 173 */ 174 public static final long getSerialVersionUID( java.lang.Class<?> clazz) { 175 ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz ); 176 if( theosc != null ) 177 { 178 return theosc.getSerialVersionUID( ); 179 } 180 return 0; 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 final long getSerialVersionUID() { 190 return suid; 191 } 192 193 /** 194 * Return the serialVersionUID string for this class. 195 * The serialVersionUID defines a set of classes all with the same name 196 * that have evolved from a common root class and agree to be serialized 197 * and deserialized using a common format. 198 */ 199 public final String getSerialVersionUIDStr() { 200 if (suidStr == null) 201 suidStr = Long.toHexString(suid).toUpperCase(); 202 return suidStr; 203 } 204 205 /** 206 * Return the actual (computed) serialVersionUID for this class. 207 */ 208 public static final long getActualSerialVersionUID( java.lang.Class<?> clazz ) 209 { 210 ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz ); 211 if( theosc != null ) 212 { 213 return theosc.getActualSerialVersionUID( ); 214 } 215 return 0; 216 } 217 218 /** 219 * Return the actual (computed) serialVersionUID for this class. 220 */ 221 public final long getActualSerialVersionUID() { 222 return actualSuid; 223 } 224 225 /** 226 * Return the actual (computed) serialVersionUID for this class. 227 */ 228 public final String getActualSerialVersionUIDStr() { 229 if (actualSuidStr == null) 230 actualSuidStr = Long.toHexString(actualSuid).toUpperCase(); 231 return actualSuidStr; 232 } 233 234 /** 235 * Return the class in the local VM that this version is mapped to. 236 * Null is returned if there is no corresponding local class. 237 */ 238 public final Class<?> forClass() { 239 return ofClass; 240 } 241 242 /** 243 * Return an array of the fields of this serializable class. 244 * @return an array containing an element for each persistent 245 * field of this class. Returns an array of length zero if 246 * there are no fields. 247 * @since 1.2 248 */ 249 public ObjectStreamField[] getFields() { 250 // Return a copy so the caller can't change the fields. 251 if (fields.length > 0) { 252 ObjectStreamField[] dup = new ObjectStreamField[fields.length]; 253 System.arraycopy(fields, 0, dup, 0, fields.length); 254 return dup; 255 } else { 256 return fields; 257 } 258 } 259 260 public boolean hasField(ValueMember field){ 261 262 for (int i = 0; i < fields.length; i++){ 263 try{ 264 if (fields[i].getName().equals(field.name)) { 265 266 if (fields[i].getSignature().equals(ValueUtility.getSignature(field))) 267 return true; 268 } 269 } 270 catch(Throwable t){} 271 } 272 return false; 273 } 274 275 /* Avoid unnecessary allocations. */ 276 final ObjectStreamField[] getFieldsNoCopy() { 277 return fields; 278 } 279 280 /** 281 * Get the field of this class by name. 282 * @return The ObjectStreamField object of the named field or null if there 283 * is no such named field. 284 */ 285 public final ObjectStreamField getField(String name) { 286 /* Binary search of fields by name. 287 */ 288 for (int i = fields.length-1; i >= 0; i--) { 289 if (name.equals(fields[i].getName())) { 290 return fields[i]; 291 } 292 } 293 return null; 294 } 295 296 public Serializable writeReplace(Serializable value) { 297 if (writeReplaceObjectMethod != null) { 298 try { 299 return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList); 300 } 301 catch(Throwable t) { 302 throw new RuntimeException(t.getMessage()); 303 } 304 } 305 else return value; 306 } 307 308 public Object readResolve(Object value) { 309 if (readResolveObjectMethod != null) { 310 try { 311 return readResolveObjectMethod.invoke(value,noArgsList); 312 } 313 catch(Throwable t) { 314 throw new RuntimeException(t.getMessage()); 315 } 316 } 317 else return value; 318 } 319 320 /** 321 * Return a string describing this ObjectStreamClass_1_3_1. 322 */ 323 public final String toString() { 324 StringBuffer sb = new StringBuffer(); 325 326 sb.append(name); 327 sb.append(": static final long serialVersionUID = "); 328 sb.append(Long.toString(suid)); 329 sb.append("L;"); 330 return sb.toString(); 331 } 332 333 /* 334 * Create a new ObjectStreamClass_1_3_1 from a loaded class. 335 * Don't call this directly, call lookup instead. 336 */ 337 private ObjectStreamClass_1_3_1(java.lang.Class<?> cl, ObjectStreamClass_1_3_1 superdesc, 338 boolean serial, boolean extern) 339 { 340 ofClass = cl; /* created from this class */ 341 342 if (Proxy.isProxyClass(cl)) { 343 forProxyClass = true; 344 } 345 346 name = cl.getName(); 347 superclass = superdesc; 348 serializable = serial; 349 if (!forProxyClass) { 350 // proxy classes are never externalizable 351 externalizable = extern; 352 } 353 354 /* 355 * Enter this class in the table of known descriptors. 356 * Otherwise, when the fields are read it may recurse 357 * trying to find the descriptor for itself. 358 */ 359 insertDescriptorFor(this); 360 361 /* 362 * The remainder of initialization occurs in init(), which is called 363 * after the lock on the global class descriptor table has been 364 * released. 365 */ 366 } 367 368 /* 369 * Initialize class descriptor. This method is only invoked on class 370 * descriptors created via calls to lookupInternal(). This method is kept 371 * separate from the ObjectStreamClass_1_3_1 constructor so that lookupInternal 372 * does not have to hold onto a global class descriptor table lock while the 373 * class descriptor is being initialized (see bug 4165204). 374 */ 375 376 377 private void init() { 378 synchronized (lock) { 379 380 final Class<?> cl = ofClass; 381 382 if (fields != null) // already initialized 383 return; 384 385 386 if (!serializable || 387 externalizable || 388 forProxyClass || 389 name.equals("java.lang.String")) { 390 fields = NO_FIELDS; 391 } else if (serializable) { 392 393 /* Ask for permission to override field access checks. 394 */ 395 AccessController.doPrivileged(new PrivilegedAction() { 396 public Object run() { 397 /* Fill in the list of persistent fields. 398 * If it is declared, use the declared serialPersistentFields. 399 * Otherwise, extract the fields from the class itself. 400 */ 401 try { 402 Field pf = cl.getDeclaredField("serialPersistentFields"); 403 // serial bug 7; the serialPersistentFields were not 404 // being read and stored as Accessible bit was not set 405 pf.setAccessible(true); 406 // serial bug 7; need to find if the field is of type 407 // java.io.ObjectStreamField 408 java.io.ObjectStreamField[] f = 409 (java.io.ObjectStreamField[])pf.get(cl); 410 int mods = pf.getModifiers(); 411 if ((Modifier.isPrivate(mods)) && 412 (Modifier.isStatic(mods)) && 413 (Modifier.isFinal(mods))) 414 { 415 fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl)); 416 } 417 } catch (NoSuchFieldException e) { 418 fields = null; 419 } catch (IllegalAccessException e) { 420 fields = null; 421 } catch (IllegalArgumentException e) { 422 fields = null; 423 } catch (ClassCastException e) { 424 /* Thrown if a field serialPersistentField exists 425 * but it is not of type ObjectStreamField. 426 */ 427 fields = null; 428 } 429 430 431 if (fields == null) { 432 /* Get all of the declared fields for this 433 * Class. setAccessible on all fields so they 434 * can be accessed later. Create a temporary 435 * ObjectStreamField array to hold each 436 * non-static, non-transient field. Then copy the 437 * temporary array into an array of the correct 438 * size once the number of fields is known. 439 */ 440 Field[] actualfields = cl.getDeclaredFields(); 441 442 int numFields = 0; 443 ObjectStreamField[] tempFields = 444 new ObjectStreamField[actualfields.length]; 445 for (int i = 0; i < actualfields.length; i++) { 446 int modifiers = actualfields[i].getModifiers(); 447 if (!Modifier.isStatic(modifiers) && 448 !Modifier.isTransient(modifiers)) { 449 tempFields[numFields++] = 450 new ObjectStreamField(actualfields[i]); 451 } 452 } 453 fields = new ObjectStreamField[numFields]; 454 System.arraycopy(tempFields, 0, fields, 0, numFields); 455 456 } else { 457 // For each declared persistent field, look for an actual 458 // reflected Field. If there is one, make sure it's the correct 459 // type and cache it in the ObjectStreamClass_1_3_1 for that field. 460 for (int j = fields.length-1; j >= 0; j--) { 461 try { 462 Field reflField = cl.getDeclaredField(fields[j].getName()); 463 if (fields[j].getType() == reflField.getType()) { 464 // reflField.setAccessible(true); 465 fields[j].setField(reflField); 466 } 467 } catch (NoSuchFieldException e) { 468 // Nothing to do 469 } 470 } 471 } 472 return null; 473 } 474 }); 475 476 if (fields.length > 1) 477 Arrays.sort(fields); 478 479 /* Set up field data for use while writing using the API api. */ 480 computeFieldInfo(); 481 } 482 483 /* Get the serialVersionUID from the class. 484 * It uses the access override mechanism so make sure 485 * the field objects is only used here. 486 * 487 * NonSerializable classes have a serialVerisonUID of 0L. 488 */ 489 if (isNonSerializable()) { 490 suid = 0L; 491 } else { 492 // Lookup special Serializable members using reflection. 493 AccessController.doPrivileged(new PrivilegedAction() { 494 public Object run() { 495 if (forProxyClass) { 496 // proxy classes always have serialVersionUID of 0L 497 suid = 0L; 498 } else { 499 try { 500 final Field f = cl.getDeclaredField("serialVersionUID"); 501 int mods = f.getModifiers(); 502 // SerialBug 5: static final SUID should be read 503 if (Modifier.isStatic(mods) && 504 Modifier.isFinal(mods) ) { 505 f.setAccessible(true); 506 suid = f.getLong(cl); 507 // get rid of native code 508 // suid = getSerialVersionUIDField(cl); 509 // SerialBug 2: should be computed after writeObject 510 // actualSuid = computeStructuralUID(cl); 511 } else { 512 suid = ObjectStreamClass.getSerialVersionUID(cl); 513 // SerialBug 2: should be computed after writeObject 514 // actualSuid = computeStructuralUID(cl); 515 } 516 } catch (NoSuchFieldException ex) { 517 suid = ObjectStreamClass.getSerialVersionUID(cl); 518 // SerialBug 2: should be computed after writeObject 519 // actualSuid = computeStructuralUID(cl); 520 } catch (IllegalAccessException ex) { 521 suid = ObjectStreamClass.getSerialVersionUID(cl); 522 } 523 } 524 525 526 try { 527 writeReplaceObjectMethod = cl.getDeclaredMethod("writeReplace", noTypesList); 528 if (Modifier.isStatic(writeReplaceObjectMethod.getModifiers())) { 529 writeReplaceObjectMethod = null; 530 } else { 531 writeReplaceObjectMethod.setAccessible(true); 532 } 533 534 } catch (NoSuchMethodException e2) { 535 536 } 537 538 try { 539 readResolveObjectMethod = cl.getDeclaredMethod("readResolve", noTypesList); 540 if (Modifier.isStatic(readResolveObjectMethod.getModifiers())) { 541 readResolveObjectMethod = null; 542 } else { 543 readResolveObjectMethod.setAccessible(true); 544 } 545 546 } catch (NoSuchMethodException e2) { 547 548 } 549 550 /* Cache lookup of writeObject and readObject for 551 * Serializable classes. (Do not lookup for 552 * Externalizable) 553 */ 554 555 if (serializable && !forProxyClass) { 556 557 /* Look for the writeObject method 558 * Set the accessible flag on it here. ObjectOutputStream 559 * will call it as necessary. 560 */ 561 try { 562 Class<?>[] args = {java.io.ObjectOutputStream.class}; 563 writeObjectMethod = cl.getDeclaredMethod("writeObject", args); 564 hasWriteObjectMethod = true; 565 int mods = writeObjectMethod.getModifiers(); 566 567 // Method must be private and non-static 568 if (!Modifier.isPrivate(mods) || 569 Modifier.isStatic(mods)) { 570 writeObjectMethod = null; 571 hasWriteObjectMethod = false; 572 } 573 574 } catch (NoSuchMethodException e) { 575 } 576 577 /* Look for the readObject method 578 * set the access override and save the reference for 579 * ObjectInputStream so it can all the method directly. 580 */ 581 try { 582 Class<?>[] args = {java.io.ObjectInputStream.class}; 583 readObjectMethod = cl.getDeclaredMethod("readObject", args); 584 int mods = readObjectMethod.getModifiers(); 585 586 // Method must be private and non-static 587 if (!Modifier.isPrivate(mods) || 588 Modifier.isStatic(mods)) { 589 readObjectMethod = null; 590 } 591 } catch (NoSuchMethodException e) { 592 } 593 // Compute the structural UID. This must be done after the 594 // calculation for writeObject. Fixed 4/20/2000, eea1 595 // SerialBug 2: to have correct value in RepId 596 } 597 return null; 598 } 599 }); 600 } 601 602 actualSuid = computeStructuralUID(this, cl); 603 } 604 605 } 606 607 /* 608 * Create an empty ObjectStreamClass_1_3_1 for a class about to be read. 609 * This is separate from read so ObjectInputStream can assign the 610 * wire handle early, before any nested ObjectStreamClass_1_3_1 might 611 * be read. 612 */ 613 ObjectStreamClass_1_3_1(String n, long s) { 614 name = n; 615 suid = s; 616 superclass = null; 617 } 618 619 private static Object[] translateFields(Object objs[]) 620 throws NoSuchFieldException { 621 try{ 622 java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs; 623 Object translation[] = null; 624 625 if (translatedFields == null) 626 translatedFields = new Hashtable(); 627 628 translation = (Object[])translatedFields.get(fields); 629 630 if (translation != null) 631 return translation; 632 else { 633 Class<?> osfClass = com.sun.corba.se.impl.orbutil.ObjectStreamField.class; 634 635 translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length); 636 Object arg[] = new Object[2]; 637 Class<?> types[] = {String.class, Class.class}; 638 Constructor constructor = osfClass.getDeclaredConstructor(types); 639 for (int i = fields.length -1; i >= 0; i--){ 640 arg[0] = fields[i].getName(); 641 arg[1] = fields[i].getType(); 642 643 translation[i] = constructor.newInstance(arg); 644 } 645 translatedFields.put(fields, translation); 646 647 } 648 649 return (Object[])translation; 650 } 651 catch(Throwable t){ 652 throw new NoSuchFieldException(); 653 } 654 } 655 656 /* Compare the base class names of streamName and localName. 657 * 658 * @return Return true iff the base class name compare. 659 * @parameter streamName Fully qualified class name. 660 * @parameter localName Fully qualified class name. 661 * @parameter pkgSeparator class names use either '.' or '/'. 662 * 663 * Only compare base class name to allow package renaming. 664 */ 665 static boolean compareClassNames(String streamName, 666 String localName, 667 char pkgSeparator) { 668 /* compare the class names, stripping off package names. */ 669 int streamNameIndex = streamName.lastIndexOf(pkgSeparator); 670 if (streamNameIndex < 0) 671 streamNameIndex = 0; 672 673 int localNameIndex = localName.lastIndexOf(pkgSeparator); 674 if (localNameIndex < 0) 675 localNameIndex = 0; 676 677 return streamName.regionMatches(false, streamNameIndex, 678 localName, localNameIndex, 679 streamName.length() - streamNameIndex); 680 } 681 682 /* 683 * Compare the types of two class descriptors. 684 * They match if they have the same class name and suid 685 */ 686 final boolean typeEquals(ObjectStreamClass_1_3_1 other) { 687 return (suid == other.suid) && 688 compareClassNames(name, other.name, '.'); 689 } 690 691 /* 692 * Return the superclass descriptor of this descriptor. 693 */ 694 final void setSuperclass(ObjectStreamClass_1_3_1 s) { 695 superclass = s; 696 } 697 698 /* 699 * Return the superclass descriptor of this descriptor. 700 */ 701 final ObjectStreamClass_1_3_1 getSuperclass() { 702 return superclass; 703 } 704 705 /* 706 * Return whether the class has a writeObject method 707 */ 708 final boolean hasWriteObject() { 709 return hasWriteObjectMethod; 710 } 711 712 final boolean isCustomMarshaled() { 713 return (hasWriteObject() || isExternalizable()); 714 } 715 716 /* 717 * Return true if all instances of 'this' Externalizable class 718 * are written in block-data mode from the stream that 'this' was read 719 * from. <p> 720 * 721 * In JDK 1.1, all Externalizable instances are not written 722 * in block-data mode. 723 * In JDK 1.2, all Externalizable instances, by default, are written 724 * in block-data mode and the Externalizable instance is terminated with 725 * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable 726 * instances. 727 * 728 * IMPLEMENTATION NOTE: 729 * This should have been a mode maintained per stream; however, 730 * for compatibility reasons, it was only possible to record 731 * this change per class. All Externalizable classes within 732 * a given stream should either have this mode enabled or 733 * disabled. This is enforced by not allowing the PROTOCOL_VERSION 734 * of a stream to he changed after any objects have been written. 735 * 736 * @see ObjectOutputStream#useProtocolVersion 737 * @see ObjectStreamConstants#PROTOCOL_VERSION_1 738 * @see ObjectStreamConstants#PROTOCOL_VERSION_2 739 * 740 * @since 1.2 741 */ 742 boolean hasExternalizableBlockDataMode() { 743 return hasExternalizableBlockData; 744 } 745 746 /* 747 * Return the ObjectStreamClass_1_3_1 of the local class this one is based on. 748 */ 749 final ObjectStreamClass_1_3_1 localClassDescriptor() { 750 return localClassDesc; 751 } 752 753 /* 754 * Get the Serializability of the class. 755 */ 756 boolean isSerializable() { 757 return serializable; 758 } 759 760 /* 761 * Get the externalizability of the class. 762 */ 763 boolean isExternalizable() { 764 return externalizable; 765 } 766 767 boolean isNonSerializable() { 768 return ! (externalizable || serializable); 769 } 770 771 /* 772 * Calculate the size of the array needed to store primitive data and the 773 * number of object references to read when reading from the input 774 * stream. 775 */ 776 private void computeFieldInfo() { 777 primBytes = 0; 778 objFields = 0; 779 780 for (int i = 0; i < fields.length; i++ ) { 781 switch (fields[i].getTypeCode()) { 782 case 'B': 783 case 'Z': 784 primBytes += 1; 785 break; 786 case 'C': 787 case 'S': 788 primBytes += 2; 789 break; 790 791 case 'I': 792 case 'F': 793 primBytes += 4; 794 break; 795 case 'J': 796 case 'D' : 797 primBytes += 8; 798 break; 799 800 case 'L': 801 case '[': 802 objFields += 1; 803 break; 804 } 805 } 806 } 807 808 private static long computeStructuralUID(ObjectStreamClass_1_3_1 osc, Class<?> cl) { 809 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512); 810 811 long h = 0; 812 try { 813 814 if ((!java.io.Serializable.class.isAssignableFrom(cl)) || 815 (cl.isInterface())){ 816 return 0; 817 } 818 819 if (java.io.Externalizable.class.isAssignableFrom(cl)) { 820 return 1; 821 } 822 823 MessageDigest md = MessageDigest.getInstance("SHA"); 824 DigestOutputStream mdo = new DigestOutputStream(devnull, md); 825 DataOutputStream data = new DataOutputStream(mdo); 826 827 // Get SUID of parent 828 Class<?> parent = cl.getSuperclass(); 829 if ((parent != null)) 830 // SerialBug 1; acc. to spec the one for 831 // java.lang.object 832 // should be computed and put 833 // && (parent != java.lang.Object.class)) 834 { 835 //data.writeLong(computeSerialVersionUID(null,parent)); 836 data.writeLong(computeStructuralUID(lookup(parent), parent)); 837 } 838 839 if (osc.hasWriteObject()) 840 data.writeInt(2); 841 else 842 data.writeInt(1); 843 844 /* Sort the field names to get a deterministic order */ 845 // Field[] field = ObjectStreamClass_1_3_1.getDeclaredFields(cl); 846 847 ObjectStreamField[] fields = osc.getFields(); 848 849 // Must make sure that the Field array we allocate 850 // below is exactly the right size. Bug fix for 851 // 4397133. 852 int numNonNullFields = 0; 853 for (int i = 0; i < fields.length; i++) 854 if (fields[i].getField() != null) 855 numNonNullFields++; 856 857 Field [] field = new java.lang.reflect.Field[numNonNullFields]; 858 for (int i = 0, fieldNum = 0; i < fields.length; i++) { 859 if (fields[i].getField() != null) { 860 field[fieldNum++] = fields[i].getField(); 861 } 862 } 863 864 if (field.length > 1) 865 Arrays.sort(field, compareMemberByName); 866 867 for (int i = 0; i < field.length; i++) { 868 Field f = field[i]; 869 870 /* Include in the hash all fields except those that are 871 * transient 872 */ 873 int m = f.getModifiers(); 874 //Serial 6 875 //if (Modifier.isTransient(m) || Modifier.isStatic(m)) 876 // spec reference 00-01-06.pdf, 1.3.5.6, states non-static 877 // non-transient, public fields are mapped to Java IDL. 878 // 879 // Here's the quote from the first paragraph: 880 // Java non-static non-transient public fields are mapped to 881 // OMG IDL public data members, and other Java fields are 882 // not mapped. 883 884 // if (Modifier.isTransient(m) || Modifier.isStatic(m)) 885 // continue; 886 887 data.writeUTF(f.getName()); 888 data.writeUTF(getSignature(f.getType())); 889 } 890 891 /* Compute the hash value for this class. 892 * Use only the first 64 bits of the hash. 893 */ 894 data.flush(); 895 byte hasharray[] = md.digest(); 896 // int minimum = Math.min(8, hasharray.length); 897 // SerialBug 3: SHA computation is wrong; for loop reversed 898 //for (int i = minimum; i > 0; i--) 899 for (int i = 0; i < Math.min(8, hasharray.length); i++) { 900 h += (long)(hasharray[i] & 255) << (i * 8); 901 } 902 } catch (IOException ignore) { 903 /* can't happen, but be deterministic anyway. */ 904 h = -1; 905 } catch (NoSuchAlgorithmException complain) { 906 throw new SecurityException(complain.getMessage()); 907 } 908 return h; 909 } 910 911 /** 912 * Compute the JVM signature for the class. 913 */ 914 static String getSignature(Class<?> clazz) { 915 String type = null; 916 if (clazz.isArray()) { 917 Class<?> cl = clazz; 918 int dimensions = 0; 919 while (cl.isArray()) { 920 dimensions++; 921 cl = cl.getComponentType(); 922 } 923 StringBuffer sb = new StringBuffer(); 924 for (int i = 0; i < dimensions; i++) { 925 sb.append("["); 926 } 927 sb.append(getSignature(cl)); 928 type = sb.toString(); 929 } else if (clazz.isPrimitive()) { 930 if (clazz == Integer.TYPE) { 931 type = "I"; 932 } else if (clazz == Byte.TYPE) { 933 type = "B"; 934 } else if (clazz == Long.TYPE) { 935 type = "J"; 936 } else if (clazz == Float.TYPE) { 937 type = "F"; 938 } else if (clazz == Double.TYPE) { 939 type = "D"; 940 } else if (clazz == Short.TYPE) { 941 type = "S"; 942 } else if (clazz == Character.TYPE) { 943 type = "C"; 944 } else if (clazz == Boolean.TYPE) { 945 type = "Z"; 946 } else if (clazz == Void.TYPE) { 947 type = "V"; 948 } 949 } else { 950 type = "L" + clazz.getName().replace('.', '/') + ";"; 951 } 952 return type; 953 } 954 955 /* 956 * Compute the JVM method descriptor for the method. 957 */ 958 static String getSignature(Method meth) { 959 StringBuffer sb = new StringBuffer(); 960 961 sb.append("("); 962 963 Class<?>[] params = meth.getParameterTypes(); // avoid clone 964 for (int j = 0; j < params.length; j++) { 965 sb.append(getSignature(params[j])); 966 } 967 sb.append(")"); 968 sb.append(getSignature(meth.getReturnType())); 969 return sb.toString(); 970 } 971 972 /* 973 * Compute the JVM constructor descriptor for the constructor. 974 */ 975 static String getSignature(Constructor cons) { 976 StringBuffer sb = new StringBuffer(); 977 978 sb.append("("); 979 980 Class<?>[] params = cons.getParameterTypes(); // avoid clone 981 for (int j = 0; j < params.length; j++) { 982 sb.append(getSignature(params[j])); 983 } 984 sb.append(")V"); 985 return sb.toString(); 986 } 987 988 /* 989 * Cache of Class -> ClassDescriptor Mappings. 990 */ 991 static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61]; 992 993 /* 994 * findDescriptorFor a Class. This looks in the cache for a 995 * mapping from Class -> ObjectStreamClass mappings. The hashCode 996 * of the Class is used for the lookup since the Class is the key. 997 * The entries are extended from java.lang.ref.SoftReference so the 998 * gc will be able to free them if needed. 999 */ 1000 private static ObjectStreamClass_1_3_1 findDescriptorFor(Class<?> cl) { 1001 1002 int hash = cl.hashCode(); 1003 int index = (hash & 0x7FFFFFFF) % descriptorFor.length; 1004 ObjectStreamClassEntry e; 1005 ObjectStreamClassEntry prev; 1006 1007 /* Free any initial entries whose refs have been cleared */ 1008 while ((e = descriptorFor[index]) != null && e.get() == null) { 1009 descriptorFor[index] = e.next; 1010 } 1011 1012 /* Traverse the chain looking for a descriptor with ofClass == cl. 1013 * unlink entries that are unresolved. 1014 */ 1015 prev = e; 1016 while (e != null ) { 1017 ObjectStreamClass_1_3_1 desc = (ObjectStreamClass_1_3_1)(e.get()); 1018 if (desc == null) { 1019 // This entry has been cleared, unlink it 1020 prev.next = e.next; 1021 } else { 1022 if (desc.ofClass == cl) 1023 return desc; 1024 prev = e; 1025 } 1026 e = e.next; 1027 } 1028 return null; 1029 } 1030 1031 /* 1032 * insertDescriptorFor a Class -> ObjectStreamClass_1_3_1 mapping. 1033 */ 1034 private static void insertDescriptorFor(ObjectStreamClass_1_3_1 desc) { 1035 // Make sure not already present 1036 if (findDescriptorFor(desc.ofClass) != null) { 1037 return; 1038 } 1039 1040 int hash = desc.ofClass.hashCode(); 1041 int index = (hash & 0x7FFFFFFF) % descriptorFor.length; 1042 ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc); 1043 e.next = descriptorFor[index]; 1044 descriptorFor[index] = e; 1045 } 1046 1047 private static Field[] getDeclaredFields(final Class clz) { 1048 return (Field[]) AccessController.doPrivileged(new PrivilegedAction() { 1049 public Object run() { 1050 return clz.getDeclaredFields(); 1051 } 1052 }); 1053 } 1054 1055 1056 /* 1057 * The name of this descriptor 1058 */ 1059 private String name; 1060 1061 /* 1062 * The descriptor of the supertype. 1063 */ 1064 private ObjectStreamClass_1_3_1 superclass; 1065 1066 /* 1067 * Flags for Serializable and Externalizable. 1068 */ 1069 private boolean serializable; 1070 private boolean externalizable; 1071 1072 /* 1073 * Array of persistent fields of this class, sorted by 1074 * type and name. 1075 */ 1076 private ObjectStreamField[] fields; 1077 1078 /* 1079 * Class that is a descriptor for in this virtual machine. 1080 */ 1081 private Class<?> ofClass; 1082 1083 /* 1084 * True if descriptor for a proxy class. 1085 */ 1086 boolean forProxyClass; 1087 1088 1089 /* 1090 * SerialVersionUID for this class. 1091 */ 1092 private long suid = kDefaultUID; 1093 private String suidStr = null; 1094 1095 /* 1096 * Actual (computed) SerialVersionUID for this class. 1097 */ 1098 private long actualSuid = kDefaultUID; 1099 private String actualSuidStr = null; 1100 1101 /* 1102 * The total number of bytes of primitive fields. 1103 * The total number of object fields. 1104 */ 1105 int primBytes; 1106 int objFields; 1107 1108 /* Internal lock object. */ 1109 private Object lock = new Object(); 1110 1111 /* True if this class has/had a writeObject method */ 1112 private boolean hasWriteObjectMethod; 1113 1114 /* In JDK 1.1, external data was not written in block mode. 1115 * As of JDK 1.2, external data is written in block data mode. This 1116 * flag enables JDK 1.2 to be able to read JDK 1.1 written external data. 1117 * 1118 * @since 1.2 1119 */ 1120 private boolean hasExternalizableBlockData; 1121 Method writeObjectMethod; 1122 Method readObjectMethod; 1123 private transient Method writeReplaceObjectMethod; 1124 private transient Method readResolveObjectMethod; 1125 1126 /* 1127 * ObjectStreamClass_1_3_1 that this one was built from. 1128 */ 1129 private ObjectStreamClass_1_3_1 localClassDesc; 1130 1131 /* Get the private static final field for serial version UID */ 1132 // private static native long getSerialVersionUIDField(Class cl); 1133 1134 /** use serialVersionUID from JDK 1.1. for interoperability */ 1135 private static final long serialVersionUID = -6120832682080437368L; 1136 1137 /** 1138 * Set serialPersistentFields of a Serializable class to this value to 1139 * denote that the class has no Serializable fields. 1140 */ 1141 public static final ObjectStreamField[] NO_FIELDS = 1142 new ObjectStreamField[0]; 1143 1144 /* 1145 * Entries held in the Cache of known ObjectStreamClass_1_3_1 objects. 1146 * Entries are chained together with the same hash value (modulo array size). 1147 */ 1148 private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference 1149 { 1150 ObjectStreamClassEntry(ObjectStreamClass_1_3_1 c) { 1151 //super(c); 1152 this.c = c; 1153 } 1154 ObjectStreamClassEntry next; 1155 1156 public Object get() 1157 { 1158 return c; 1159 } 1160 private ObjectStreamClass_1_3_1 c; 1161 } 1162 1163 /* 1164 * Comparator object for Classes and Interfaces 1165 */ 1166 private static Comparator compareClassByName = 1167 new CompareClassByName(); 1168 1169 private static class CompareClassByName implements Comparator { 1170 public int compare(Object o1, Object o2) { 1171 Class<?> c1 = (Class)o1; 1172 Class<?> c2 = (Class)o2; 1173 return (c1.getName()).compareTo(c2.getName()); 1174 } 1175 } 1176 1177 /* 1178 * Comparator object for Members, Fields, and Methods 1179 */ 1180 private static Comparator compareMemberByName = 1181 new CompareMemberByName(); 1182 1183 private static class CompareMemberByName implements Comparator { 1184 public int compare(Object o1, Object o2) { 1185 String s1 = ((Member)o1).getName(); 1186 String s2 = ((Member)o2).getName(); 1187 1188 if (o1 instanceof Method) { 1189 s1 += getSignature((Method)o1); 1190 s2 += getSignature((Method)o2); 1191 } else if (o1 instanceof Constructor) { 1192 s1 += getSignature((Constructor)o1); 1193 s2 += getSignature((Constructor)o2); 1194 } 1195 return s1.compareTo(s2); 1196 } 1197 } 1198 1199 /* It is expensive to recompute a method or constructor signature 1200 many times, so compute it only once using this data structure. */ 1201 private static class MethodSignature implements Comparator { 1202 Member member; 1203 String signature; // cached parameter signature 1204 1205 /* Given an array of Method or Constructor members, 1206 return a sorted array of the non-private members.*/ 1207 /* A better implementation would be to implement the returned data 1208 structure as an insertion sorted link list.*/ 1209 static MethodSignature[] removePrivateAndSort(Member[] m) { 1210 int numNonPrivate = 0; 1211 for (int i = 0; i < m.length; i++) { 1212 if (! Modifier.isPrivate(m[i].getModifiers())) { 1213 numNonPrivate++; 1214 } 1215 } 1216 MethodSignature[] cm = new MethodSignature[numNonPrivate]; 1217 int cmi = 0; 1218 for (int i = 0; i < m.length; i++) { 1219 if (! Modifier.isPrivate(m[i].getModifiers())) { 1220 cm[cmi] = new MethodSignature(m[i]); 1221 cmi++; 1222 } 1223 } 1224 if (cmi > 0) 1225 Arrays.sort(cm, cm[0]); 1226 return cm; 1227 } 1228 1229 /* Assumes that o1 and o2 are either both methods 1230 or both constructors.*/ 1231 public int compare(Object o1, Object o2) { 1232 /* Arrays.sort calls compare when o1 and o2 are equal.*/ 1233 if (o1 == o2) 1234 return 0; 1235 1236 MethodSignature c1 = (MethodSignature)o1; 1237 MethodSignature c2 = (MethodSignature)o2; 1238 1239 int result; 1240 if (isConstructor()) { 1241 result = c1.signature.compareTo(c2.signature); 1242 } else { // is a Method. 1243 result = c1.member.getName().compareTo(c2.member.getName()); 1244 if (result == 0) 1245 result = c1.signature.compareTo(c2.signature); 1246 } 1247 return result; 1248 } 1249 1250 final private boolean isConstructor() { 1251 return member instanceof Constructor; 1252 } 1253 private MethodSignature(Member m) { 1254 member = m; 1255 if (isConstructor()) { 1256 signature = ObjectStreamClass_1_3_1.getSignature((Constructor)m); 1257 } else { 1258 signature = ObjectStreamClass_1_3_1.getSignature((Method)m); 1259 } 1260 } 1261 } 1262 }