1 /* 2 * Copyright (c) 1996, 2013, 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 package java.io; 27 28 import java.lang.ref.Reference; 29 import java.lang.ref.ReferenceQueue; 30 import java.lang.ref.SoftReference; 31 import java.lang.ref.WeakReference; 32 import java.lang.reflect.Constructor; 33 import java.lang.reflect.Field; 34 import java.lang.reflect.InvocationTargetException; 35 import java.lang.reflect.Member; 36 import java.lang.reflect.Method; 37 import java.lang.reflect.Modifier; 38 import java.lang.reflect.Proxy; 39 import java.security.AccessController; 40 import java.security.MessageDigest; 41 import java.security.NoSuchAlgorithmException; 42 import java.security.PrivilegedAction; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.Collections; 46 import java.util.Comparator; 47 import java.util.HashSet; 48 import java.util.Set; 49 import java.util.concurrent.ConcurrentHashMap; 50 import java.util.concurrent.ConcurrentMap; 51 import sun.misc.Unsafe; 52 import sun.reflect.CallerSensitive; 53 import sun.reflect.Reflection; 54 import sun.reflect.misc.ReflectUtil; 55 import dalvik.system.VMRuntime; 56 import dalvik.system.VMStack; 57 /** 58 * Serialization's descriptor for classes. It contains the name and 59 * serialVersionUID of the class. The ObjectStreamClass for a specific class 60 * loaded in this Java VM can be found/created using the lookup method. 61 * 62 * <p>The algorithm to compute the SerialVersionUID is described in 63 * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/platform/serialization/spec/class.html#4100">Object 64 * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>. 65 * 66 * @author Mike Warres 67 * @author Roger Riggs 68 * @see ObjectStreamField 69 * @see <a href="{@docRoot}openjdk-redirect.html?v=8&path=/platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a> 70 * @since JDK1.1 71 */ 72 public class ObjectStreamClass implements Serializable { 73 74 /** serialPersistentFields value indicating no serializable fields */ 75 public static final ObjectStreamField[] NO_FIELDS = 76 new ObjectStreamField[0]; 77 78 private static final long serialVersionUID = -6120832682080437368L; 79 private static final ObjectStreamField[] serialPersistentFields = 80 NO_FIELDS; 81 82 /** reflection factory for obtaining serialization constructors */ 83 84 private static class Caches { 85 /** cache mapping local classes -> descriptors */ 86 static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs = 87 new ConcurrentHashMap<>(); 88 89 /** cache mapping field group/local desc pairs -> field reflectors */ 90 static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors = 91 new ConcurrentHashMap<>(); 92 93 /** queue for WeakReferences to local classes */ 94 private static final ReferenceQueue<Class<?>> localDescsQueue = 95 new ReferenceQueue<>(); 96 /** queue for WeakReferences to field reflectors keys */ 97 private static final ReferenceQueue<Class<?>> reflectorsQueue = 98 new ReferenceQueue<>(); 99 } 100 101 /** class associated with this descriptor (if any) */ 102 private Class<?> cl; 103 /** name of class represented by this descriptor */ 104 private String name; 105 /** serialVersionUID of represented class (null if not computed yet) */ 106 private volatile Long suid; 107 108 /** true if represents dynamic proxy class */ 109 private boolean isProxy; 110 /** true if represents enum type */ 111 private boolean isEnum; 112 /** true if represented class implements Serializable */ 113 private boolean serializable; 114 /** true if represented class implements Externalizable */ 115 private boolean externalizable; 116 /** true if desc has data written by class-defined writeObject method */ 117 private boolean hasWriteObjectData; 118 /** 119 * true if desc has externalizable data written in block data format; this 120 * must be true by default to accommodate ObjectInputStream subclasses which 121 * override readClassDescriptor() to return class descriptors obtained from 122 * ObjectStreamClass.lookup() (see 4461737) 123 */ 124 private boolean hasBlockExternalData = true; 125 126 /** 127 * Contains information about InvalidClassException instances to be thrown 128 * when attempting operations on an invalid class. Note that instances of 129 * this class are immutable and are potentially shared among 130 * ObjectStreamClass instances. 131 */ 132 private static class ExceptionInfo { 133 private final String className; 134 private final String message; 135 136 ExceptionInfo(String cn, String msg) { 137 className = cn; 138 message = msg; 139 } 140 141 /** 142 * Returns (does not throw) an InvalidClassException instance created 143 * from the information in this object, suitable for being thrown by 144 * the caller. 145 */ 146 InvalidClassException newInvalidClassException() { 147 return new InvalidClassException(className, message); 148 } 149 } 150 151 /** exception (if any) thrown while attempting to resolve class */ 152 private ClassNotFoundException resolveEx; 153 /** exception (if any) to throw if non-enum deserialization attempted */ 154 private ExceptionInfo deserializeEx; 155 /** exception (if any) to throw if non-enum serialization attempted */ 156 private ExceptionInfo serializeEx; 157 /** exception (if any) to throw if default serialization attempted */ 158 private ExceptionInfo defaultSerializeEx; 159 160 /** serializable fields */ 161 private ObjectStreamField[] fields; 162 /** aggregate marshalled size of primitive fields */ 163 private int primDataSize; 164 /** number of non-primitive fields */ 165 private int numObjFields; 166 /** reflector for setting/getting serializable field values */ 167 private FieldReflector fieldRefl; 168 /** data layout of serialized objects described by this class desc */ 169 private volatile ClassDataSlot[] dataLayout; 170 171 /** serialization-appropriate constructor, or null if none */ 172 private Constructor<?> cons; 173 /** class-defined writeObject method, or null if none */ 174 private Method writeObjectMethod; 175 /** class-defined readObject method, or null if none */ 176 private Method readObjectMethod; 177 /** class-defined readObjectNoData method, or null if none */ 178 private Method readObjectNoDataMethod; 179 /** class-defined writeReplace method, or null if none */ 180 private Method writeReplaceMethod; 181 /** class-defined readResolve method, or null if none */ 182 private Method readResolveMethod; 183 184 /** local class descriptor for represented class (may point to self) */ 185 private ObjectStreamClass localDesc; 186 /** superclass descriptor appearing in stream */ 187 private ObjectStreamClass superDesc; 188 189 /** 190 * Find the descriptor for a class that can be serialized. Creates an 191 * ObjectStreamClass instance if one does not exist yet for class. Null is 192 * returned if the specified class does not implement java.io.Serializable 193 * or java.io.Externalizable. 194 * 195 * @param cl class for which to get the descriptor 196 * @return the class descriptor for the specified class 197 */ 198 public static ObjectStreamClass lookup(Class<?> cl) { 199 return lookup(cl, false); 200 } 201 202 /** 203 * Returns the descriptor for any class, regardless of whether it 204 * implements {@link Serializable}. 205 * 206 * @param cl class for which to get the descriptor 207 * @return the class descriptor for the specified class 208 * @since 1.6 209 */ 210 public static ObjectStreamClass lookupAny(Class<?> cl) { 211 return lookup(cl, true); 212 } 213 214 /** 215 * Returns the name of the class described by this descriptor. 216 * This method returns the name of the class in the format that 217 * is used by the {@link Class#getName} method. 218 * 219 * @return a string representing the name of the class 220 */ 221 public String getName() { 222 return name; 223 } 224 225 /** 226 * Return the serialVersionUID for this class. The serialVersionUID 227 * defines a set of classes all with the same name that have evolved from a 228 * common root class and agree to be serialized and deserialized using a 229 * common format. NonSerializable classes have a serialVersionUID of 0L. 230 * 231 * @return the SUID of the class described by this descriptor 232 */ 233 public long getSerialVersionUID() { 234 // REMIND: synchronize instead of relying on volatile? 235 if (suid == null) { 236 suid = AccessController.doPrivileged( 237 new PrivilegedAction<Long>() { 238 public Long run() { 239 return computeDefaultSUID(cl); 240 } 241 } 242 ); 243 } 244 return suid.longValue(); 245 } 246 247 /** 248 * Return the class in the local VM that this version is mapped to. Null 249 * is returned if there is no corresponding local class. 250 * 251 * @return the <code>Class</code> instance that this descriptor represents 252 */ 253 @CallerSensitive 254 public Class<?> forClass() { 255 if (cl == null) { 256 return null; 257 } 258 if (System.getSecurityManager() != null) { 259 if (ReflectUtil.needsPackageAccessCheck(VMStack.getCallingClassLoader(), 260 cl.getClassLoader())) { 261 ReflectUtil.checkPackageAccess(cl); 262 } 263 } 264 return cl; 265 } 266 267 /** 268 * Return an array of the fields of this serializable class. 269 * 270 * @return an array containing an element for each persistent field of 271 * this class. Returns an array of length zero if there are no 272 * fields. 273 * @since 1.2 274 */ 275 public ObjectStreamField[] getFields() { 276 return getFields(true); 277 } 278 279 /** 280 * Get the field of this class by name. 281 * 282 * @param name the name of the data field to look for 283 * @return The ObjectStreamField object of the named field or null if 284 * there is no such named field. 285 */ 286 public ObjectStreamField getField(String name) { 287 return getField(name, null); 288 } 289 290 /** 291 * Return a string describing this ObjectStreamClass. 292 */ 293 public String toString() { 294 return name + ": static final long serialVersionUID = " + 295 getSerialVersionUID() + "L;"; 296 } 297 298 /** 299 * Looks up and returns class descriptor for given class, or null if class 300 * is non-serializable and "all" is set to false. 301 * 302 * @param cl class to look up 303 * @param all if true, return descriptors for all classes; if false, only 304 * return descriptors for serializable classes 305 */ 306 static ObjectStreamClass lookup(Class<?> cl, boolean all) { 307 if (!(all || Serializable.class.isAssignableFrom(cl))) { 308 return null; 309 } 310 processQueue(Caches.localDescsQueue, Caches.localDescs); 311 WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); 312 Reference<?> ref = Caches.localDescs.get(key); 313 Object entry = null; 314 if (ref != null) { 315 entry = ref.get(); 316 } 317 EntryFuture future = null; 318 if (entry == null) { 319 EntryFuture newEntry = new EntryFuture(); 320 Reference<?> newRef = new SoftReference<>(newEntry); 321 do { 322 if (ref != null) { 323 Caches.localDescs.remove(key, ref); 324 } 325 ref = Caches.localDescs.putIfAbsent(key, newRef); 326 if (ref != null) { 327 entry = ref.get(); 328 } 329 } while (ref != null && entry == null); 330 if (entry == null) { 331 future = newEntry; 332 } 333 } 334 335 if (entry instanceof ObjectStreamClass) { // check common case first 336 return (ObjectStreamClass) entry; 337 } 338 if (entry instanceof EntryFuture) { 339 future = (EntryFuture) entry; 340 if (future.getOwner() == Thread.currentThread()) { 341 /* 342 * Handle nested call situation described by 4803747: waiting 343 * for future value to be set by a lookup() call further up the 344 * stack will result in deadlock, so calculate and set the 345 * future value here instead. 346 */ 347 entry = null; 348 } else { 349 entry = future.get(); 350 } 351 } 352 if (entry == null) { 353 try { 354 entry = new ObjectStreamClass(cl); 355 } catch (Throwable th) { 356 entry = th; 357 } 358 if (future.set(entry)) { 359 Caches.localDescs.put(key, new SoftReference<Object>(entry)); 360 } else { 361 // nested lookup call already set future 362 entry = future.get(); 363 } 364 } 365 366 if (entry instanceof ObjectStreamClass) { 367 return (ObjectStreamClass) entry; 368 } else if (entry instanceof RuntimeException) { 369 throw (RuntimeException) entry; 370 } else if (entry instanceof Error) { 371 throw (Error) entry; 372 } else { 373 throw new InternalError("unexpected entry: " + entry); 374 } 375 } 376 377 /** 378 * Placeholder used in class descriptor and field reflector lookup tables 379 * for an entry in the process of being initialized. (Internal) callers 380 * which receive an EntryFuture belonging to another thread as the result 381 * of a lookup should call the get() method of the EntryFuture; this will 382 * return the actual entry once it is ready for use and has been set(). To 383 * conserve objects, EntryFutures synchronize on themselves. 384 */ 385 private static class EntryFuture { 386 387 private static final Object unset = new Object(); 388 private final Thread owner = Thread.currentThread(); 389 private Object entry = unset; 390 391 /** 392 * Attempts to set the value contained by this EntryFuture. If the 393 * EntryFuture's value has not been set already, then the value is 394 * saved, any callers blocked in the get() method are notified, and 395 * true is returned. If the value has already been set, then no saving 396 * or notification occurs, and false is returned. 397 */ 398 synchronized boolean set(Object entry) { 399 if (this.entry != unset) { 400 return false; 401 } 402 this.entry = entry; 403 notifyAll(); 404 return true; 405 } 406 407 /** 408 * Returns the value contained by this EntryFuture, blocking if 409 * necessary until a value is set. 410 */ 411 synchronized Object get() { 412 boolean interrupted = false; 413 while (entry == unset) { 414 try { 415 wait(); 416 } catch (InterruptedException ex) { 417 interrupted = true; 418 } 419 } 420 if (interrupted) { 421 AccessController.doPrivileged( 422 new PrivilegedAction<Void>() { 423 public Void run() { 424 Thread.currentThread().interrupt(); 425 return null; 426 } 427 } 428 ); 429 } 430 return entry; 431 } 432 433 /** 434 * Returns the thread that created this EntryFuture. 435 */ 436 Thread getOwner() { 437 return owner; 438 } 439 } 440 441 /** 442 * Creates local class descriptor representing given class. 443 */ 444 private ObjectStreamClass(final Class<?> cl) { 445 this.cl = cl; 446 name = cl.getName(); 447 isProxy = Proxy.isProxyClass(cl); 448 isEnum = Enum.class.isAssignableFrom(cl); 449 serializable = Serializable.class.isAssignableFrom(cl); 450 externalizable = Externalizable.class.isAssignableFrom(cl); 451 452 Class<?> superCl = cl.getSuperclass(); 453 superDesc = (superCl != null) ? lookup(superCl, false) : null; 454 localDesc = this; 455 456 if (serializable) { 457 AccessController.doPrivileged(new PrivilegedAction<Void>() { 458 public Void run() { 459 if (isEnum) { 460 suid = Long.valueOf(0); 461 fields = NO_FIELDS; 462 return null; 463 } 464 if (cl.isArray()) { 465 fields = NO_FIELDS; 466 return null; 467 } 468 469 suid = getDeclaredSUID(cl); 470 try { 471 fields = getSerialFields(cl); 472 computeFieldOffsets(); 473 } catch (InvalidClassException e) { 474 serializeEx = deserializeEx = 475 new ExceptionInfo(e.classname, e.getMessage()); 476 fields = NO_FIELDS; 477 } 478 479 if (externalizable) { 480 cons = getExternalizableConstructor(cl); 481 } else { 482 cons = getSerializableConstructor(cl); 483 writeObjectMethod = getPrivateMethod(cl, "writeObject", 484 new Class<?>[] { ObjectOutputStream.class }, 485 Void.TYPE); 486 readObjectMethod = getPrivateMethod(cl, "readObject", 487 new Class<?>[] { ObjectInputStream.class }, 488 Void.TYPE); 489 readObjectNoDataMethod = getPrivateMethod( 490 cl, "readObjectNoData", null, Void.TYPE); 491 hasWriteObjectData = (writeObjectMethod != null); 492 } 493 writeReplaceMethod = getInheritableMethod( 494 cl, "writeReplace", null, Object.class); 495 readResolveMethod = getInheritableMethod( 496 cl, "readResolve", null, Object.class); 497 return null; 498 } 499 }); 500 } else { 501 suid = Long.valueOf(0); 502 fields = NO_FIELDS; 503 } 504 505 try { 506 fieldRefl = getReflector(fields, this); 507 } catch (InvalidClassException ex) { 508 // field mismatches impossible when matching local fields vs. self 509 throw new InternalError(ex); 510 } 511 512 if (deserializeEx == null) { 513 if (isEnum) { 514 deserializeEx = new ExceptionInfo(name, "enum type"); 515 } else if (cons == null) { 516 deserializeEx = new ExceptionInfo(name, "no valid constructor"); 517 } 518 } 519 for (int i = 0; i < fields.length; i++) { 520 if (fields[i].getField() == null) { 521 defaultSerializeEx = new ExceptionInfo( 522 name, "unmatched serializable field(s) declared"); 523 } 524 } 525 } 526 527 /** 528 * Creates blank class descriptor which should be initialized via a 529 * subsequent call to initProxy(), initNonProxy() or readNonProxy(). 530 */ 531 ObjectStreamClass() { 532 } 533 534 /** 535 * Initializes class descriptor representing a proxy class. 536 */ 537 void initProxy(Class<?> cl, 538 ClassNotFoundException resolveEx, 539 ObjectStreamClass superDesc) 540 throws InvalidClassException 541 { 542 this.cl = cl; 543 this.resolveEx = resolveEx; 544 this.superDesc = superDesc; 545 isProxy = true; 546 serializable = true; 547 suid = Long.valueOf(0); 548 fields = NO_FIELDS; 549 550 if (cl != null) { 551 localDesc = lookup(cl, true); 552 if (!localDesc.isProxy) { 553 throw new InvalidClassException( 554 "cannot bind proxy descriptor to a non-proxy class"); 555 } 556 name = localDesc.name; 557 externalizable = localDesc.externalizable; 558 cons = localDesc.cons; 559 writeReplaceMethod = localDesc.writeReplaceMethod; 560 readResolveMethod = localDesc.readResolveMethod; 561 deserializeEx = localDesc.deserializeEx; 562 } 563 fieldRefl = getReflector(fields, localDesc); 564 } 565 566 /** 567 * Initializes class descriptor representing a non-proxy class. 568 */ 569 void initNonProxy(ObjectStreamClass model, 570 Class<?> cl, 571 ClassNotFoundException resolveEx, 572 ObjectStreamClass superDesc) 573 throws InvalidClassException 574 { 575 this.cl = cl; 576 this.resolveEx = resolveEx; 577 this.superDesc = superDesc; 578 name = model.name; 579 suid = Long.valueOf(model.getSerialVersionUID()); 580 isProxy = false; 581 isEnum = model.isEnum; 582 serializable = model.serializable; 583 externalizable = model.externalizable; 584 hasBlockExternalData = model.hasBlockExternalData; 585 hasWriteObjectData = model.hasWriteObjectData; 586 fields = model.fields; 587 primDataSize = model.primDataSize; 588 numObjFields = model.numObjFields; 589 590 if (cl != null) { 591 localDesc = lookup(cl, true); 592 if (localDesc.isProxy) { 593 throw new InvalidClassException( 594 "cannot bind non-proxy descriptor to a proxy class"); 595 } 596 if (isEnum != localDesc.isEnum) { 597 throw new InvalidClassException(isEnum ? 598 "cannot bind enum descriptor to a non-enum class" : 599 "cannot bind non-enum descriptor to an enum class"); 600 } 601 602 if (serializable == localDesc.serializable && 603 !cl.isArray() && 604 suid.longValue() != localDesc.getSerialVersionUID()) 605 { 606 throw new InvalidClassException(localDesc.name, 607 "local class incompatible: " + 608 "stream classdesc serialVersionUID = " + suid + 609 ", local class serialVersionUID = " + 610 localDesc.getSerialVersionUID()); 611 } 612 613 if (!classNamesEqual(name, localDesc.name)) { 614 throw new InvalidClassException(localDesc.name, 615 "local class name incompatible with stream class " + 616 "name \"" + name + "\""); 617 } 618 619 if (!isEnum) { 620 if ((serializable == localDesc.serializable) && 621 (externalizable != localDesc.externalizable)) 622 { 623 throw new InvalidClassException(localDesc.name, 624 "Serializable incompatible with Externalizable"); 625 } 626 627 if ((serializable != localDesc.serializable) || 628 (externalizable != localDesc.externalizable) || 629 !(serializable || externalizable)) 630 { 631 deserializeEx = new ExceptionInfo( 632 localDesc.name, "class invalid for deserialization"); 633 } 634 } 635 636 cons = localDesc.cons; 637 writeObjectMethod = localDesc.writeObjectMethod; 638 readObjectMethod = localDesc.readObjectMethod; 639 readObjectNoDataMethod = localDesc.readObjectNoDataMethod; 640 writeReplaceMethod = localDesc.writeReplaceMethod; 641 readResolveMethod = localDesc.readResolveMethod; 642 if (deserializeEx == null) { 643 deserializeEx = localDesc.deserializeEx; 644 } 645 } 646 fieldRefl = getReflector(fields, localDesc); 647 // reassign to matched fields so as to reflect local unshared settings 648 fields = fieldRefl.getFields(); 649 } 650 651 /** 652 * Reads non-proxy class descriptor information from given input stream. 653 * The resulting class descriptor is not fully functional; it can only be 654 * used as input to the ObjectInputStream.resolveClass() and 655 * ObjectStreamClass.initNonProxy() methods. 656 */ 657 void readNonProxy(ObjectInputStream in) 658 throws IOException, ClassNotFoundException 659 { 660 name = in.readUTF(); 661 suid = Long.valueOf(in.readLong()); 662 isProxy = false; 663 664 byte flags = in.readByte(); 665 hasWriteObjectData = 666 ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); 667 hasBlockExternalData = 668 ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); 669 externalizable = 670 ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); 671 boolean sflag = 672 ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); 673 if (externalizable && sflag) { 674 throw new InvalidClassException( 675 name, "serializable and externalizable flags conflict"); 676 } 677 serializable = externalizable || sflag; 678 isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); 679 if (isEnum && suid.longValue() != 0L) { 680 throw new InvalidClassException(name, 681 "enum descriptor has non-zero serialVersionUID: " + suid); 682 } 683 684 int numFields = in.readShort(); 685 if (isEnum && numFields != 0) { 686 throw new InvalidClassException(name, 687 "enum descriptor has non-zero field count: " + numFields); 688 } 689 fields = (numFields > 0) ? 690 new ObjectStreamField[numFields] : NO_FIELDS; 691 for (int i = 0; i < numFields; i++) { 692 char tcode = (char) in.readByte(); 693 String fname = in.readUTF(); 694 String signature = ((tcode == 'L') || (tcode == '[')) ? 695 in.readTypeString() : new String(new char[] { tcode }); 696 try { 697 fields[i] = new ObjectStreamField(fname, signature, false); 698 } catch (RuntimeException e) { 699 throw (IOException) new InvalidClassException(name, 700 "invalid descriptor for field " + fname).initCause(e); 701 } 702 } 703 computeFieldOffsets(); 704 } 705 706 /** 707 * Writes non-proxy class descriptor information to given output stream. 708 */ 709 void writeNonProxy(ObjectOutputStream out) throws IOException { 710 out.writeUTF(name); 711 out.writeLong(getSerialVersionUID()); 712 713 byte flags = 0; 714 if (externalizable) { 715 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; 716 int protocol = out.getProtocolVersion(); 717 if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { 718 flags |= ObjectStreamConstants.SC_BLOCK_DATA; 719 } 720 } else if (serializable) { 721 flags |= ObjectStreamConstants.SC_SERIALIZABLE; 722 } 723 if (hasWriteObjectData) { 724 flags |= ObjectStreamConstants.SC_WRITE_METHOD; 725 } 726 if (isEnum) { 727 flags |= ObjectStreamConstants.SC_ENUM; 728 } 729 out.writeByte(flags); 730 731 out.writeShort(fields.length); 732 for (int i = 0; i < fields.length; i++) { 733 ObjectStreamField f = fields[i]; 734 out.writeByte(f.getTypeCode()); 735 out.writeUTF(f.getName()); 736 if (!f.isPrimitive()) { 737 out.writeTypeString(f.getTypeString()); 738 } 739 } 740 } 741 742 /** 743 * Returns ClassNotFoundException (if any) thrown while attempting to 744 * resolve local class corresponding to this class descriptor. 745 */ 746 ClassNotFoundException getResolveException() { 747 return resolveEx; 748 } 749 750 /** 751 * Throws an InvalidClassException if object instances referencing this 752 * class descriptor should not be allowed to deserialize. This method does 753 * not apply to deserialization of enum constants. 754 */ 755 void checkDeserialize() throws InvalidClassException { 756 if (deserializeEx != null) { 757 throw deserializeEx.newInvalidClassException(); 758 } 759 } 760 761 /** 762 * Throws an InvalidClassException if objects whose class is represented by 763 * this descriptor should not be allowed to serialize. This method does 764 * not apply to serialization of enum constants. 765 */ 766 void checkSerialize() throws InvalidClassException { 767 if (serializeEx != null) { 768 throw serializeEx.newInvalidClassException(); 769 } 770 } 771 772 /** 773 * Throws an InvalidClassException if objects whose class is represented by 774 * this descriptor should not be permitted to use default serialization 775 * (e.g., if the class declares serializable fields that do not correspond 776 * to actual fields, and hence must use the GetField API). This method 777 * does not apply to deserialization of enum constants. 778 */ 779 void checkDefaultSerialize() throws InvalidClassException { 780 if (defaultSerializeEx != null) { 781 throw defaultSerializeEx.newInvalidClassException(); 782 } 783 } 784 785 /** 786 * Returns superclass descriptor. Note that on the receiving side, the 787 * superclass descriptor may be bound to a class that is not a superclass 788 * of the subclass descriptor's bound class. 789 */ 790 ObjectStreamClass getSuperDesc() { 791 return superDesc; 792 } 793 794 /** 795 * Returns the "local" class descriptor for the class associated with this 796 * class descriptor (i.e., the result of 797 * ObjectStreamClass.lookup(this.forClass())) or null if there is no class 798 * associated with this descriptor. 799 */ 800 ObjectStreamClass getLocalDesc() { 801 return localDesc; 802 } 803 804 /** 805 * Returns arrays of ObjectStreamFields representing the serializable 806 * fields of the represented class. If copy is true, a clone of this class 807 * descriptor's field array is returned, otherwise the array itself is 808 * returned. 809 */ 810 ObjectStreamField[] getFields(boolean copy) { 811 return copy ? fields.clone() : fields; 812 } 813 814 /** 815 * Looks up a serializable field of the represented class by name and type. 816 * A specified type of null matches all types, Object.class matches all 817 * non-primitive types, and any other non-null type matches assignable 818 * types only. Returns matching field, or null if no match found. 819 */ 820 ObjectStreamField getField(String name, Class<?> type) { 821 for (int i = 0; i < fields.length; i++) { 822 ObjectStreamField f = fields[i]; 823 if (f.getName().equals(name)) { 824 if (type == null || 825 (type == Object.class && !f.isPrimitive())) 826 { 827 return f; 828 } 829 Class<?> ftype = f.getType(); 830 if (ftype != null && type.isAssignableFrom(ftype)) { 831 return f; 832 } 833 } 834 } 835 return null; 836 } 837 838 /** 839 * Returns true if class descriptor represents a dynamic proxy class, false 840 * otherwise. 841 */ 842 boolean isProxy() { 843 return isProxy; 844 } 845 846 /** 847 * Returns true if class descriptor represents an enum type, false 848 * otherwise. 849 */ 850 boolean isEnum() { 851 return isEnum; 852 } 853 854 /** 855 * Returns true if represented class implements Externalizable, false 856 * otherwise. 857 */ 858 boolean isExternalizable() { 859 return externalizable; 860 } 861 862 /** 863 * Returns true if represented class implements Serializable, false 864 * otherwise. 865 */ 866 boolean isSerializable() { 867 return serializable; 868 } 869 870 /** 871 * Returns true if class descriptor represents externalizable class that 872 * has written its data in 1.2 (block data) format, false otherwise. 873 */ 874 boolean hasBlockExternalData() { 875 return hasBlockExternalData; 876 } 877 878 /** 879 * Returns true if class descriptor represents serializable (but not 880 * externalizable) class which has written its data via a custom 881 * writeObject() method, false otherwise. 882 */ 883 boolean hasWriteObjectData() { 884 return hasWriteObjectData; 885 } 886 887 /** 888 * Returns true if represented class is serializable/externalizable and can 889 * be instantiated by the serialization runtime--i.e., if it is 890 * externalizable and defines a public no-arg constructor, or if it is 891 * non-externalizable and its first non-serializable superclass defines an 892 * accessible no-arg constructor. Otherwise, returns false. 893 */ 894 boolean isInstantiable() { 895 return (cons != null); 896 } 897 898 /** 899 * Returns true if represented class is serializable (but not 900 * externalizable) and defines a conformant writeObject method. Otherwise, 901 * returns false. 902 */ 903 boolean hasWriteObjectMethod() { 904 return (writeObjectMethod != null); 905 } 906 907 /** 908 * Returns true if represented class is serializable (but not 909 * externalizable) and defines a conformant readObject method. Otherwise, 910 * returns false. 911 */ 912 boolean hasReadObjectMethod() { 913 return (readObjectMethod != null); 914 } 915 916 /** 917 * Returns true if represented class is serializable (but not 918 * externalizable) and defines a conformant readObjectNoData method. 919 * Otherwise, returns false. 920 */ 921 boolean hasReadObjectNoDataMethod() { 922 return (readObjectNoDataMethod != null); 923 } 924 925 /** 926 * Returns true if represented class is serializable or externalizable and 927 * defines a conformant writeReplace method. Otherwise, returns false. 928 */ 929 boolean hasWriteReplaceMethod() { 930 return (writeReplaceMethod != null); 931 } 932 933 /** 934 * Returns true if represented class is serializable or externalizable and 935 * defines a conformant readResolve method. Otherwise, returns false. 936 */ 937 boolean hasReadResolveMethod() { 938 return (readResolveMethod != null); 939 } 940 941 /** 942 * Creates a new instance of the represented class. If the class is 943 * externalizable, invokes its public no-arg constructor; otherwise, if the 944 * class is serializable, invokes the no-arg constructor of the first 945 * non-serializable superclass. Throws UnsupportedOperationException if 946 * this class descriptor is not associated with a class, if the associated 947 * class is non-serializable or if the appropriate no-arg constructor is 948 * inaccessible/unavailable. 949 */ 950 Object newInstance() 951 throws InstantiationException, InvocationTargetException, 952 UnsupportedOperationException 953 { 954 if (cons != null) { 955 try { 956 return cons.newInstance(); 957 } catch (IllegalAccessException ex) { 958 // should not occur, as access checks have been suppressed 959 throw new InternalError(ex); 960 } 961 } else { 962 throw new UnsupportedOperationException(); 963 } 964 } 965 966 /** 967 * Invokes the writeObject method of the represented serializable class. 968 * Throws UnsupportedOperationException if this class descriptor is not 969 * associated with a class, or if the class is externalizable, 970 * non-serializable or does not define writeObject. 971 */ 972 void invokeWriteObject(Object obj, ObjectOutputStream out) 973 throws IOException, UnsupportedOperationException 974 { 975 if (writeObjectMethod != null) { 976 try { 977 writeObjectMethod.invoke(obj, new Object[]{ out }); 978 } catch (InvocationTargetException ex) { 979 Throwable th = ex.getTargetException(); 980 if (th instanceof IOException) { 981 throw (IOException) th; 982 } else { 983 throwMiscException(th); 984 } 985 } catch (IllegalAccessException ex) { 986 // should not occur, as access checks have been suppressed 987 throw new InternalError(ex); 988 } 989 } else { 990 throw new UnsupportedOperationException(); 991 } 992 } 993 994 /** 995 * Invokes the readObject method of the represented serializable class. 996 * Throws UnsupportedOperationException if this class descriptor is not 997 * associated with a class, or if the class is externalizable, 998 * non-serializable or does not define readObject. 999 */ 1000 void invokeReadObject(Object obj, ObjectInputStream in) 1001 throws ClassNotFoundException, IOException, 1002 UnsupportedOperationException 1003 { 1004 if (readObjectMethod != null) { 1005 try { 1006 readObjectMethod.invoke(obj, new Object[]{ in }); 1007 } catch (InvocationTargetException ex) { 1008 Throwable th = ex.getTargetException(); 1009 if (th instanceof ClassNotFoundException) { 1010 throw (ClassNotFoundException) th; 1011 } else if (th instanceof IOException) { 1012 throw (IOException) th; 1013 } else { 1014 throwMiscException(th); 1015 } 1016 } catch (IllegalAccessException ex) { 1017 // should not occur, as access checks have been suppressed 1018 throw new InternalError(ex); 1019 } 1020 } else { 1021 throw new UnsupportedOperationException(); 1022 } 1023 } 1024 1025 /** 1026 * Invokes the readObjectNoData method of the represented serializable 1027 * class. Throws UnsupportedOperationException if this class descriptor is 1028 * not associated with a class, or if the class is externalizable, 1029 * non-serializable or does not define readObjectNoData. 1030 */ 1031 void invokeReadObjectNoData(Object obj) 1032 throws IOException, UnsupportedOperationException 1033 { 1034 if (readObjectNoDataMethod != null) { 1035 try { 1036 readObjectNoDataMethod.invoke(obj, (Object[]) null); 1037 } catch (InvocationTargetException ex) { 1038 Throwable th = ex.getTargetException(); 1039 if (th instanceof ObjectStreamException) { 1040 throw (ObjectStreamException) th; 1041 } else { 1042 throwMiscException(th); 1043 } 1044 } catch (IllegalAccessException ex) { 1045 // should not occur, as access checks have been suppressed 1046 throw new InternalError(ex); 1047 } 1048 } else { 1049 throw new UnsupportedOperationException(); 1050 } 1051 } 1052 1053 /** 1054 * Invokes the writeReplace method of the represented serializable class and 1055 * returns the result. Throws UnsupportedOperationException if this class 1056 * descriptor is not associated with a class, or if the class is 1057 * non-serializable or does not define writeReplace. 1058 */ 1059 Object invokeWriteReplace(Object obj) 1060 throws IOException, UnsupportedOperationException 1061 { 1062 if (writeReplaceMethod != null) { 1063 try { 1064 return writeReplaceMethod.invoke(obj, (Object[]) null); 1065 } catch (InvocationTargetException ex) { 1066 Throwable th = ex.getTargetException(); 1067 if (th instanceof ObjectStreamException) { 1068 throw (ObjectStreamException) th; 1069 } else { 1070 throwMiscException(th); 1071 throw new InternalError(th); // never reached 1072 } 1073 } catch (IllegalAccessException ex) { 1074 // should not occur, as access checks have been suppressed 1075 throw new InternalError(ex); 1076 } 1077 } else { 1078 throw new UnsupportedOperationException(); 1079 } 1080 } 1081 1082 /** 1083 * Invokes the readResolve method of the represented serializable class and 1084 * returns the result. Throws UnsupportedOperationException if this class 1085 * descriptor is not associated with a class, or if the class is 1086 * non-serializable or does not define readResolve. 1087 */ 1088 Object invokeReadResolve(Object obj) 1089 throws IOException, UnsupportedOperationException 1090 { 1091 if (readResolveMethod != null) { 1092 try { 1093 return readResolveMethod.invoke(obj, (Object[]) null); 1094 } catch (InvocationTargetException ex) { 1095 Throwable th = ex.getTargetException(); 1096 if (th instanceof ObjectStreamException) { 1097 throw (ObjectStreamException) th; 1098 } else { 1099 throwMiscException(th); 1100 throw new InternalError(th); // never reached 1101 } 1102 } catch (IllegalAccessException ex) { 1103 // should not occur, as access checks have been suppressed 1104 throw new InternalError(ex); 1105 } 1106 } else { 1107 throw new UnsupportedOperationException(); 1108 } 1109 } 1110 1111 /** 1112 * Class representing the portion of an object's serialized form allotted 1113 * to data described by a given class descriptor. If "hasData" is false, 1114 * the object's serialized form does not contain data associated with the 1115 * class descriptor. 1116 */ 1117 static class ClassDataSlot { 1118 1119 /** class descriptor "occupying" this slot */ 1120 final ObjectStreamClass desc; 1121 /** true if serialized form includes data for this slot's descriptor */ 1122 final boolean hasData; 1123 1124 ClassDataSlot(ObjectStreamClass desc, boolean hasData) { 1125 this.desc = desc; 1126 this.hasData = hasData; 1127 } 1128 } 1129 1130 /** 1131 * Returns array of ClassDataSlot instances representing the data layout 1132 * (including superclass data) for serialized objects described by this 1133 * class descriptor. ClassDataSlots are ordered by inheritance with those 1134 * containing "higher" superclasses appearing first. The final 1135 * ClassDataSlot contains a reference to this descriptor. 1136 */ 1137 ClassDataSlot[] getClassDataLayout() throws InvalidClassException { 1138 // REMIND: synchronize instead of relying on volatile? 1139 if (dataLayout == null) { 1140 dataLayout = getClassDataLayout0(); 1141 } 1142 return dataLayout; 1143 } 1144 1145 private ClassDataSlot[] getClassDataLayout0() 1146 throws InvalidClassException 1147 { 1148 ArrayList<ClassDataSlot> slots = new ArrayList<>(); 1149 Class<?> start = cl, end = cl; 1150 1151 // locate closest non-serializable superclass 1152 while (end != null && Serializable.class.isAssignableFrom(end)) { 1153 end = end.getSuperclass(); 1154 } 1155 1156 HashSet<String> oscNames = new HashSet<>(3); 1157 1158 for (ObjectStreamClass d = this; d != null; d = d.superDesc) { 1159 if (oscNames.contains(d.name)) { 1160 throw new InvalidClassException("Circular reference."); 1161 } else { 1162 oscNames.add(d.name); 1163 } 1164 1165 // search up inheritance hierarchy for class with matching name 1166 String searchName = (d.cl != null) ? d.cl.getName() : d.name; 1167 Class<?> match = null; 1168 for (Class<?> c = start; c != end; c = c.getSuperclass()) { 1169 if (searchName.equals(c.getName())) { 1170 match = c; 1171 break; 1172 } 1173 } 1174 1175 // add "no data" slot for each unmatched class below match 1176 if (match != null) { 1177 for (Class<?> c = start; c != match; c = c.getSuperclass()) { 1178 slots.add(new ClassDataSlot( 1179 ObjectStreamClass.lookup(c, true), false)); 1180 } 1181 start = match.getSuperclass(); 1182 } 1183 1184 // record descriptor/class pairing 1185 slots.add(new ClassDataSlot(d.getVariantFor(match), true)); 1186 } 1187 1188 // add "no data" slot for any leftover unmatched classes 1189 for (Class<?> c = start; c != end; c = c.getSuperclass()) { 1190 slots.add(new ClassDataSlot( 1191 ObjectStreamClass.lookup(c, true), false)); 1192 } 1193 1194 // order slots from superclass -> subclass 1195 Collections.reverse(slots); 1196 return slots.toArray(new ClassDataSlot[slots.size()]); 1197 } 1198 1199 /** 1200 * Returns aggregate size (in bytes) of marshalled primitive field values 1201 * for represented class. 1202 */ 1203 int getPrimDataSize() { 1204 return primDataSize; 1205 } 1206 1207 /** 1208 * Returns number of non-primitive serializable fields of represented 1209 * class. 1210 */ 1211 int getNumObjFields() { 1212 return numObjFields; 1213 } 1214 1215 /** 1216 * Fetches the serializable primitive field values of object obj and 1217 * marshals them into byte array buf starting at offset 0. It is the 1218 * responsibility of the caller to ensure that obj is of the proper type if 1219 * non-null. 1220 */ 1221 void getPrimFieldValues(Object obj, byte[] buf) { 1222 fieldRefl.getPrimFieldValues(obj, buf); 1223 } 1224 1225 /** 1226 * Sets the serializable primitive fields of object obj using values 1227 * unmarshalled from byte array buf starting at offset 0. It is the 1228 * responsibility of the caller to ensure that obj is of the proper type if 1229 * non-null. 1230 */ 1231 void setPrimFieldValues(Object obj, byte[] buf) { 1232 fieldRefl.setPrimFieldValues(obj, buf); 1233 } 1234 1235 /** 1236 * Fetches the serializable object field values of object obj and stores 1237 * them in array vals starting at offset 0. It is the responsibility of 1238 * the caller to ensure that obj is of the proper type if non-null. 1239 */ 1240 void getObjFieldValues(Object obj, Object[] vals) { 1241 fieldRefl.getObjFieldValues(obj, vals); 1242 } 1243 1244 /** 1245 * Sets the serializable object fields of object obj using values from 1246 * array vals starting at offset 0. It is the responsibility of the caller 1247 * to ensure that obj is of the proper type if non-null. 1248 */ 1249 void setObjFieldValues(Object obj, Object[] vals) { 1250 fieldRefl.setObjFieldValues(obj, vals); 1251 } 1252 1253 /** 1254 * Calculates and sets serializable field offsets, as well as primitive 1255 * data size and object field count totals. Throws InvalidClassException 1256 * if fields are illegally ordered. 1257 */ 1258 private void computeFieldOffsets() throws InvalidClassException { 1259 primDataSize = 0; 1260 numObjFields = 0; 1261 int firstObjIndex = -1; 1262 1263 for (int i = 0; i < fields.length; i++) { 1264 ObjectStreamField f = fields[i]; 1265 switch (f.getTypeCode()) { 1266 case 'Z': 1267 case 'B': 1268 f.setOffset(primDataSize++); 1269 break; 1270 1271 case 'C': 1272 case 'S': 1273 f.setOffset(primDataSize); 1274 primDataSize += 2; 1275 break; 1276 1277 case 'I': 1278 case 'F': 1279 f.setOffset(primDataSize); 1280 primDataSize += 4; 1281 break; 1282 1283 case 'J': 1284 case 'D': 1285 f.setOffset(primDataSize); 1286 primDataSize += 8; 1287 break; 1288 1289 case '[': 1290 case 'L': 1291 f.setOffset(numObjFields++); 1292 if (firstObjIndex == -1) { 1293 firstObjIndex = i; 1294 } 1295 break; 1296 1297 default: 1298 throw new InternalError(); 1299 } 1300 } 1301 if (firstObjIndex != -1 && 1302 firstObjIndex + numObjFields != fields.length) 1303 { 1304 throw new InvalidClassException(name, "illegal field order"); 1305 } 1306 } 1307 1308 /** 1309 * If given class is the same as the class associated with this class 1310 * descriptor, returns reference to this class descriptor. Otherwise, 1311 * returns variant of this class descriptor bound to given class. 1312 */ 1313 private ObjectStreamClass getVariantFor(Class<?> cl) 1314 throws InvalidClassException 1315 { 1316 if (this.cl == cl) { 1317 return this; 1318 } 1319 ObjectStreamClass desc = new ObjectStreamClass(); 1320 if (isProxy) { 1321 desc.initProxy(cl, null, superDesc); 1322 } else { 1323 desc.initNonProxy(this, cl, null, superDesc); 1324 } 1325 return desc; 1326 } 1327 1328 /** 1329 * Returns public no-arg constructor of given class, or null if none found. 1330 * Access checks are disabled on the returned constructor (if any), since 1331 * the defining class may still be non-public. 1332 */ 1333 private static Constructor<?> getExternalizableConstructor(Class<?> cl) { 1334 try { 1335 Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null); 1336 cons.setAccessible(true); 1337 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? 1338 cons : null; 1339 } catch (NoSuchMethodException ex) { 1340 return null; 1341 } 1342 } 1343 1344 /** 1345 * Returns subclass-accessible no-arg constructor of first non-serializable 1346 * superclass, or null if none found. Access checks are disabled on the 1347 * returned constructor (if any). 1348 */ 1349 private static Constructor<?> getSerializableConstructor(Class<?> cl) { 1350 Class<?> initCl = cl; 1351 while (Serializable.class.isAssignableFrom(initCl)) { 1352 if ((initCl = initCl.getSuperclass()) == null) { 1353 return null; 1354 } 1355 } 1356 try { 1357 Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null); 1358 int mods = cons.getModifiers(); 1359 if ((mods & Modifier.PRIVATE) != 0 || 1360 ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 && 1361 !packageEquals(cl, initCl))) 1362 { 1363 return null; 1364 } 1365 if (cons.getDeclaringClass() != cl) { 1366 cons = cons.serializationCopy(cons.getDeclaringClass(), cl); 1367 } 1368 cons.setAccessible(true); 1369 return cons; 1370 } catch (NoSuchMethodException ex) { 1371 return null; 1372 } 1373 } 1374 1375 /** 1376 * Returns non-static, non-abstract method with given signature provided it 1377 * is defined by or accessible (via inheritance) by the given class, or 1378 * null if no match found. Access checks are disabled on the returned 1379 * method (if any). 1380 */ 1381 private static Method getInheritableMethod(Class<?> cl, String name, 1382 Class<?>[] argTypes, 1383 Class<?> returnType) 1384 { 1385 Method meth = null; 1386 Class<?> defCl = cl; 1387 while (defCl != null) { 1388 try { 1389 meth = defCl.getDeclaredMethod(name, argTypes); 1390 break; 1391 } catch (NoSuchMethodException ex) { 1392 defCl = defCl.getSuperclass(); 1393 } 1394 } 1395 1396 if ((meth == null) || (meth.getReturnType() != returnType)) { 1397 return null; 1398 } 1399 meth.setAccessible(true); 1400 int mods = meth.getModifiers(); 1401 if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) { 1402 return null; 1403 } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) { 1404 return meth; 1405 } else if ((mods & Modifier.PRIVATE) != 0) { 1406 return (cl == defCl) ? meth : null; 1407 } else { 1408 return packageEquals(cl, defCl) ? meth : null; 1409 } 1410 } 1411 1412 /** 1413 * Returns non-static private method with given signature defined by given 1414 * class, or null if none found. Access checks are disabled on the 1415 * returned method (if any). 1416 */ 1417 private static Method getPrivateMethod(Class<?> cl, String name, 1418 Class<?>[] argTypes, 1419 Class<?> returnType) 1420 { 1421 try { 1422 Method meth = cl.getDeclaredMethod(name, argTypes); 1423 meth.setAccessible(true); 1424 int mods = meth.getModifiers(); 1425 return ((meth.getReturnType() == returnType) && 1426 ((mods & Modifier.STATIC) == 0) && 1427 ((mods & Modifier.PRIVATE) != 0)) ? meth : null; 1428 } catch (NoSuchMethodException ex) { 1429 return null; 1430 } 1431 } 1432 1433 /** 1434 * Returns true if classes are defined in the same runtime package, false 1435 * otherwise. 1436 */ 1437 private static boolean packageEquals(Class<?> cl1, Class<?> cl2) { 1438 return (cl1.getClassLoader() == cl2.getClassLoader() && 1439 getPackageName(cl1).equals(getPackageName(cl2))); 1440 } 1441 1442 /** 1443 * Returns package name of given class. 1444 */ 1445 private static String getPackageName(Class<?> cl) { 1446 String s = cl.getName(); 1447 int i = s.lastIndexOf('['); 1448 if (i >= 0) { 1449 s = s.substring(i + 2); 1450 } 1451 i = s.lastIndexOf('.'); 1452 return (i >= 0) ? s.substring(0, i) : ""; 1453 } 1454 1455 /** 1456 * Compares class names for equality, ignoring package names. Returns true 1457 * if class names equal, false otherwise. 1458 */ 1459 private static boolean classNamesEqual(String name1, String name2) { 1460 name1 = name1.substring(name1.lastIndexOf('.') + 1); 1461 name2 = name2.substring(name2.lastIndexOf('.') + 1); 1462 return name1.equals(name2); 1463 } 1464 1465 /** 1466 * Returns JVM type signature for given class. 1467 */ 1468 private static String getClassSignature(Class<?> cl) { 1469 StringBuilder sbuf = new StringBuilder(); 1470 while (cl.isArray()) { 1471 sbuf.append('['); 1472 cl = cl.getComponentType(); 1473 } 1474 if (cl.isPrimitive()) { 1475 if (cl == Integer.TYPE) { 1476 sbuf.append('I'); 1477 } else if (cl == Byte.TYPE) { 1478 sbuf.append('B'); 1479 } else if (cl == Long.TYPE) { 1480 sbuf.append('J'); 1481 } else if (cl == Float.TYPE) { 1482 sbuf.append('F'); 1483 } else if (cl == Double.TYPE) { 1484 sbuf.append('D'); 1485 } else if (cl == Short.TYPE) { 1486 sbuf.append('S'); 1487 } else if (cl == Character.TYPE) { 1488 sbuf.append('C'); 1489 } else if (cl == Boolean.TYPE) { 1490 sbuf.append('Z'); 1491 } else if (cl == Void.TYPE) { 1492 sbuf.append('V'); 1493 } else { 1494 throw new InternalError(); 1495 } 1496 } else { 1497 sbuf.append('L' + cl.getName().replace('.', '/') + ';'); 1498 } 1499 return sbuf.toString(); 1500 } 1501 1502 /** 1503 * Returns JVM type signature for given list of parameters and return type. 1504 */ 1505 private static String getMethodSignature(Class<?>[] paramTypes, 1506 Class<?> retType) 1507 { 1508 StringBuilder sbuf = new StringBuilder(); 1509 sbuf.append('('); 1510 for (int i = 0; i < paramTypes.length; i++) { 1511 sbuf.append(getClassSignature(paramTypes[i])); 1512 } 1513 sbuf.append(')'); 1514 sbuf.append(getClassSignature(retType)); 1515 return sbuf.toString(); 1516 } 1517 1518 /** 1519 * Convenience method for throwing an exception that is either a 1520 * RuntimeException, Error, or of some unexpected type (in which case it is 1521 * wrapped inside an IOException). 1522 */ 1523 private static void throwMiscException(Throwable th) throws IOException { 1524 if (th instanceof RuntimeException) { 1525 throw (RuntimeException) th; 1526 } else if (th instanceof Error) { 1527 throw (Error) th; 1528 } else { 1529 IOException ex = new IOException("unexpected exception type"); 1530 ex.initCause(th); 1531 throw ex; 1532 } 1533 } 1534 1535 /** 1536 * Returns ObjectStreamField array describing the serializable fields of 1537 * the given class. Serializable fields backed by an actual field of the 1538 * class are represented by ObjectStreamFields with corresponding non-null 1539 * Field objects. Throws InvalidClassException if the (explicitly 1540 * declared) serializable fields are invalid. 1541 */ 1542 private static ObjectStreamField[] getSerialFields(Class<?> cl) 1543 throws InvalidClassException 1544 { 1545 ObjectStreamField[] fields; 1546 if (Serializable.class.isAssignableFrom(cl) && 1547 !Externalizable.class.isAssignableFrom(cl) && 1548 !Proxy.isProxyClass(cl) && 1549 !cl.isInterface()) 1550 { 1551 if ((fields = getDeclaredSerialFields(cl)) == null) { 1552 fields = getDefaultSerialFields(cl); 1553 } 1554 Arrays.sort(fields); 1555 } else { 1556 fields = NO_FIELDS; 1557 } 1558 return fields; 1559 } 1560 1561 /** 1562 * Returns serializable fields of given class as defined explicitly by a 1563 * "serialPersistentFields" field, or null if no appropriate 1564 * "serialPersistentFields" field is defined. Serializable fields backed 1565 * by an actual field of the class are represented by ObjectStreamFields 1566 * with corresponding non-null Field objects. For compatibility with past 1567 * releases, a "serialPersistentFields" field with a null value is 1568 * considered equivalent to not declaring "serialPersistentFields". Throws 1569 * InvalidClassException if the declared serializable fields are 1570 * invalid--e.g., if multiple fields share the same name. 1571 */ 1572 private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl) 1573 throws InvalidClassException 1574 { 1575 ObjectStreamField[] serialPersistentFields = null; 1576 try { 1577 Field f = cl.getDeclaredField("serialPersistentFields"); 1578 int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; 1579 if ((f.getModifiers() & mask) == mask) { 1580 f.setAccessible(true); 1581 serialPersistentFields = (ObjectStreamField[]) f.get(null); 1582 } 1583 } catch (Exception ex) { 1584 } 1585 if (serialPersistentFields == null) { 1586 return null; 1587 } else if (serialPersistentFields.length == 0) { 1588 return NO_FIELDS; 1589 } 1590 1591 ObjectStreamField[] boundFields = 1592 new ObjectStreamField[serialPersistentFields.length]; 1593 Set<String> fieldNames = new HashSet<>(serialPersistentFields.length); 1594 1595 for (int i = 0; i < serialPersistentFields.length; i++) { 1596 ObjectStreamField spf = serialPersistentFields[i]; 1597 1598 String fname = spf.getName(); 1599 if (fieldNames.contains(fname)) { 1600 throw new InvalidClassException( 1601 "multiple serializable fields named " + fname); 1602 } 1603 fieldNames.add(fname); 1604 1605 try { 1606 Field f = cl.getDeclaredField(fname); 1607 if ((f.getType() == spf.getType()) && 1608 ((f.getModifiers() & Modifier.STATIC) == 0)) 1609 { 1610 boundFields[i] = 1611 new ObjectStreamField(f, spf.isUnshared(), true); 1612 } 1613 } catch (NoSuchFieldException ex) { 1614 } 1615 if (boundFields[i] == null) { 1616 boundFields[i] = new ObjectStreamField( 1617 fname, spf.getType(), spf.isUnshared()); 1618 } 1619 } 1620 return boundFields; 1621 } 1622 1623 /** 1624 * Returns array of ObjectStreamFields corresponding to all non-static 1625 * non-transient fields declared by given class. Each ObjectStreamField 1626 * contains a Field object for the field it represents. If no default 1627 * serializable fields exist, NO_FIELDS is returned. 1628 */ 1629 private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) { 1630 Field[] clFields = cl.getDeclaredFields(); 1631 ArrayList<ObjectStreamField> list = new ArrayList<>(); 1632 int mask = Modifier.STATIC | Modifier.TRANSIENT; 1633 1634 for (int i = 0; i < clFields.length; i++) { 1635 if ((clFields[i].getModifiers() & mask) == 0) { 1636 list.add(new ObjectStreamField(clFields[i], false, true)); 1637 } 1638 } 1639 int size = list.size(); 1640 return (size == 0) ? NO_FIELDS : 1641 list.toArray(new ObjectStreamField[size]); 1642 } 1643 1644 /** 1645 * Returns explicit serial version UID value declared by given class, or 1646 * null if none. 1647 */ 1648 private static Long getDeclaredSUID(Class<?> cl) { 1649 try { 1650 Field f = cl.getDeclaredField("serialVersionUID"); 1651 int mask = Modifier.STATIC | Modifier.FINAL; 1652 if ((f.getModifiers() & mask) == mask) { 1653 f.setAccessible(true); 1654 return Long.valueOf(f.getLong(null)); 1655 } 1656 } catch (Exception ex) { 1657 } 1658 return null; 1659 } 1660 1661 /** 1662 * Computes the default serial version UID value for the given class. 1663 */ 1664 private static long computeDefaultSUID(Class<?> cl) { 1665 if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) 1666 { 1667 return 0L; 1668 } 1669 1670 try { 1671 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 1672 DataOutputStream dout = new DataOutputStream(bout); 1673 1674 dout.writeUTF(cl.getName()); 1675 1676 int classMods = cl.getModifiers() & 1677 (Modifier.PUBLIC | Modifier.FINAL | 1678 Modifier.INTERFACE | Modifier.ABSTRACT); 1679 1680 /* 1681 * compensate for javac bug in which ABSTRACT bit was set for an 1682 * interface only if the interface declared methods 1683 */ 1684 Method[] methods = cl.getDeclaredMethods(); 1685 if ((classMods & Modifier.INTERFACE) != 0) { 1686 classMods = (methods.length > 0) ? 1687 (classMods | Modifier.ABSTRACT) : 1688 (classMods & ~Modifier.ABSTRACT); 1689 } 1690 dout.writeInt(classMods); 1691 1692 if (!cl.isArray()) { 1693 /* 1694 * compensate for change in 1.2FCS in which 1695 * Class.getInterfaces() was modified to return Cloneable and 1696 * Serializable for array classes. 1697 */ 1698 Class<?>[] interfaces = cl.getInterfaces(); 1699 String[] ifaceNames = new String[interfaces.length]; 1700 for (int i = 0; i < interfaces.length; i++) { 1701 ifaceNames[i] = interfaces[i].getName(); 1702 } 1703 Arrays.sort(ifaceNames); 1704 for (int i = 0; i < ifaceNames.length; i++) { 1705 dout.writeUTF(ifaceNames[i]); 1706 } 1707 } 1708 1709 Field[] fields = cl.getDeclaredFields(); 1710 MemberSignature[] fieldSigs = new MemberSignature[fields.length]; 1711 for (int i = 0; i < fields.length; i++) { 1712 fieldSigs[i] = new MemberSignature(fields[i]); 1713 } 1714 Arrays.sort(fieldSigs, new Comparator<MemberSignature>() { 1715 public int compare(MemberSignature ms1, MemberSignature ms2) { 1716 return ms1.name.compareTo(ms2.name); 1717 } 1718 }); 1719 for (int i = 0; i < fieldSigs.length; i++) { 1720 MemberSignature sig = fieldSigs[i]; 1721 int mods = sig.member.getModifiers() & 1722 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 1723 Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | 1724 Modifier.TRANSIENT); 1725 if (((mods & Modifier.PRIVATE) == 0) || 1726 ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) 1727 { 1728 dout.writeUTF(sig.name); 1729 dout.writeInt(mods); 1730 dout.writeUTF(sig.signature); 1731 } 1732 } 1733 1734 boolean checkSuperclass = !(VMRuntime.getRuntime().getTargetSdkVersion() 1735 <= MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND); 1736 if (hasStaticInitializer(cl, checkSuperclass)) { 1737 dout.writeUTF("<clinit>"); 1738 dout.writeInt(Modifier.STATIC); 1739 dout.writeUTF("()V"); 1740 } 1741 1742 Constructor<?>[] cons = cl.getDeclaredConstructors(); 1743 MemberSignature[] consSigs = new MemberSignature[cons.length]; 1744 for (int i = 0; i < cons.length; i++) { 1745 consSigs[i] = new MemberSignature(cons[i]); 1746 } 1747 Arrays.sort(consSigs, new Comparator<MemberSignature>() { 1748 public int compare(MemberSignature ms1, MemberSignature ms2) { 1749 return ms1.signature.compareTo(ms2.signature); 1750 } 1751 }); 1752 for (int i = 0; i < consSigs.length; i++) { 1753 MemberSignature sig = consSigs[i]; 1754 int mods = sig.member.getModifiers() & 1755 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 1756 Modifier.STATIC | Modifier.FINAL | 1757 Modifier.SYNCHRONIZED | Modifier.NATIVE | 1758 Modifier.ABSTRACT | Modifier.STRICT); 1759 if ((mods & Modifier.PRIVATE) == 0) { 1760 dout.writeUTF("<init>"); 1761 dout.writeInt(mods); 1762 dout.writeUTF(sig.signature.replace('/', '.')); 1763 } 1764 } 1765 1766 MemberSignature[] methSigs = new MemberSignature[methods.length]; 1767 for (int i = 0; i < methods.length; i++) { 1768 methSigs[i] = new MemberSignature(methods[i]); 1769 } 1770 Arrays.sort(methSigs, new Comparator<MemberSignature>() { 1771 public int compare(MemberSignature ms1, MemberSignature ms2) { 1772 int comp = ms1.name.compareTo(ms2.name); 1773 if (comp == 0) { 1774 comp = ms1.signature.compareTo(ms2.signature); 1775 } 1776 return comp; 1777 } 1778 }); 1779 for (int i = 0; i < methSigs.length; i++) { 1780 MemberSignature sig = methSigs[i]; 1781 int mods = sig.member.getModifiers() & 1782 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 1783 Modifier.STATIC | Modifier.FINAL | 1784 Modifier.SYNCHRONIZED | Modifier.NATIVE | 1785 Modifier.ABSTRACT | Modifier.STRICT); 1786 if ((mods & Modifier.PRIVATE) == 0) { 1787 dout.writeUTF(sig.name); 1788 dout.writeInt(mods); 1789 dout.writeUTF(sig.signature.replace('/', '.')); 1790 } 1791 } 1792 1793 dout.flush(); 1794 1795 MessageDigest md = MessageDigest.getInstance("SHA"); 1796 byte[] hashBytes = md.digest(bout.toByteArray()); 1797 long hash = 0; 1798 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { 1799 hash = (hash << 8) | (hashBytes[i] & 0xFF); 1800 } 1801 return hash; 1802 } catch (IOException ex) { 1803 throw new InternalError(ex); 1804 } catch (NoSuchAlgorithmException ex) { 1805 throw new SecurityException(ex.getMessage()); 1806 } 1807 } 1808 1809 /** Max SDK target version for which we use buggy hasStaticIntializier implementation. */ 1810 static final int MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND = 23; 1811 1812 /** 1813 * Returns true if the given class defines a static initializer method, 1814 * false otherwise. 1815 * if checkSuperclass is false, we use a buggy version (for compatibility reason) that 1816 * will return true even if only the superclass has a static initializer method. 1817 */ 1818 private native static boolean hasStaticInitializer(Class<?> cl, boolean checkSuperclass); 1819 1820 1821 /** 1822 * Class for computing and caching field/constructor/method signatures 1823 * during serialVersionUID calculation. 1824 */ 1825 private static class MemberSignature { 1826 1827 public final Member member; 1828 public final String name; 1829 public final String signature; 1830 1831 public MemberSignature(Field field) { 1832 member = field; 1833 name = field.getName(); 1834 signature = getClassSignature(field.getType()); 1835 } 1836 1837 public MemberSignature(Constructor<?> cons) { 1838 member = cons; 1839 name = cons.getName(); 1840 signature = getMethodSignature( 1841 cons.getParameterTypes(), Void.TYPE); 1842 } 1843 1844 public MemberSignature(Method meth) { 1845 member = meth; 1846 name = meth.getName(); 1847 signature = getMethodSignature( 1848 meth.getParameterTypes(), meth.getReturnType()); 1849 } 1850 } 1851 1852 /** 1853 * Class for setting and retrieving serializable field values in batch. 1854 */ 1855 // REMIND: dynamically generate these? 1856 private static class FieldReflector { 1857 1858 /** handle for performing unsafe operations */ 1859 private static final Unsafe unsafe = Unsafe.getUnsafe(); 1860 1861 /** fields to operate on */ 1862 private final ObjectStreamField[] fields; 1863 /** number of primitive fields */ 1864 private final int numPrimFields; 1865 /** unsafe field keys for reading fields - may contain dupes */ 1866 private final long[] readKeys; 1867 /** unsafe fields keys for writing fields - no dupes */ 1868 private final long[] writeKeys; 1869 /** field data offsets */ 1870 private final int[] offsets; 1871 /** field type codes */ 1872 private final char[] typeCodes; 1873 /** field types */ 1874 private final Class<?>[] types; 1875 1876 /** 1877 * Constructs FieldReflector capable of setting/getting values from the 1878 * subset of fields whose ObjectStreamFields contain non-null 1879 * reflective Field objects. ObjectStreamFields with null Fields are 1880 * treated as filler, for which get operations return default values 1881 * and set operations discard given values. 1882 */ 1883 FieldReflector(ObjectStreamField[] fields) { 1884 this.fields = fields; 1885 int nfields = fields.length; 1886 readKeys = new long[nfields]; 1887 writeKeys = new long[nfields]; 1888 offsets = new int[nfields]; 1889 typeCodes = new char[nfields]; 1890 ArrayList<Class<?>> typeList = new ArrayList<>(); 1891 Set<Long> usedKeys = new HashSet<>(); 1892 1893 1894 for (int i = 0; i < nfields; i++) { 1895 ObjectStreamField f = fields[i]; 1896 Field rf = f.getField(); 1897 long key = (rf != null) ? 1898 unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET; 1899 readKeys[i] = key; 1900 writeKeys[i] = usedKeys.add(key) ? 1901 key : Unsafe.INVALID_FIELD_OFFSET; 1902 offsets[i] = f.getOffset(); 1903 typeCodes[i] = f.getTypeCode(); 1904 if (!f.isPrimitive()) { 1905 typeList.add((rf != null) ? rf.getType() : null); 1906 } 1907 } 1908 1909 types = typeList.toArray(new Class<?>[typeList.size()]); 1910 numPrimFields = nfields - types.length; 1911 } 1912 1913 /** 1914 * Returns list of ObjectStreamFields representing fields operated on 1915 * by this reflector. The shared/unshared values and Field objects 1916 * contained by ObjectStreamFields in the list reflect their bindings 1917 * to locally defined serializable fields. 1918 */ 1919 ObjectStreamField[] getFields() { 1920 return fields; 1921 } 1922 1923 /** 1924 * Fetches the serializable primitive field values of object obj and 1925 * marshals them into byte array buf starting at offset 0. The caller 1926 * is responsible for ensuring that obj is of the proper type. 1927 */ 1928 void getPrimFieldValues(Object obj, byte[] buf) { 1929 if (obj == null) { 1930 throw new NullPointerException(); 1931 } 1932 /* assuming checkDefaultSerialize() has been called on the class 1933 * descriptor this FieldReflector was obtained from, no field keys 1934 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET. 1935 */ 1936 for (int i = 0; i < numPrimFields; i++) { 1937 long key = readKeys[i]; 1938 int off = offsets[i]; 1939 switch (typeCodes[i]) { 1940 case 'Z': 1941 Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key)); 1942 break; 1943 1944 case 'B': 1945 buf[off] = unsafe.getByte(obj, key); 1946 break; 1947 1948 case 'C': 1949 Bits.putChar(buf, off, unsafe.getChar(obj, key)); 1950 break; 1951 1952 case 'S': 1953 Bits.putShort(buf, off, unsafe.getShort(obj, key)); 1954 break; 1955 1956 case 'I': 1957 Bits.putInt(buf, off, unsafe.getInt(obj, key)); 1958 break; 1959 1960 case 'F': 1961 Bits.putFloat(buf, off, unsafe.getFloat(obj, key)); 1962 break; 1963 1964 case 'J': 1965 Bits.putLong(buf, off, unsafe.getLong(obj, key)); 1966 break; 1967 1968 case 'D': 1969 Bits.putDouble(buf, off, unsafe.getDouble(obj, key)); 1970 break; 1971 1972 default: 1973 throw new InternalError(); 1974 } 1975 } 1976 } 1977 1978 /** 1979 * Sets the serializable primitive fields of object obj using values 1980 * unmarshalled from byte array buf starting at offset 0. The caller 1981 * is responsible for ensuring that obj is of the proper type. 1982 */ 1983 void setPrimFieldValues(Object obj, byte[] buf) { 1984 if (obj == null) { 1985 throw new NullPointerException(); 1986 } 1987 for (int i = 0; i < numPrimFields; i++) { 1988 long key = writeKeys[i]; 1989 if (key == Unsafe.INVALID_FIELD_OFFSET) { 1990 continue; // discard value 1991 } 1992 int off = offsets[i]; 1993 switch (typeCodes[i]) { 1994 case 'Z': 1995 unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off)); 1996 break; 1997 1998 case 'B': 1999 unsafe.putByte(obj, key, buf[off]); 2000 break; 2001 2002 case 'C': 2003 unsafe.putChar(obj, key, Bits.getChar(buf, off)); 2004 break; 2005 2006 case 'S': 2007 unsafe.putShort(obj, key, Bits.getShort(buf, off)); 2008 break; 2009 2010 case 'I': 2011 unsafe.putInt(obj, key, Bits.getInt(buf, off)); 2012 break; 2013 2014 case 'F': 2015 unsafe.putFloat(obj, key, Bits.getFloat(buf, off)); 2016 break; 2017 2018 case 'J': 2019 unsafe.putLong(obj, key, Bits.getLong(buf, off)); 2020 break; 2021 2022 case 'D': 2023 unsafe.putDouble(obj, key, Bits.getDouble(buf, off)); 2024 break; 2025 2026 default: 2027 throw new InternalError(); 2028 } 2029 } 2030 } 2031 2032 /** 2033 * Fetches the serializable object field values of object obj and 2034 * stores them in array vals starting at offset 0. The caller is 2035 * responsible for ensuring that obj is of the proper type. 2036 */ 2037 void getObjFieldValues(Object obj, Object[] vals) { 2038 if (obj == null) { 2039 throw new NullPointerException(); 2040 } 2041 /* assuming checkDefaultSerialize() has been called on the class 2042 * descriptor this FieldReflector was obtained from, no field keys 2043 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET. 2044 */ 2045 for (int i = numPrimFields; i < fields.length; i++) { 2046 switch (typeCodes[i]) { 2047 case 'L': 2048 case '[': 2049 vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]); 2050 break; 2051 2052 default: 2053 throw new InternalError(); 2054 } 2055 } 2056 } 2057 2058 /** 2059 * Sets the serializable object fields of object obj using values from 2060 * array vals starting at offset 0. The caller is responsible for 2061 * ensuring that obj is of the proper type; however, attempts to set a 2062 * field with a value of the wrong type will trigger an appropriate 2063 * ClassCastException. 2064 */ 2065 void setObjFieldValues(Object obj, Object[] vals) { 2066 if (obj == null) { 2067 throw new NullPointerException(); 2068 } 2069 for (int i = numPrimFields; i < fields.length; i++) { 2070 long key = writeKeys[i]; 2071 if (key == Unsafe.INVALID_FIELD_OFFSET) { 2072 continue; // discard value 2073 } 2074 switch (typeCodes[i]) { 2075 case 'L': 2076 case '[': 2077 Object val = vals[offsets[i]]; 2078 if (val != null && 2079 !types[i - numPrimFields].isInstance(val)) 2080 { 2081 Field f = fields[i].getField(); 2082 throw new ClassCastException( 2083 "cannot assign instance of " + 2084 val.getClass().getName() + " to field " + 2085 f.getDeclaringClass().getName() + "." + 2086 f.getName() + " of type " + 2087 f.getType().getName() + " in instance of " + 2088 obj.getClass().getName()); 2089 } 2090 unsafe.putObject(obj, key, val); 2091 break; 2092 2093 default: 2094 throw new InternalError(); 2095 } 2096 } 2097 } 2098 } 2099 2100 /** 2101 * Matches given set of serializable fields with serializable fields 2102 * described by the given local class descriptor, and returns a 2103 * FieldReflector instance capable of setting/getting values from the 2104 * subset of fields that match (non-matching fields are treated as filler, 2105 * for which get operations return default values and set operations 2106 * discard given values). Throws InvalidClassException if unresolvable 2107 * type conflicts exist between the two sets of fields. 2108 */ 2109 private static FieldReflector getReflector(ObjectStreamField[] fields, 2110 ObjectStreamClass localDesc) 2111 throws InvalidClassException 2112 { 2113 // class irrelevant if no fields 2114 Class<?> cl = (localDesc != null && fields.length > 0) ? 2115 localDesc.cl : null; 2116 processQueue(Caches.reflectorsQueue, Caches.reflectors); 2117 FieldReflectorKey key = new FieldReflectorKey(cl, fields, 2118 Caches.reflectorsQueue); 2119 Reference<?> ref = Caches.reflectors.get(key); 2120 Object entry = null; 2121 if (ref != null) { 2122 entry = ref.get(); 2123 } 2124 EntryFuture future = null; 2125 if (entry == null) { 2126 EntryFuture newEntry = new EntryFuture(); 2127 Reference<?> newRef = new SoftReference<>(newEntry); 2128 do { 2129 if (ref != null) { 2130 Caches.reflectors.remove(key, ref); 2131 } 2132 ref = Caches.reflectors.putIfAbsent(key, newRef); 2133 if (ref != null) { 2134 entry = ref.get(); 2135 } 2136 } while (ref != null && entry == null); 2137 if (entry == null) { 2138 future = newEntry; 2139 } 2140 } 2141 2142 if (entry instanceof FieldReflector) { // check common case first 2143 return (FieldReflector) entry; 2144 } else if (entry instanceof EntryFuture) { 2145 entry = ((EntryFuture) entry).get(); 2146 } else if (entry == null) { 2147 try { 2148 entry = new FieldReflector(matchFields(fields, localDesc)); 2149 } catch (Throwable th) { 2150 entry = th; 2151 } 2152 future.set(entry); 2153 Caches.reflectors.put(key, new SoftReference<Object>(entry)); 2154 } 2155 2156 if (entry instanceof FieldReflector) { 2157 return (FieldReflector) entry; 2158 } else if (entry instanceof InvalidClassException) { 2159 throw (InvalidClassException) entry; 2160 } else if (entry instanceof RuntimeException) { 2161 throw (RuntimeException) entry; 2162 } else if (entry instanceof Error) { 2163 throw (Error) entry; 2164 } else { 2165 throw new InternalError("unexpected entry: " + entry); 2166 } 2167 } 2168 2169 /** 2170 * FieldReflector cache lookup key. Keys are considered equal if they 2171 * refer to the same class and equivalent field formats. 2172 */ 2173 private static class FieldReflectorKey extends WeakReference<Class<?>> { 2174 2175 private final String sigs; 2176 private final int hash; 2177 private final boolean nullClass; 2178 2179 FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields, 2180 ReferenceQueue<Class<?>> queue) 2181 { 2182 super(cl, queue); 2183 nullClass = (cl == null); 2184 StringBuilder sbuf = new StringBuilder(); 2185 for (int i = 0; i < fields.length; i++) { 2186 ObjectStreamField f = fields[i]; 2187 sbuf.append(f.getName()).append(f.getSignature()); 2188 } 2189 sigs = sbuf.toString(); 2190 hash = System.identityHashCode(cl) + sigs.hashCode(); 2191 } 2192 2193 public int hashCode() { 2194 return hash; 2195 } 2196 2197 public boolean equals(Object obj) { 2198 if (obj == this) { 2199 return true; 2200 } 2201 2202 if (obj instanceof FieldReflectorKey) { 2203 FieldReflectorKey other = (FieldReflectorKey) obj; 2204 Class<?> referent; 2205 return (nullClass ? other.nullClass 2206 : ((referent = get()) != null) && 2207 (referent == other.get())) && 2208 sigs.equals(other.sigs); 2209 } else { 2210 return false; 2211 } 2212 } 2213 } 2214 2215 /** 2216 * Matches given set of serializable fields with serializable fields 2217 * obtained from the given local class descriptor (which contain bindings 2218 * to reflective Field objects). Returns list of ObjectStreamFields in 2219 * which each ObjectStreamField whose signature matches that of a local 2220 * field contains a Field object for that field; unmatched 2221 * ObjectStreamFields contain null Field objects. Shared/unshared settings 2222 * of the returned ObjectStreamFields also reflect those of matched local 2223 * ObjectStreamFields. Throws InvalidClassException if unresolvable type 2224 * conflicts exist between the two sets of fields. 2225 */ 2226 private static ObjectStreamField[] matchFields(ObjectStreamField[] fields, 2227 ObjectStreamClass localDesc) 2228 throws InvalidClassException 2229 { 2230 ObjectStreamField[] localFields = (localDesc != null) ? 2231 localDesc.fields : NO_FIELDS; 2232 2233 /* 2234 * Even if fields == localFields, we cannot simply return localFields 2235 * here. In previous implementations of serialization, 2236 * ObjectStreamField.getType() returned Object.class if the 2237 * ObjectStreamField represented a non-primitive field and belonged to 2238 * a non-local class descriptor. To preserve this (questionable) 2239 * behavior, the ObjectStreamField instances returned by matchFields 2240 * cannot report non-primitive types other than Object.class; hence 2241 * localFields cannot be returned directly. 2242 */ 2243 2244 ObjectStreamField[] matches = new ObjectStreamField[fields.length]; 2245 for (int i = 0; i < fields.length; i++) { 2246 ObjectStreamField f = fields[i], m = null; 2247 for (int j = 0; j < localFields.length; j++) { 2248 ObjectStreamField lf = localFields[j]; 2249 // Android-changed: We can have fields with a same name and a different type. 2250 if (f.getName().equals(lf.getName()) && 2251 f.getSignature().equals(lf.getSignature())) { 2252 if (lf.getField() != null) { 2253 m = new ObjectStreamField( 2254 lf.getField(), lf.isUnshared(), false); 2255 } else { 2256 m = new ObjectStreamField( 2257 lf.getName(), lf.getSignature(), lf.isUnshared()); 2258 } 2259 } 2260 } 2261 if (m == null) { 2262 m = new ObjectStreamField( 2263 f.getName(), f.getSignature(), false); 2264 } 2265 m.setOffset(f.getOffset()); 2266 matches[i] = m; 2267 } 2268 return matches; 2269 } 2270 2271 // NOTE: The following couple of methods are left here because frameworks such as objenesis 2272 // use them. 2273 // 2274 // **** THESE METHODS WILL BE REMOVED IN A FUTURE ANDROID RELEASE ****. 2275 // 2276 private static long getConstructorId(Class<?> clazz) { 2277 final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); 2278 if (targetSdkVersion > 0 && targetSdkVersion <= 24) { 2279 System.logE("WARNING: ObjectStreamClass.getConstructorId(Class<?>) is private API and" + 2280 "will be removed in a future Android release."); 2281 // NOTE: This method is a stub that returns a fixed value. It's meant to be used 2282 // with newInstance(Class<?>, long) and our current implementation of that method ignores 2283 // the "constructorId" argument. We return : 2284 // 2285 // oh one one eight nine nine nine 2286 // eight eight one nine nine 2287 // nine one one nine seven two five 2288 // three 2289 // 2290 // in all cases. 2291 return 1189998819991197253L; 2292 } 2293 2294 throw new UnsupportedOperationException("ObjectStreamClass.getConstructorId(Class<?>) is " + 2295 "not supported on SDK " + targetSdkVersion); 2296 } 2297 private static Object newInstance(Class<?> clazz, long constructorId) { 2298 final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); 2299 if (targetSdkVersion > 0 && targetSdkVersion <= 24) { 2300 System.logE("WARNING: ObjectStreamClass.newInstance(Class<?>, long) is private API and" + 2301 "will be removed in a future Android release."); 2302 return sun.misc.Unsafe.getUnsafe().allocateInstance(clazz); 2303 } 2304 2305 throw new UnsupportedOperationException("ObjectStreamClass.newInstance(Class<?>, long) " + 2306 "is not supported on SDK " + targetSdkVersion); 2307 } 2308 2309 /** 2310 * Removes from the specified map any keys that have been enqueued 2311 * on the specified reference queue. 2312 */ 2313 static void processQueue(ReferenceQueue<Class<?>> queue, 2314 ConcurrentMap<? extends 2315 WeakReference<Class<?>>, ?> map) 2316 { 2317 Reference<? extends Class<?>> ref; 2318 while((ref = queue.poll()) != null) { 2319 map.remove(ref); 2320 } 2321 } 2322 2323 /** 2324 * Weak key for Class objects. 2325 * 2326 **/ 2327 static class WeakClassKey extends WeakReference<Class<?>> { 2328 /** 2329 * saved value of the referent's identity hash code, to maintain 2330 * a consistent hash code after the referent has been cleared 2331 */ 2332 private final int hash; 2333 2334 /** 2335 * Create a new WeakClassKey to the given object, registered 2336 * with a queue. 2337 */ 2338 WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) { 2339 super(cl, refQueue); 2340 hash = System.identityHashCode(cl); 2341 } 2342 2343 /** 2344 * Returns the identity hash code of the original referent. 2345 */ 2346 public int hashCode() { 2347 return hash; 2348 } 2349 2350 /** 2351 * Returns true if the given object is this identical 2352 * WeakClassKey instance, or, if this object's referent has not 2353 * been cleared, if the given object is another WeakClassKey 2354 * instance with the identical non-null referent as this one. 2355 */ 2356 public boolean equals(Object obj) { 2357 if (obj == this) { 2358 return true; 2359 } 2360 2361 if (obj instanceof WeakClassKey) { 2362 Object referent = get(); 2363 return (referent != null) && 2364 (referent == ((WeakClassKey) obj).get()); 2365 } else { 2366 return false; 2367 } 2368 } 2369 } 2370 } 2371