1 7 8 package java.io; 9 10 import java.lang.ref.Reference ; 11 import java.lang.ref.ReferenceQueue ; 12 import java.lang.ref.SoftReference ; 13 import java.lang.ref.WeakReference ; 14 import java.lang.reflect.Constructor ; 15 import java.lang.reflect.Field ; 16 import java.lang.reflect.InvocationTargetException ; 17 import java.lang.reflect.Member ; 18 import java.lang.reflect.Method ; 19 import java.lang.reflect.Modifier ; 20 import java.lang.reflect.Proxy ; 21 import java.security.AccessController ; 22 import java.security.MessageDigest ; 23 import java.security.NoSuchAlgorithmException ; 24 import java.security.PrivilegedAction ; 25 import java.util.ArrayList ; 26 import java.util.Arrays ; 27 import java.util.Collections ; 28 import java.util.Comparator ; 29 import java.util.HashSet ; 30 import java.util.Set ; 31 import java.util.concurrent.ConcurrentHashMap ; 32 import java.util.concurrent.ConcurrentMap ; 33 import sun.misc.Unsafe; 34 import sun.reflect.ReflectionFactory; 35 36 52 public class ObjectStreamClass implements Serializable { 53 54 55 public static final ObjectStreamField [] NO_FIELDS = 56 new ObjectStreamField [0]; 57 58 private static final long serialVersionUID = -6120832682080437368L; 59 private static final ObjectStreamField [] serialPersistentFields = 60 NO_FIELDS; 61 62 63 private static final ReflectionFactory reflFactory = (ReflectionFactory) 64 AccessController.doPrivileged( 65 new ReflectionFactory.GetReflectionFactoryAction()); 66 67 private static class Caches { 68 69 static final ConcurrentMap <WeakClassKey,Reference <?>> localDescs = 70 new ConcurrentHashMap <WeakClassKey,Reference <?>>(); 71 72 73 static final ConcurrentMap <FieldReflectorKey,Reference <?>> reflectors = 74 new ConcurrentHashMap <FieldReflectorKey,Reference <?>>(); 75 76 77 private static final ReferenceQueue <Class <?>> localDescsQueue = 78 new ReferenceQueue <Class <?>>(); 79 80 private static final ReferenceQueue <Class <?>> reflectorsQueue = 81 new ReferenceQueue <Class <?>>(); 82 } 83 84 85 private Class cl; 86 87 private String name; 88 89 private volatile Long suid; 90 91 92 private boolean isProxy; 93 94 private boolean isEnum; 95 96 private boolean serializable; 97 98 private boolean externalizable; 99 100 private boolean hasWriteObjectData; 101 107 private boolean hasBlockExternalData = true; 108 109 110 private ClassNotFoundException resolveEx; 111 112 private InvalidClassException deserializeEx; 113 114 private InvalidClassException serializeEx; 115 116 private InvalidClassException defaultSerializeEx; 117 118 119 private ObjectStreamField [] fields; 120 121 private int primDataSize; 122 123 private int numObjFields; 124 125 private FieldReflector fieldRefl; 126 127 private volatile ClassDataSlot[] dataLayout; 128 129 130 private Constructor cons; 131 132 private Method writeObjectMethod; 133 134 private Method readObjectMethod; 135 136 private Method readObjectNoDataMethod; 137 138 private Method writeReplaceMethod; 139 140 private Method readResolveMethod; 141 142 143 private ObjectStreamClass localDesc; 144 145 private ObjectStreamClass superDesc; 146 147 150 private static native void initNative(); 151 static { 152 initNative(); 153 } 154 155 164 public static ObjectStreamClass lookup(Class <?> cl) { 165 return lookup(cl, false); 166 } 167 168 174 public String getName() { 175 return name; 176 } 177 178 186 public long getSerialVersionUID() { 187 if (suid == null) { 189 suid = (Long ) AccessController.doPrivileged( 190 new PrivilegedAction () { 191 public Object run() { 192 return new Long (computeDefaultSUID(cl)); 193 } 194 } 195 ); 196 } 197 return suid.longValue(); 198 } 199 200 206 public Class <?> forClass() { 207 return cl; 208 } 209 210 218 public ObjectStreamField [] getFields() { 219 return getFields(true); 220 } 221 222 229 public ObjectStreamField getField(String name) { 230 return getField(name, null); 231 } 232 233 236 public String toString() { 237 return name + ": static final long serialVersionUID = " + 238 getSerialVersionUID() + "L;"; 239 } 240 241 249 static ObjectStreamClass lookup(Class cl, boolean all) { 250 if (!(all || Serializable .class.isAssignableFrom(cl))) { 251 return null; 252 } 253 processQueue(Caches.localDescsQueue, Caches.localDescs); 254 WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); 255 Reference <?> ref = Caches.localDescs.get(key); 256 Object entry = null; 257 if (ref != null) { 258 entry = ref.get(); 259 } 260 EntryFuture future = null; 261 if (entry == null) { 262 EntryFuture newEntry = new EntryFuture(); 263 Reference <?> newRef = new SoftReference <EntryFuture>(newEntry); 264 do { 265 if (ref != null) { 266 Caches.localDescs.remove(key, ref); 267 } 268 ref = Caches.localDescs.putIfAbsent(key, newRef); 269 if (ref != null) { 270 entry = ref.get(); 271 } 272 } while (ref != null && entry == null); 273 if (entry == null) { 274 future = newEntry; 275 } 276 } 277 278 if (entry instanceof ObjectStreamClass ) { return (ObjectStreamClass ) entry; 280 } 281 if (entry instanceof EntryFuture) { 282 future = (EntryFuture) entry; 283 if (future.getOwner() == Thread.currentThread()) { 284 290 entry = null; 291 } else { 292 entry = future.get(); 293 } 294 } 295 if (entry == null) { 296 try { 297 entry = new ObjectStreamClass (cl); 298 } catch (Throwable th) { 299 entry = th; 300 } 301 if (future.set(entry)) { 302 Caches.localDescs.put(key, new SoftReference <Object >(entry)); 303 } else { 304 entry = future.get(); 306 } 307 } 308 309 if (entry instanceof ObjectStreamClass ) { 310 return (ObjectStreamClass ) entry; 311 } else if (entry instanceof RuntimeException ) { 312 throw (RuntimeException ) entry; 313 } else if (entry instanceof Error ) { 314 throw (Error ) entry; 315 } else { 316 throw new InternalError ("unexpected entry: " + entry); 317 } 318 } 319 320 328 private static class EntryFuture { 329 330 private static final Object unset = new Object (); 331 private final Thread owner = Thread.currentThread(); 332 private Object entry = unset; 333 334 341 synchronized boolean set(Object entry) { 342 if (this.entry != unset) { 343 return false; 344 } 345 this.entry = entry; 346 notifyAll(); 347 return true; 348 } 349 350 354 synchronized Object get() { 355 boolean interrupted = false; 356 while (entry == unset) { 357 try { 358 wait(); 359 } catch (InterruptedException ex) { 360 interrupted = true; 361 } 362 } 363 if (interrupted) { 364 AccessController.doPrivileged( 365 new PrivilegedAction () { 366 public Object run() { 367 Thread.currentThread().interrupt(); 368 return null; 369 } 370 } 371 ); 372 } 373 return entry; 374 } 375 376 379 Thread getOwner() { 380 return owner; 381 } 382 } 383 384 387 private ObjectStreamClass(final Class cl) { 388 this.cl = cl; 389 name = cl.getName(); 390 isProxy = Proxy.isProxyClass(cl); 391 isEnum = Enum .class.isAssignableFrom(cl); 392 serializable = Serializable .class.isAssignableFrom(cl); 393 externalizable = Externalizable .class.isAssignableFrom(cl); 394 395 Class superCl = cl.getSuperclass(); 396 superDesc = (superCl != null) ? lookup(superCl, false) : null; 397 localDesc = this; 398 399 if (serializable) { 400 AccessController.doPrivileged(new PrivilegedAction () { 401 public Object run() { 402 if (isEnum) { 403 suid = new Long (0); 404 fields = NO_FIELDS; 405 return null; 406 } 407 408 suid = getDeclaredSUID(cl); 409 try { 410 fields = getSerialFields(cl); 411 computeFieldOffsets(); 412 } catch (InvalidClassException e) { 413 serializeEx = deserializeEx = e; 414 fields = NO_FIELDS; 415 } 416 417 if (externalizable) { 418 cons = getExternalizableConstructor(cl); 419 } else { 420 cons = getSerializableConstructor(cl); 421 writeObjectMethod = getPrivateMethod(cl, "writeObject", 422 new Class [] { ObjectOutputStream .class }, 423 Void.TYPE); 424 readObjectMethod = getPrivateMethod(cl, "readObject", 425 new Class [] { ObjectInputStream .class }, 426 Void.TYPE); 427 readObjectNoDataMethod = getPrivateMethod( 428 cl, "readObjectNoData", 429 new Class [0], Void.TYPE); 430 hasWriteObjectData = (writeObjectMethod != null); 431 } 432 writeReplaceMethod = getInheritableMethod( 433 cl, "writeReplace", new Class [0], Object .class); 434 readResolveMethod = getInheritableMethod( 435 cl, "readResolve", new Class [0], Object .class); 436 return null; 437 } 438 }); 439 } else { 440 suid = new Long (0); 441 fields = NO_FIELDS; 442 } 443 444 try { 445 fieldRefl = getReflector(fields, this); 446 } catch (InvalidClassException ex) { 447 throw new InternalError (); 449 } 450 451 if (deserializeEx == null) { 452 if (isEnum) { 453 deserializeEx = new InvalidClassException (name, "enum type"); 454 } else if (cons == null) { 455 deserializeEx = new InvalidClassException ( 456 name, "no valid constructor"); 457 } 458 } 459 for (int i = 0; i < fields.length; i++) { 460 if (fields[i].getField() == null) { 461 defaultSerializeEx = new InvalidClassException ( 462 name, "unmatched serializable field(s) declared"); 463 } 464 } 465 } 466 467 471 ObjectStreamClass() { 472 } 473 474 477 void initProxy(Class cl, 478 ClassNotFoundException resolveEx, 479 ObjectStreamClass superDesc) 480 throws InvalidClassException 481 { 482 this.cl = cl; 483 this.resolveEx = resolveEx; 484 this.superDesc = superDesc; 485 isProxy = true; 486 serializable = true; 487 suid = new Long (0); 488 fields = NO_FIELDS; 489 490 if (cl != null) { 491 localDesc = lookup(cl, true); 492 if (!localDesc.isProxy) { 493 throw new InvalidClassException ( 494 "cannot bind proxy descriptor to a non-proxy class"); 495 } 496 name = localDesc.name; 497 externalizable = localDesc.externalizable; 498 cons = localDesc.cons; 499 writeReplaceMethod = localDesc.writeReplaceMethod; 500 readResolveMethod = localDesc.readResolveMethod; 501 deserializeEx = localDesc.deserializeEx; 502 } 503 fieldRefl = getReflector(fields, localDesc); 504 } 505 506 509 void initNonProxy(ObjectStreamClass model, 510 Class cl, 511 ClassNotFoundException resolveEx, 512 ObjectStreamClass superDesc) 513 throws InvalidClassException 514 { 515 this.cl = cl; 516 this.resolveEx = resolveEx; 517 this.superDesc = superDesc; 518 name = model.name; 519 suid = new Long (model.getSerialVersionUID()); 520 isProxy = false; 521 isEnum = model.isEnum; 522 serializable = model.serializable; 523 externalizable = model.externalizable; 524 hasBlockExternalData = model.hasBlockExternalData; 525 hasWriteObjectData = model.hasWriteObjectData; 526 fields = model.fields; 527 primDataSize = model.primDataSize; 528 numObjFields = model.numObjFields; 529 530 if (cl != null) { 531 localDesc = lookup(cl, true); 532 if (localDesc.isProxy) { 533 throw new InvalidClassException ( 534 "cannot bind non-proxy descriptor to a proxy class"); 535 } 536 if (isEnum != localDesc.isEnum) { 537 throw new InvalidClassException (isEnum ? 538 "cannot bind enum descriptor to a non-enum class" : 539 "cannot bind non-enum descriptor to an enum class"); 540 } 541 542 if (serializable == localDesc.serializable && 543 !cl.isArray() && 544 suid.longValue() != localDesc.getSerialVersionUID()) 545 { 546 throw new InvalidClassException (localDesc.name, 547 "local class incompatible: " + 548 "stream classdesc serialVersionUID = " + suid + 549 ", local class serialVersionUID = " + 550 localDesc.getSerialVersionUID()); 551 } 552 553 if (!classNamesEqual(name, localDesc.name)) { 554 throw new InvalidClassException (localDesc.name, 555 "local class name incompatible with stream class " + 556 "name \"" + name + "\""); 557 } 558 559 if (!isEnum) { 560 if ((serializable == localDesc.serializable) && 561 (externalizable != localDesc.externalizable)) 562 { 563 throw new InvalidClassException (localDesc.name, 564 "Serializable incompatible with Externalizable"); 565 } 566 567 if ((serializable != localDesc.serializable) || 568 (externalizable != localDesc.externalizable) || 569 !(serializable || externalizable)) 570 { 571 deserializeEx = new InvalidClassException (localDesc.name, 572 "class invalid for deserialization"); 573 } 574 } 575 576 cons = localDesc.cons; 577 writeObjectMethod = localDesc.writeObjectMethod; 578 readObjectMethod = localDesc.readObjectMethod; 579 readObjectNoDataMethod = localDesc.readObjectNoDataMethod; 580 writeReplaceMethod = localDesc.writeReplaceMethod; 581 readResolveMethod = localDesc.readResolveMethod; 582 if (deserializeEx == null) { 583 deserializeEx = localDesc.deserializeEx; 584 } 585 } 586 fieldRefl = getReflector(fields, localDesc); 587 fields = fieldRefl.getFields(); 589 } 590 591 597 void readNonProxy(ObjectInputStream in) 598 throws IOException , ClassNotFoundException 599 { 600 name = in.readUTF(); 601 suid = new Long (in.readLong()); 602 isProxy = false; 603 604 byte flags = in.readByte(); 605 hasWriteObjectData = 606 ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); 607 hasBlockExternalData = 608 ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); 609 externalizable = 610 ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); 611 boolean sflag = 612 ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); 613 if (externalizable && sflag) { 614 throw new InvalidClassException ( 615 name, "serializable and externalizable flags conflict"); 616 } 617 serializable = externalizable || sflag; 618 isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); 619 if (isEnum && suid.longValue() != 0L) { 620 throw new InvalidClassException (name, 621 "enum descriptor has non-zero serialVersionUID: " + suid); 622 } 623 624 int numFields = in.readShort(); 625 if (isEnum && numFields != 0) { 626 throw new InvalidClassException (name, 627 "enum descriptor has non-zero field count: " + numFields); 628 } 629 fields = (numFields > 0) ? 630 new ObjectStreamField [numFields] : NO_FIELDS; 631 for (int i = 0; i < numFields; i++) { 632 char tcode = (char) in.readByte(); 633 String fname = in.readUTF(); 634 String signature = ((tcode == 'L') || (tcode == '[')) ? 635 in.readTypeString() : new String (new char[] { tcode }); 636 try { 637 fields[i] = new ObjectStreamField (fname, signature, false); 638 } catch (RuntimeException e) { 639 throw (IOException ) new InvalidClassException (name, 640 "invalid descriptor for field " + fname).initCause(e); 641 } 642 } 643 computeFieldOffsets(); 644 } 645 646 649 void writeNonProxy(ObjectOutputStream out) throws IOException { 650 out.writeUTF(name); 651 out.writeLong(getSerialVersionUID()); 652 653 byte flags = 0; 654 if (externalizable) { 655 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; 656 int protocol = out.getProtocolVersion(); 657 if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { 658 flags |= ObjectStreamConstants.SC_BLOCK_DATA; 659 } 660 } else if (serializable) { 661 flags |= ObjectStreamConstants.SC_SERIALIZABLE; 662 } 663 if (hasWriteObjectData) { 664 flags |= ObjectStreamConstants.SC_WRITE_METHOD; 665 } 666 if (isEnum) { 667 flags |= ObjectStreamConstants.SC_ENUM; 668 } 669 out.writeByte(flags); 670 671 out.writeShort(fields.length); 672 for (int i = 0; i < fields.length; i++) { 673 ObjectStreamField f = fields[i]; 674 out.writeByte(f.getTypeCode()); 675 out.writeUTF(f.getName()); 676 if (!f.isPrimitive()) { 677 out.writeTypeString(f.getTypeString()); 678 } 679 } 680 } 681 682 686 ClassNotFoundException getResolveException() { 687 return resolveEx; 688 } 689 690 695 void checkDeserialize() throws InvalidClassException { 696 if (deserializeEx != null) { 697 throw deserializeEx; 698 } 699 } 700 701 706 void checkSerialize() throws InvalidClassException { 707 if (serializeEx != null) { 708 throw serializeEx; 709 } 710 } 711 712 719 void checkDefaultSerialize() throws InvalidClassException { 720 if (defaultSerializeEx != null) { 721 throw defaultSerializeEx; 722 } 723 } 724 725 730 ObjectStreamClass getSuperDesc() { 731 return superDesc; 732 } 733 734 740 ObjectStreamClass getLocalDesc() { 741 return localDesc; 742 } 743 744 750 ObjectStreamField [] getFields(boolean copy) { 751 return copy ? (ObjectStreamField []) fields.clone() : fields; 752 } 753 754 760 ObjectStreamField getField(String name, Class type) { 761 for (int i = 0; i < fields.length; i++) { 762 ObjectStreamField f = fields[i]; 763 if (f.getName().equals(name)) { 764 if (type == null || 765 (type == Object .class && !f.isPrimitive())) 766 { 767 return f; 768 } 769 Class ftype = f.getType(); 770 if (ftype != null && type.isAssignableFrom(ftype)) { 771 return f; 772 } 773 } 774 } 775 return null; 776 } 777 778 782 boolean isProxy() { 783 return isProxy; 784 } 785 786 790 boolean isEnum() { 791 return isEnum; 792 } 793 794 798 boolean isExternalizable() { 799 return externalizable; 800 } 801 802 806 boolean isSerializable() { 807 return serializable; 808 } 809 810 814 boolean hasBlockExternalData() { 815 return hasBlockExternalData; 816 } 817 818 823 boolean hasWriteObjectData() { 824 return hasWriteObjectData; 825 } 826 827 834 boolean isInstantiable() { 835 return (cons != null); 836 } 837 838 843 boolean hasWriteObjectMethod() { 844 return (writeObjectMethod != null); 845 } 846 847 852 boolean hasReadObjectMethod() { 853 return (readObjectMethod != null); 854 } 855 856 861 boolean hasReadObjectNoDataMethod() { 862 return (readObjectNoDataMethod != null); 863 } 864 865 869 boolean hasWriteReplaceMethod() { 870 return (writeReplaceMethod != null); 871 } 872 873 877 boolean hasReadResolveMethod() { 878 return (readResolveMethod != null); 879 } 880 881 890 Object newInstance() 891 throws InstantiationException , InvocationTargetException , 892 UnsupportedOperationException 893 { 894 if (cons != null) { 895 try { 896 return cons.newInstance(null); 897 } catch (IllegalAccessException ex) { 898 throw new InternalError (); 900 } 901 } else { 902 throw new UnsupportedOperationException (); 903 } 904 } 905 906 912 void invokeWriteObject(Object obj, ObjectOutputStream out) 913 throws IOException , UnsupportedOperationException 914 { 915 if (writeObjectMethod != null) { 916 try { 917 writeObjectMethod.invoke(obj, new Object []{ out }); 918 } catch (InvocationTargetException ex) { 919 Throwable th = ex.getTargetException(); 920 if (th instanceof IOException ) { 921 throw (IOException ) th; 922 } else { 923 throwMiscException(th); 924 } 925 } catch (IllegalAccessException ex) { 926 throw new InternalError (); 928 } 929 } else { 930 throw new UnsupportedOperationException (); 931 } 932 } 933 934 940 void invokeReadObject(Object obj, ObjectInputStream in) 941 throws ClassNotFoundException , IOException , 942 UnsupportedOperationException 943 { 944 if (readObjectMethod != null) { 945 try { 946 readObjectMethod.invoke(obj, new Object []{ in }); 947 } catch (InvocationTargetException ex) { 948 Throwable th = ex.getTargetException(); 949 if (th instanceof ClassNotFoundException ) { 950 throw (ClassNotFoundException ) th; 951 } else if (th instanceof IOException ) { 952 throw (IOException ) th; 953 } else { 954 throwMiscException(th); 955 } 956 } catch (IllegalAccessException ex) { 957 throw new InternalError (); 959 } 960 } else { 961 throw new UnsupportedOperationException (); 962 } 963 } 964 965 971 void invokeReadObjectNoData(Object obj) 972 throws IOException , UnsupportedOperationException 973 { 974 if (readObjectNoDataMethod != null) { 975 try { 976 readObjectNoDataMethod.invoke(obj, null); 977 } catch (InvocationTargetException ex) { 978 Throwable th = ex.getTargetException(); 979 if (th instanceof ObjectStreamException ) { 980 throw (ObjectStreamException ) th; 981 } else { 982 throwMiscException(th); 983 } 984 } catch (IllegalAccessException ex) { 985 throw new InternalError (); 987 } 988 } else { 989 throw new UnsupportedOperationException (); 990 } 991 } 992 993 999 Object invokeWriteReplace(Object obj) 1000 throws IOException , UnsupportedOperationException 1001 { 1002 if (writeReplaceMethod != null) { 1003 try { 1004 return writeReplaceMethod.invoke(obj, null); 1005 } catch (InvocationTargetException ex) { 1006 Throwable th = ex.getTargetException(); 1007 if (th instanceof ObjectStreamException ) { 1008 throw (ObjectStreamException ) th; 1009 } else { 1010 throwMiscException(th); 1011 throw new InternalError (); } 1013 } catch (IllegalAccessException ex) { 1014 throw new InternalError (); 1016 } 1017 } else { 1018 throw new UnsupportedOperationException (); 1019 } 1020 } 1021 1022 1028 Object invokeReadResolve(Object obj) 1029 throws IOException , UnsupportedOperationException 1030 { 1031 if (readResolveMethod != null) { 1032 try { 1033 return readResolveMethod.invoke(obj, null); 1034 } catch (InvocationTargetException ex) { 1035 Throwable th = ex.getTargetException(); 1036 if (th instanceof ObjectStreamException ) { 1037 throw (ObjectStreamException ) th; 1038 } else { 1039 throwMiscException(th); 1040 throw new InternalError (); } 1042 } catch (IllegalAccessException ex) { 1043 throw new InternalError (); 1045 } 1046 } else { 1047 throw new UnsupportedOperationException (); 1048 } 1049 } 1050 1051 1057 static class ClassDataSlot { 1058 1059 1060 final ObjectStreamClass desc; 1061 1062 final boolean hasData; 1063 1064 ClassDataSlot(ObjectStreamClass desc, boolean hasData) { 1065 this.desc = desc; 1066 this.hasData = hasData; 1067 } 1068 } 1069 1070 1077 ClassDataSlot[] getClassDataLayout() throws InvalidClassException { 1078 if (dataLayout == null) { 1080 dataLayout = getClassDataLayout0(); 1081 } 1082 return dataLayout; 1083 } 1084 1085 private ClassDataSlot[] getClassDataLayout0() 1086 throws InvalidClassException 1087 { 1088 ArrayList slots = new ArrayList (); 1089 Class start = cl, end = cl; 1090 1091 while (end != null && Serializable .class.isAssignableFrom(end)) { 1093 end = end.getSuperclass(); 1094 } 1095 1096 for (ObjectStreamClass d = this; d != null; d = d.superDesc) { 1097 1098 String searchName = (d.cl != null) ? d.cl.getName() : d.name; 1100 Class match = null; 1101 for (Class c = start; c != end; c = c.getSuperclass()) { 1102 if (searchName.equals(c.getName())) { 1103 match = c; 1104 break; 1105 } 1106 } 1107 1108 if (match != null) { 1110 for (Class c = start; c != match; c = c.getSuperclass()) { 1111 slots.add(new ClassDataSlot( 1112 ObjectStreamClass.lookup(c, true), false)); 1113 } 1114 start = match.getSuperclass(); 1115 } 1116 1117 slots.add(new ClassDataSlot(d.getVariantFor(match), true)); 1119 } 1120 1121 for (Class c = start; c != end; c = c.getSuperclass()) { 1123 slots.add(new ClassDataSlot( 1124 ObjectStreamClass.lookup(c, true), false)); 1125 } 1126 1127 Collections.reverse(slots); 1129 return (ClassDataSlot[]) 1130 slots.toArray(new ClassDataSlot[slots.size()]); 1131 } 1132 1133 1137 int getPrimDataSize() { 1138 return primDataSize; 1139 } 1140 1141 1145 int getNumObjFields() { 1146 return numObjFields; 1147 } 1148 1149 1155 void getPrimFieldValues(Object obj, byte[] buf) { 1156 fieldRefl.getPrimFieldValues(obj, buf); 1157 } 1158 1159 1165 void setPrimFieldValues(Object obj, byte[] buf) { 1166 fieldRefl.setPrimFieldValues(obj, buf); 1167 } 1168 1169 1174 void getObjFieldValues(Object obj, Object [] vals) { 1175 fieldRefl.getObjFieldValues(obj, vals); 1176 } 1177 1178 1183 void setObjFieldValues(Object obj, Object [] vals) { 1184 fieldRefl.setObjFieldValues(obj, vals); 1185 } 1186 1187 1192 private void computeFieldOffsets() throws InvalidClassException { 1193 primDataSize = 0; 1194 numObjFields = 0; 1195 int firstObjIndex = -1; 1196 1197 for (int i = 0; i < fields.length; i++) { 1198 ObjectStreamField f = fields[i]; 1199 switch (f.getTypeCode()) { 1200 case 'Z': 1201 case 'B': 1202 f.setOffset(primDataSize++); 1203 break; 1204 1205 case 'C': 1206 case 'S': 1207 f.setOffset(primDataSize); 1208 primDataSize += 2; 1209 break; 1210 1211 case 'I': 1212 case 'F': 1213 f.setOffset(primDataSize); 1214 primDataSize += 4; 1215 break; 1216 1217 case 'J': 1218 case 'D': 1219 f.setOffset(primDataSize); 1220 primDataSize += 8; 1221 break; 1222 1223 case '[': 1224 case 'L': 1225 f.setOffset(numObjFields++); 1226 if (firstObjIndex == -1) { 1227 firstObjIndex = i; 1228 } 1229 break; 1230 1231 default: 1232 throw new InternalError (); 1233 } 1234 } 1235 if (firstObjIndex != -1 && 1236 firstObjIndex + numObjFields != fields.length) 1237 { 1238 throw new InvalidClassException (name, "illegal field order"); 1239 } 1240 } 1241 1242 1247 private ObjectStreamClass getVariantFor(Class cl) 1248 throws InvalidClassException 1249 { 1250 if (this.cl == cl) { 1251 return this; 1252 } 1253 ObjectStreamClass desc = new ObjectStreamClass (); 1254 if (isProxy) { 1255 desc.initProxy(cl, null, superDesc); 1256 } else { 1257 desc.initNonProxy(this, cl, null, superDesc); 1258 } 1259 return desc; 1260 } 1261 1262 1267 private static Constructor getExternalizableConstructor(Class cl) { 1268 try { 1269 Constructor cons = cl.getDeclaredConstructor(new Class [0]); 1270 cons.setAccessible(true); 1271 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? 1272 cons : null; 1273 } catch (NoSuchMethodException ex) { 1274 return null; 1275 } 1276 } 1277 1278 1283 private static Constructor getSerializableConstructor(Class cl) { 1284 Class initCl = cl; 1285 while (Serializable .class.isAssignableFrom(initCl)) { 1286 if ((initCl = initCl.getSuperclass()) == null) { 1287 return null; 1288 } 1289 } 1290 try { 1291 Constructor cons = initCl.getDeclaredConstructor(new Class [0]); 1292 int mods = cons.getModifiers(); 1293 if ((mods & Modifier.PRIVATE) != 0 || 1294 ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 && 1295 !packageEquals(cl, initCl))) 1296 { 1297 return null; 1298 } 1299 cons = reflFactory.newConstructorForSerialization(cl, cons); 1300 cons.setAccessible(true); 1301 return cons; 1302 } catch (NoSuchMethodException ex) { 1303 return null; 1304 } 1305 } 1306 1307 1313 private static Method getInheritableMethod(Class cl, String name, 1314 Class [] argTypes, 1315 Class returnType) 1316 { 1317 Method meth = null; 1318 Class defCl = cl; 1319 while (defCl != null) { 1320 try { 1321 meth = defCl.getDeclaredMethod(name, argTypes); 1322 break; 1323 } catch (NoSuchMethodException ex) { 1324 defCl = defCl.getSuperclass(); 1325 } 1326 } 1327 1328 if ((meth == null) || (meth.getReturnType() != returnType)) { 1329 return null; 1330 } 1331 meth.setAccessible(true); 1332 int mods = meth.getModifiers(); 1333 if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) { 1334 return null; 1335 } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) { 1336 return meth; 1337 } else if ((mods & Modifier.PRIVATE) != 0) { 1338 return (cl == defCl) ? meth : null; 1339 } else { 1340 return packageEquals(cl, defCl) ? meth : null; 1341 } 1342 } 1343 1344 1349 private static Method getPrivateMethod(Class cl, String name, 1350 Class [] argTypes, 1351 Class returnType) 1352 { 1353 try { 1354 Method meth = cl.getDeclaredMethod(name, argTypes); 1355 meth.setAccessible(true); 1356 int mods = meth.getModifiers(); 1357 return ((meth.getReturnType() == returnType) && 1358 ((mods & Modifier.STATIC) == 0) && 1359 ((mods & Modifier.PRIVATE) != 0)) ? meth : null; 1360 } catch (NoSuchMethodException ex) { 1361 return null; 1362 } 1363 } 1364 1365 1369 private static boolean packageEquals(Class cl1, Class cl2) { 1370 return (cl1.getClassLoader() == cl2.getClassLoader() && 1371 getPackageName(cl1).equals(getPackageName(cl2))); 1372 } 1373 1374 1377 private static String getPackageName(Class cl) { 1378 String s = cl.getName(); 1379 int i = s.lastIndexOf('['); 1380 if (i >= 0) { 1381 s = s.substring(i + 2); 1382 } 1383 i = s.lastIndexOf('.'); 1384 return (i >= 0) ? s.substring(0, i) : ""; 1385 } 1386 1387 1391 private static boolean classNamesEqual(String name1, String name2) { 1392 name1 = name1.substring(name1.lastIndexOf('.') + 1); 1393 name2 = name2.substring(name2.lastIndexOf('.') + 1); 1394 return name1.equals(name2); 1395 } 1396 1397 1400 static String getClassSignature(Class cl) { 1401 StringBuffer sbuf = new StringBuffer (); 1402 while (cl.isArray()) { 1403 sbuf.append('['); 1404 cl = cl.getComponentType(); 1405 } 1406 if (cl.isPrimitive()) { 1407 if (cl == Integer.TYPE) { 1408 sbuf.append('I'); 1409 } else if (cl == Byte.TYPE) { 1410 sbuf.append('B'); 1411 } else if (cl == Long.TYPE) { 1412 sbuf.append('J'); 1413 } else if (cl == Float.TYPE) { 1414 sbuf.append('F'); 1415 } else if (cl == Double.TYPE) { 1416 sbuf.append('D'); 1417 } else if (cl == Short.TYPE) { 1418 sbuf.append('S'); 1419 } else if (cl == Character.TYPE) { 1420 sbuf.append('C'); 1421 } else if (cl == Boolean.TYPE) { 1422 sbuf.append('Z'); 1423 } else if (cl == Void.TYPE) { 1424 sbuf.append('V'); 1425 } else { 1426 throw new InternalError (); 1427 } 1428 } else { 1429 sbuf.append('L' + cl.getName().replace('.', '/') + ';'); 1430 } 1431 return sbuf.toString(); 1432 } 1433 1434 1437 private static String getMethodSignature(Class [] paramTypes, 1438 Class retType) 1439 { 1440 StringBuffer sbuf = new StringBuffer (); 1441 sbuf.append('('); 1442 for (int i = 0; i < paramTypes.length; i++) { 1443 sbuf.append(getClassSignature(paramTypes[i])); 1444 } 1445 sbuf.append(')'); 1446 sbuf.append(getClassSignature(retType)); 1447 return sbuf.toString(); 1448 } 1449 1450 1455 private static void throwMiscException(Throwable th) throws IOException { 1456 if (th instanceof RuntimeException ) { 1457 throw (RuntimeException ) th; 1458 } else if (th instanceof Error ) { 1459 throw (Error ) th; 1460 } else { 1461 IOException ex = new IOException ("unexpected exception type"); 1462 ex.initCause(th); 1463 throw ex; 1464 } 1465 } 1466 1467 1474 private static ObjectStreamField [] getSerialFields(Class cl) 1475 throws InvalidClassException 1476 { 1477 ObjectStreamField [] fields; 1478 if (Serializable .class.isAssignableFrom(cl) && 1479 !Externalizable .class.isAssignableFrom(cl) && 1480 !Proxy.isProxyClass(cl) && 1481 !cl.isInterface()) 1482 { 1483 if ((fields = getDeclaredSerialFields(cl)) == null) { 1484 fields = getDefaultSerialFields(cl); 1485 } 1486 Arrays.sort(fields); 1487 } else { 1488 fields = NO_FIELDS; 1489 } 1490 return fields; 1491 } 1492 1493 1504 private static ObjectStreamField [] getDeclaredSerialFields(Class cl) 1505 throws InvalidClassException 1506 { 1507 ObjectStreamField [] serialPersistentFields = null; 1508 try { 1509 Field f = cl.getDeclaredField("serialPersistentFields"); 1510 int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; 1511 if ((f.getModifiers() & mask) == mask) { 1512 f.setAccessible(true); 1513 serialPersistentFields = (ObjectStreamField []) f.get(null); 1514 } 1515 } catch (Exception ex) { 1516 } 1517 if (serialPersistentFields == null) { 1518 return null; 1519 } else if (serialPersistentFields.length == 0) { 1520 return NO_FIELDS; 1521 } 1522 1523 ObjectStreamField [] boundFields = 1524 new ObjectStreamField [serialPersistentFields.length]; 1525 Set fieldNames = new HashSet (serialPersistentFields.length); 1526 1527 for (int i = 0; i < serialPersistentFields.length; i++) { 1528 ObjectStreamField spf = serialPersistentFields[i]; 1529 1530 String fname = spf.getName(); 1531 if (fieldNames.contains(fname)) { 1532 throw new InvalidClassException ( 1533 "multiple serializable fields named " + fname); 1534 } 1535 fieldNames.add(fname); 1536 1537 try { 1538 Field f = cl.getDeclaredField(fname); 1539 if ((f.getType() == spf.getType()) && 1540 ((f.getModifiers() & Modifier.STATIC) == 0)) 1541 { 1542 boundFields[i] = 1543 new ObjectStreamField (f, spf.isUnshared(), true); 1544 } 1545 } catch (NoSuchFieldException ex) { 1546 } 1547 if (boundFields[i] == null) { 1548 boundFields[i] = new ObjectStreamField ( 1549 fname, spf.getType(), spf.isUnshared()); 1550 } 1551 } 1552 return boundFields; 1553 } 1554 1555 1561 private static ObjectStreamField [] getDefaultSerialFields(Class cl) { 1562 Field [] clFields = cl.getDeclaredFields(); 1563 ArrayList list = new ArrayList (); 1564 int mask = Modifier.STATIC | Modifier.TRANSIENT; 1565 1566 for (int i = 0; i < clFields.length; i++) { 1567 if ((clFields[i].getModifiers() & mask) == 0) { 1568 list.add(new ObjectStreamField (clFields[i], false, true)); 1569 } 1570 } 1571 int size = list.size(); 1572 return (size == 0) ? NO_FIELDS : 1573 (ObjectStreamField []) list.toArray(new ObjectStreamField [size]); 1574 } 1575 1576 1580 private static Long getDeclaredSUID(Class cl) { 1581 try { 1582 Field f = cl.getDeclaredField("serialVersionUID"); 1583 int mask = Modifier.STATIC | Modifier.FINAL; 1584 if ((f.getModifiers() & mask) == mask) { 1585 f.setAccessible(true); 1586 return new Long (f.getLong(null)); 1587 } 1588 } catch (Exception ex) { 1589 } 1590 return null; 1591 } 1592 1593 1596 private static long computeDefaultSUID(Class cl) { 1597 if (!Serializable .class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) 1598 { 1599 return 0L; 1600 } 1601 1602 try { 1603 ByteArrayOutputStream bout = new ByteArrayOutputStream (); 1604 DataOutputStream dout = new DataOutputStream (bout); 1605 1606 dout.writeUTF(cl.getName()); 1607 1608 int classMods = cl.getModifiers() & 1609 (Modifier.PUBLIC | Modifier.FINAL | 1610 Modifier.INTERFACE | Modifier.ABSTRACT); 1611 1612 1616 Method [] methods = cl.getDeclaredMethods(); 1617 if ((classMods & Modifier.INTERFACE) != 0) { 1618 classMods = (methods.length > 0) ? 1619 (classMods | Modifier.ABSTRACT) : 1620 (classMods & ~Modifier.ABSTRACT); 1621 } 1622 dout.writeInt(classMods); 1623 1624 if (!cl.isArray()) { 1625 1630 Class [] interfaces = cl.getInterfaces(); 1631 String [] ifaceNames = new String [interfaces.length]; 1632 for (int i = 0; i < interfaces.length; i++) { 1633 ifaceNames[i] = interfaces[i].getName(); 1634 } 1635 Arrays.sort(ifaceNames); 1636 for (int i = 0; i < ifaceNames.length; i++) { 1637 dout.writeUTF(ifaceNames[i]); 1638 } 1639 } 1640 1641 Field [] fields = cl.getDeclaredFields(); 1642 MemberSignature[] fieldSigs = new MemberSignature[fields.length]; 1643 for (int i = 0; i < fields.length; i++) { 1644 fieldSigs[i] = new MemberSignature(fields[i]); 1645 } 1646 Arrays.sort(fieldSigs, new Comparator () { 1647 public int compare(Object o1, Object o2) { 1648 String name1 = ((MemberSignature) o1).name; 1649 String name2 = ((MemberSignature) o2).name; 1650 return name1.compareTo(name2); 1651 } 1652 }); 1653 for (int i = 0; i < fieldSigs.length; i++) { 1654 MemberSignature sig = fieldSigs[i]; 1655 int mods = sig.member.getModifiers() & 1656 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 1657 Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | 1658 Modifier.TRANSIENT); 1659 if (((mods & Modifier.PRIVATE) == 0) || 1660 ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) 1661 { 1662 dout.writeUTF(sig.name); 1663 dout.writeInt(mods); 1664 dout.writeUTF(sig.signature); 1665 } 1666 } 1667 1668 if (hasStaticInitializer(cl)) { 1669 dout.writeUTF("<clinit>"); 1670 dout.writeInt(Modifier.STATIC); 1671 dout.writeUTF("()V"); 1672 } 1673 1674 Constructor [] cons = cl.getDeclaredConstructors(); 1675 MemberSignature[] consSigs = new MemberSignature[cons.length]; 1676 for (int i = 0; i < cons.length; i++) { 1677 consSigs[i] = new MemberSignature(cons[i]); 1678 } 1679 Arrays.sort(consSigs, new Comparator () { 1680 public int compare(Object o1, Object o2) { 1681 String sig1 = ((MemberSignature) o1).signature; 1682 String sig2 = ((MemberSignature) o2).signature; 1683 return sig1.compareTo(sig2); 1684 } 1685 }); 1686 for (int i = 0; i < consSigs.length; i++) { 1687 MemberSignature sig = consSigs[i]; 1688 int mods = sig.member.getModifiers() & 1689 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 1690 Modifier.STATIC | Modifier.FINAL | 1691 Modifier.SYNCHRONIZED | Modifier.NATIVE | 1692 Modifier.ABSTRACT | Modifier.STRICT); 1693 if ((mods & Modifier.PRIVATE) == 0) { 1694 dout.writeUTF("<init>"); 1695 dout.writeInt(mods); 1696 dout.writeUTF(sig.signature.replace('/', '.')); 1697 } 1698 } 1699 1700 MemberSignature[] methSigs = new MemberSignature[methods.length]; 1701 for (int i = 0; i < methods.length; i++) { 1702 methSigs[i] = new MemberSignature(methods[i]); 1703 } 1704 Arrays.sort(methSigs, new Comparator () { 1705 public int compare(Object o1, Object o2) { 1706 MemberSignature ms1 = (MemberSignature) o1; 1707 MemberSignature ms2 = (MemberSignature) o2; 1708 int comp = ms1.name.compareTo(ms2.name); 1709 if (comp == 0) { 1710 comp = ms1.signature.compareTo(ms2.signature); 1711 } 1712 return comp; 1713 } 1714 }); 1715 for (int i = 0; i < methSigs.length; i++) { 1716 MemberSignature sig = methSigs[i]; 1717 int mods = sig.member.getModifiers() & 1718 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 1719 Modifier.STATIC | Modifier.FINAL | 1720 Modifier.SYNCHRONIZED | Modifier.NATIVE | 1721 Modifier.ABSTRACT | Modifier.STRICT); 1722 if ((mods & Modifier.PRIVATE) == 0) { 1723 dout.writeUTF(sig.name); 1724 dout.writeInt(mods); 1725 dout.writeUTF(sig.signature.replace('/', '.')); 1726 } 1727 } 1728 1729 dout.flush(); 1730 1731 MessageDigest md = MessageDigest.getInstance("SHA"); 1732 byte[] hashBytes = md.digest(bout.toByteArray()); 1733 long hash = 0; 1734 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { 1735 hash = (hash << 8) | (hashBytes[i] & 0xFF); 1736 } 1737 return hash; 1738 } catch (IOException ex) { 1739 throw new InternalError (); 1740 } catch (NoSuchAlgorithmException ex) { 1741 throw new SecurityException (ex.getMessage()); 1742 } 1743 } 1744 1745 1749 private native static boolean hasStaticInitializer(Class cl); 1750 1751 1755 private static class MemberSignature { 1756 1757 public final Member member; 1758 public final String name; 1759 public final String signature; 1760 1761 public MemberSignature(Field field) { 1762 member = field; 1763 name = field.getName(); 1764 signature = getClassSignature(field.getType()); 1765 } 1766 1767 public MemberSignature(Constructor cons) { 1768 member = cons; 1769 name = cons.getName(); 1770 signature = getMethodSignature( 1771 cons.getParameterTypes(), Void.TYPE); 1772 } 1773 1774 public MemberSignature(Method meth) { 1775 member = meth; 1776 name = meth.getName(); 1777 signature = getMethodSignature( 1778 meth.getParameterTypes(), meth.getReturnType()); 1779 } 1780 } 1781 1782 1785 private static class FieldReflector { 1787 1788 1789 private static final Unsafe unsafe = Unsafe.getUnsafe(); 1790 1791 1792 private final ObjectStreamField [] fields; 1793 1794 private final int numPrimFields; 1795 1796 private final long[] keys; 1797 1798 private final int[] offsets; 1799 1800 private final char[] typeCodes; 1801 1802 private final Class [] types; 1803 1804 1811 FieldReflector(ObjectStreamField [] fields) { 1812 this.fields = fields; 1813 int nfields = fields.length; 1814 keys = new long[nfields]; 1815 offsets = new int[nfields]; 1816 typeCodes = new char[nfields]; 1817 ArrayList typeList = new ArrayList (); 1818 1819 for (int i = 0; i < nfields; i++) { 1820 ObjectStreamField f = fields[i]; 1821 Field rf = f.getField(); 1822 keys[i] = (rf != null) ? 1823 unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET; 1824 offsets[i] = f.getOffset(); 1825 typeCodes[i] = f.getTypeCode(); 1826 if (!f.isPrimitive()) { 1827 typeList.add((rf != null) ? rf.getType() : null); 1828 } 1829 } 1830 1831 types = (Class []) typeList.toArray(new Class [typeList.size()]); 1832 numPrimFields = nfields - types.length; 1833 } 1834 1835 1841 ObjectStreamField [] getFields() { 1842 return fields; 1843 } 1844 1845 1850 void getPrimFieldValues(Object obj, byte[] buf) { 1851 if (obj == null) { 1852 throw new NullPointerException (); 1853 } 1854 1858 for (int i = 0; i < numPrimFields; i++) { 1859 long key = keys[i]; 1860 int off = offsets[i]; 1861 switch (typeCodes[i]) { 1862 case 'Z': 1863 Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key)); 1864 break; 1865 1866 case 'B': 1867 buf[off] = unsafe.getByte(obj, key); 1868 break; 1869 1870 case 'C': 1871 Bits.putChar(buf, off, unsafe.getChar(obj, key)); 1872 break; 1873 1874 case 'S': 1875 Bits.putShort(buf, off, unsafe.getShort(obj, key)); 1876 break; 1877 1878 case 'I': 1879 Bits.putInt(buf, off, unsafe.getInt(obj, key)); 1880 break; 1881 1882 case 'F': 1883 Bits.putFloat(buf, off, unsafe.getFloat(obj, key)); 1884 break; 1885 1886 case 'J': 1887 Bits.putLong(buf, off, unsafe.getLong(obj, key)); 1888 break; 1889 1890 case 'D': 1891 Bits.putDouble(buf, off, unsafe.getDouble(obj, key)); 1892 break; 1893 1894 default: 1895 throw new InternalError (); 1896 } 1897 } 1898 } 1899 1900 1905 void setPrimFieldValues(Object obj, byte[] buf) { 1906 if (obj == null) { 1907 throw new NullPointerException (); 1908 } 1909 for (int i = 0; i < numPrimFields; i++) { 1910 long key = keys[i]; 1911 if (key == Unsafe.INVALID_FIELD_OFFSET) { 1912 continue; } 1914 int off = offsets[i]; 1915 switch (typeCodes[i]) { 1916 case 'Z': 1917 unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off)); 1918 break; 1919 1920 case 'B': 1921 unsafe.putByte(obj, key, buf[off]); 1922 break; 1923 1924 case 'C': 1925 unsafe.putChar(obj, key, Bits.getChar(buf, off)); 1926 break; 1927 1928 case 'S': 1929 unsafe.putShort(obj, key, Bits.getShort(buf, off)); 1930 break; 1931 1932 case 'I': 1933 unsafe.putInt(obj, key, Bits.getInt(buf, off)); 1934 break; 1935 1936 case 'F': 1937 unsafe.putFloat(obj, key, Bits.getFloat(buf, off)); 1938 break; 1939 1940 case 'J': 1941 unsafe.putLong(obj, key, Bits.getLong(buf, off)); 1942 break; 1943 1944 case 'D': 1945 unsafe.putDouble(obj, key, Bits.getDouble(buf, off)); 1946 break; 1947 1948 default: 1949 throw new InternalError (); 1950 } 1951 } 1952 } 1953 1954 1959 void getObjFieldValues(Object obj, Object [] vals) { 1960 if (obj == null) { 1961 throw new NullPointerException (); 1962 } 1963 1967 for (int i = numPrimFields; i < fields.length; i++) { 1968 switch (typeCodes[i]) { 1969 case 'L': 1970 case '[': 1971 vals[offsets[i]] = unsafe.getObject(obj, keys[i]); 1972 break; 1973 1974 default: 1975 throw new InternalError (); 1976 } 1977 } 1978 } 1979 1980 1987 void setObjFieldValues(Object obj, Object [] vals) { 1988 if (obj == null) { 1989 throw new NullPointerException (); 1990 } 1991 for (int i = numPrimFields; i < fields.length; i++) { 1992 long key = keys[i]; 1993 if (key == Unsafe.INVALID_FIELD_OFFSET) { 1994 continue; } 1996 switch (typeCodes[i]) { 1997 case 'L': 1998 case '[': 1999 Object val = vals[offsets[i]]; 2000 if (val != null && 2001 !types[i - numPrimFields].isInstance(val)) 2002 { 2003 Field f = fields[i].getField(); 2004 throw new ClassCastException ( 2005 "cannot assign instance of " + 2006 val.getClass().getName() + " to field " + 2007 f.getDeclaringClass().getName() + "." + 2008 f.getName() + " of type " + 2009 f.getType().getName() + " in instance of " + 2010 obj.getClass().getName()); 2011 } 2012 unsafe.putObject(obj, key, val); 2013 break; 2014 2015 default: 2016 throw new InternalError (); 2017 } 2018 } 2019 } 2020 } 2021 2022 2031 private static FieldReflector getReflector(ObjectStreamField [] fields, 2032 ObjectStreamClass localDesc) 2033 throws InvalidClassException 2034 { 2035 Class cl = (localDesc != null && fields.length > 0) ? 2037 localDesc.cl : null; 2038 processQueue(Caches.reflectorsQueue, Caches.reflectors); 2039 FieldReflectorKey key = new FieldReflectorKey(cl, fields, 2040 Caches.reflectorsQueue); 2041 Reference <?> ref = Caches.reflectors.get(key); 2042 Object entry = null; 2043 if (ref != null) { 2044 entry = ref.get(); 2045 } 2046 EntryFuture future = null; 2047 if (entry == null) { 2048 EntryFuture newEntry = new EntryFuture(); 2049 Reference <?> newRef = new SoftReference <EntryFuture>(newEntry); 2050 do { 2051 if (ref != null) { 2052 Caches.reflectors.remove(key, ref); 2053 } 2054 ref = Caches.reflectors.putIfAbsent(key, newRef); 2055 if (ref != null) { 2056 entry = ref.get(); 2057 } 2058 } while (ref != null && entry == null); 2059 if (entry == null) { 2060 future = newEntry; 2061 } 2062 } 2063 2064 if (entry instanceof FieldReflector) { return (FieldReflector) entry; 2066 } else if (entry instanceof EntryFuture) { 2067 entry = ((EntryFuture) entry).get(); 2068 } else if (entry == null) { 2069 try { 2070 entry = new FieldReflector(matchFields(fields, localDesc)); 2071 } catch (Throwable th) { 2072 entry = th; 2073 } 2074 future.set(entry); 2075 Caches.reflectors.put(key, new SoftReference <Object >(entry)); 2076 } 2077 2078 if (entry instanceof FieldReflector) { 2079 return (FieldReflector) entry; 2080 } else if (entry instanceof InvalidClassException ) { 2081 throw (InvalidClassException ) entry; 2082 } else if (entry instanceof RuntimeException ) { 2083 throw (RuntimeException ) entry; 2084 } else if (entry instanceof Error ) { 2085 throw (Error ) entry; 2086 } else { 2087 throw new InternalError ("unexpected entry: " + entry); 2088 } 2089 } 2090 2091 2095 private static class FieldReflectorKey extends WeakReference <Class <?>> { 2096 2097 private final String sigs; 2098 private final int hash; 2099 private final boolean nullClass; 2100 2101 FieldReflectorKey(Class <?> cl, ObjectStreamField [] fields, 2102 ReferenceQueue <Class <?>> queue) 2103 { 2104 super(cl, queue); 2105 nullClass = (cl == null); 2106 StringBuilder sbuf = new StringBuilder (); 2107 for (int i = 0; i < fields.length; i++) { 2108 ObjectStreamField f = fields[i]; 2109 sbuf.append(f.getName()).append(f.getSignature()); 2110 } 2111 sigs = sbuf.toString(); 2112 hash = System.identityHashCode(cl) + sigs.hashCode(); 2113 } 2114 2115 public int hashCode() { 2116 return hash; 2117 } 2118 2119 public boolean equals(Object obj) { 2120 if (obj == this) { 2121 return true; 2122 } 2123 2124 if (obj instanceof FieldReflectorKey) { 2125 FieldReflectorKey other = (FieldReflectorKey) obj; 2126 Class <?> referent; 2127 return (nullClass ? other.nullClass 2128 : ((referent = get()) != null) && 2129 (referent == other.get())) && 2130 sigs.equals(other.sigs); 2131 } else { 2132 return false; 2133 } 2134 } 2135 } 2136 2137 2148 private static ObjectStreamField [] matchFields(ObjectStreamField [] fields, 2149 ObjectStreamClass localDesc) 2150 throws InvalidClassException 2151 { 2152 ObjectStreamField [] localFields = (localDesc != null) ? 2153 localDesc.fields : NO_FIELDS; 2154 2155 2165 2166 ObjectStreamField [] matches = new ObjectStreamField [fields.length]; 2167 for (int i = 0; i < fields.length; i++) { 2168 ObjectStreamField f = fields[i], m = null; 2169 for (int j = 0; j < localFields.length; j++) { 2170 ObjectStreamField lf = localFields[j]; 2171 if (f.getName().equals(lf.getName())) { 2172 if ((f.isPrimitive() || lf.isPrimitive()) && 2173 f.getTypeCode() != lf.getTypeCode()) 2174 { 2175 throw new InvalidClassException (localDesc.name, 2176 "incompatible types for field " + f.getName()); 2177 } 2178 if (lf.getField() != null) { 2179 m = new ObjectStreamField ( 2180 lf.getField(), lf.isUnshared(), false); 2181 } else { 2182 m = new ObjectStreamField ( 2183 lf.getName(), lf.getSignature(), lf.isUnshared()); 2184 } 2185 } 2186 } 2187 if (m == null) { 2188 m = new ObjectStreamField ( 2189 f.getName(), f.getSignature(), false); 2190 } 2191 m.setOffset(f.getOffset()); 2192 matches[i] = m; 2193 } 2194 return matches; 2195 } 2196 2197 2201 static void processQueue(ReferenceQueue <Class <?>> queue, 2202 ConcurrentMap <? extends 2203 WeakReference <Class <?>>, ?> map) 2204 { 2205 Reference <? extends Class <?>> ref; 2206 while((ref = queue.poll()) != null) { 2207 map.remove(ref); 2208 } 2209 } 2210 2211 2215 static class WeakClassKey extends WeakReference <Class <?>> { 2216 2220 private final int hash; 2221 2222 2226 WeakClassKey(Class <?> cl, ReferenceQueue <Class <?>> refQueue) { 2227 super(cl, refQueue); 2228 hash = System.identityHashCode(cl); 2229 } 2230 2231 2234 public int hashCode() { 2235 return hash; 2236 } 2237 2238 2244 public boolean equals(Object obj) { 2245 if (obj == this) { 2246 return true; 2247 } 2248 2249 if (obj instanceof WeakClassKey) { 2250 Object referent = get(); 2251 return (referent != null) && 2252 (referent == ((WeakClassKey) obj).get()); 2253 } else { 2254 return false; 2255 } 2256 } 2257 } 2258} 2259 | Popular Tags |