| 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 hasWriteOb
|