0001 /*
0002 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.io;
0027
0028 import java.lang.ref.Reference;
0029 import java.lang.ref.ReferenceQueue;
0030 import java.lang.ref.SoftReference;
0031 import java.lang.ref.WeakReference;
0032 import java.lang.reflect.Constructor;
0033 import java.lang.reflect.Field;
0034 import java.lang.reflect.InvocationTargetException;
0035 import java.lang.reflect.Member;
0036 import java.lang.reflect.Method;
0037 import java.lang.reflect.Modifier;
0038 import java.lang.reflect.Proxy;
0039 import java.security.AccessController;
0040 import java.security.MessageDigest;
0041 import java.security.NoSuchAlgorithmException;
0042 import java.security.PrivilegedAction;
0043 import java.util.ArrayList;
0044 import java.util.Arrays;
0045 import java.util.Collections;
0046 import java.util.Comparator;
0047 import java.util.HashSet;
0048 import java.util.Set;
0049 import java.util.concurrent.ConcurrentHashMap;
0050 import java.util.concurrent.ConcurrentMap;
0051 import sun.misc.Unsafe;
0052 import sun.reflect.ReflectionFactory;
0053
0054 /**
0055 * Serialization's descriptor for classes. It contains the name and
0056 * serialVersionUID of the class. The ObjectStreamClass for a specific class
0057 * loaded in this Java VM can be found/created using the lookup method.
0058 *
0059 * <p>The algorithm to compute the SerialVersionUID is described in
0060 * <a href="../../../platform/serialization/spec/class.html#4100">Object
0061 * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
0062 *
0063 * @author Mike Warres
0064 * @author Roger Riggs
0065 * @version 1.158, 05/05/07
0066 * @see ObjectStreamField
0067 * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
0068 * @since JDK1.1
0069 */
0070 public class ObjectStreamClass implements Serializable {
0071
0072 /** serialPersistentFields value indicating no serializable fields */
0073 public static final ObjectStreamField[] NO_FIELDS = new ObjectStreamField[0];
0074
0075 private static final long serialVersionUID = -6120832682080437368L;
0076 private static final ObjectStreamField[] serialPersistentFields = NO_FIELDS;
0077
0078 /** reflection factory for obtaining serialization constructors */
0079 private static final ReflectionFactory reflFactory = (ReflectionFactory) AccessController
0080 .doPrivileged(new ReflectionFactory.GetReflectionFactoryAction());
0081
0082 private static class Caches {
0083 /** cache mapping local classes -> descriptors */
0084 static final ConcurrentMap<WeakClassKey, Reference<?>> localDescs = new ConcurrentHashMap<WeakClassKey, Reference<?>>();
0085
0086 /** cache mapping field group/local desc pairs -> field reflectors */
0087 static final ConcurrentMap<FieldReflectorKey, Reference<?>> reflectors = new ConcurrentHashMap<FieldReflectorKey, Reference<?>>();
0088
0089 /** queue for WeakReferences to local classes */
0090 private static final ReferenceQueue<Class<?>> localDescsQueue = new ReferenceQueue<Class<?>>();
0091 /** queue for WeakReferences to field reflectors keys */
0092 private static final ReferenceQueue<Class<?>> reflectorsQueue = new ReferenceQueue<Class<?>>();
0093 }
0094
0095 /** class associated with this descriptor (if any) */
0096 private Class cl;
0097 /** name of class represented by this descriptor */
0098 private String name;
0099 /** serialVersionUID of represented class (null if not computed yet) */
0100 private volatile Long suid;
0101
0102 /** true if represents dynamic proxy class */
0103 private boolean isProxy;
0104 /** true if represents enum type */
0105 private boolean isEnum;
0106 /** true if represented class implements Serializable */
0107 private boolean serializable;
0108 /** true if represented class implements Externalizable */
0109 private boolean externalizable;
0110 /** true if desc has data written by class-defined writeObject method */
0111 private boolean hasWriteObjectData;
0112 /**
0113 * true if desc has externalizable data written in block data format; this
0114 * must be true by default to accommodate ObjectInputStream subclasses which
0115 * override readClassDescriptor() to return class descriptors obtained from
0116 * ObjectStreamClass.lookup() (see 4461737)
0117 */
0118 private boolean hasBlockExternalData = true;
0119
0120 /** exception (if any) thrown while attempting to resolve class */
0121 private ClassNotFoundException resolveEx;
0122 /** exception (if any) to throw if non-enum deserialization attempted */
0123 private InvalidClassException deserializeEx;
0124 /** exception (if any) to throw if non-enum serialization attempted */
0125 private InvalidClassException serializeEx;
0126 /** exception (if any) to throw if default serialization attempted */
0127 private InvalidClassException defaultSerializeEx;
0128
0129 /** serializable fields */
0130 private ObjectStreamField[] fields;
0131 /** aggregate marshalled size of primitive fields */
0132 private int primDataSize;
0133 /** number of non-primitive fields */
0134 private int numObjFields;
0135 /** reflector for setting/getting serializable field values */
0136 private FieldReflector fieldRefl;
0137 /** data layout of serialized objects described by this class desc */
0138 private volatile ClassDataSlot[] dataLayout;
0139
0140 /** serialization-appropriate constructor, or null if none */
0141 private Constructor cons;
0142 /** class-defined writeObject method, or null if none */
0143 private Method writeObjectMethod;
0144 /** class-defined readObject method, or null if none */
0145 private Method readObjectMethod;
0146 /** class-defined readObjectNoData method, or null if none */
0147 private Method readObjectNoDataMethod;
0148 /** class-defined writeReplace method, or null if none */
0149 private Method writeReplaceMethod;
0150 /** class-defined readResolve method, or null if none */
0151 private Method readResolveMethod;
0152
0153 /** local class descriptor for represented class (may point to self) */
0154 private ObjectStreamClass localDesc;
0155 /** superclass descriptor appearing in stream */
0156 private ObjectStreamClass super Desc;
0157
0158 /**
0159 * Initializes native code.
0160 */
0161 private static native void initNative();
0162
0163 static {
0164 initNative();
0165 }
0166
0167 /**
0168 * Find the descriptor for a class that can be serialized. Creates an
0169 * ObjectStreamClass instance if one does not exist yet for class. Null is
0170 * returned if the specified class does not implement java.io.Serializable
0171 * or java.io.Externalizable.
0172 *
0173 * @param cl class for which to get the descriptor
0174 * @return the class descriptor for the specified class
0175 */
0176 public static ObjectStreamClass lookup(Class<?> cl) {
0177 return lookup(cl, false);
0178 }
0179
0180 /**
0181 * Returns the descriptor for any class, regardless of whether it
0182 * implements {@link Serializable}.
0183 *
0184 * @param cl class for which to get the descriptor
0185 * @return the class descriptor for the specified class
0186 * @since 1.6
0187 */
0188 public static ObjectStreamClass lookupAny(Class<?> cl) {
0189 return lookup(cl, true);
0190 }
0191
0192 /**
0193 * Returns the name of the class described by this descriptor.
0194 * This method returns the name of the class in the format that
0195 * is used by the {@link Class#getName} method.
0196 *
0197 * @return a string representing the name of the class
0198 */
0199 public String getName() {
0200 return name;
0201 }
0202
0203 /**
0204 * Return the serialVersionUID for this class. The serialVersionUID
0205 * defines a set of classes all with the same name that have evolved from a
0206 * common root class and agree to be serialized and deserialized using a
0207 * common format. NonSerializable classes have a serialVersionUID of 0L.
0208 *
0209 * @return the SUID of the class described by this descriptor
0210 */
0211 public long getSerialVersionUID() {
0212 // REMIND: synchronize instead of relying on volatile?
0213 if (suid == null) {
0214 suid = (Long) AccessController
0215 .doPrivileged(new PrivilegedAction() {
0216 public Object run() {
0217 return Long.valueOf(computeDefaultSUID(cl));
0218 }
0219 });
0220 }
0221 return suid.longValue();
0222 }
0223
0224 /**
0225 * Return the class in the local VM that this version is mapped to. Null
0226 * is returned if there is no corresponding local class.
0227 *
0228 * @return the <code>Class</code> instance that this descriptor represents
0229 */
0230 public Class<?> forClass() {
0231 return cl;
0232 }
0233
0234 /**
0235 * Return an array of the fields of this serializable class.
0236 *
0237 * @return an array containing an element for each persistent field of
0238 * this class. Returns an array of length zero if there are no
0239 * fields.
0240 * @since 1.2
0241 */
0242 public ObjectStreamField[] getFields() {
0243 return getFields(true);
0244 }
0245
0246 /**
0247 * Get the field of this class by name.
0248 *
0249 * @param name the name of the data field to look for
0250 * @return The ObjectStreamField object of the named field or null if
0251 * there is no such named field.
0252 */
0253 public ObjectStreamField getField(String name) {
0254 return getField(name, null);
0255 }
0256
0257 /**
0258 * Return a string describing this ObjectStreamClass.
0259 */
0260 public String toString() {
0261 return name + ": static final long serialVersionUID = "
0262 + getSerialVersionUID() + "L;";
0263 }
0264
0265 /**
0266 * Looks up and returns class descriptor for given class, or null if class
0267 * is non-serializable and "all" is set to false.
0268 *
0269 * @param cl class to look up
0270 * @param all if true, return descriptors for all classes; if false, only
0271 * return descriptors for serializable classes
0272 */
0273 static ObjectStreamClass lookup(Class cl, boolean all) {
0274 if (!(all || Serializable.class.isAssignableFrom(cl))) {
0275 return null;
0276 }
0277 processQueue(Caches.localDescsQueue, Caches.localDescs);
0278 WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
0279 Reference<?> ref = Caches.localDescs.get(key);
0280 Object entry = null;
0281 if (ref != null) {
0282 entry = ref.get();
0283 }
0284 EntryFuture future = null;
0285 if (entry == null) {
0286 EntryFuture newEntry = new EntryFuture();
0287 Reference<?> newRef = new SoftReference<EntryFuture>(
0288 newEntry);
0289 do {
0290 if (ref != null) {
0291 Caches.localDescs.remove(key, ref);
0292 }
0293 ref = Caches.localDescs.putIfAbsent(key, newRef);
0294 if (ref != null) {
0295 entry = ref.get();
0296 }
0297 } while (ref != null && entry == null);
0298 if (entry == null) {
0299 future = newEntry;
0300 }
0301 }
0302
0303 if (entry instanceof ObjectStreamClass) { // check common case first
0304 return (ObjectStreamClass) entry;
0305 }
0306 if (entry instanceof EntryFuture) {
0307 future = (EntryFuture) entry;
0308 if (future.getOwner() == Thread.currentThread()) {
0309 /*
0310 * Handle nested call situation described by 4803747: waiting
0311 * for future value to be set by a lookup() call further up the
0312 * stack will result in deadlock, so calculate and set the
0313 * future value here instead.
0314 */
0315 entry = null;
0316 } else {
0317 entry = future.get();
0318 }
0319 }
0320 if (entry == null) {
0321 try {
0322 entry = new ObjectStreamClass(cl);
0323 } catch (Throwable th) {
0324 entry = th;
0325 }
0326 if (future.set(entry)) {
0327 Caches.localDescs.put(key, new SoftReference<Object>(
0328 entry));
0329 } else {
0330 // nested lookup call already set future
0331 entry = future.get();
0332 }
0333 }
0334
0335 if (entry instanceof ObjectStreamClass) {
0336 return (ObjectStreamClass) entry;
0337 } else if (entry instanceof RuntimeException) {
0338 throw (RuntimeException) entry;
0339 } else if (entry instanceof Error) {
0340 throw (Error) entry;
0341 } else {
0342 throw new InternalError("unexpected entry: " + entry);
0343 }
0344 }
0345
0346 /**
0347 * Placeholder used in class descriptor and field reflector lookup tables
0348 * for an entry in the process of being initialized. (Internal) callers
0349 * which receive an EntryFuture belonging to another thread as the result
0350 * of a lookup should call the get() method of the EntryFuture; this will
0351 * return the actual entry once it is ready for use and has been set(). To
0352 * conserve objects, EntryFutures synchronize on themselves.
0353 */
0354 private static class EntryFuture {
0355
0356 private static final Object unset = new Object();
0357 private final Thread owner = Thread.currentThread();
0358 private Object entry = unset;
0359
0360 /**
0361 * Attempts to set the value contained by this EntryFuture. If the
0362 * EntryFuture's value has not been set already, then the value is
0363 * saved, any callers blocked in the get() method are notified, and
0364 * true is returned. If the value has already been set, then no saving
0365 * or notification occurs, and false is returned.
0366 */
0367 synchronized boolean set(Object entry) {
0368 if (this .entry != unset) {
0369 return false;
0370 }
0371 this .entry = entry;
0372 notifyAll();
0373 return true;
0374 }
0375
0376 /**
0377 * Returns the value contained by this EntryFuture, blocking if
0378 * necessary until a value is set.
0379 */
0380 synchronized Object get() {
0381 boolean interrupted = false;
0382 while (entry == unset) {
0383 try {
0384 wait();
0385 } catch (InterruptedException ex) {
0386 interrupted = true;
0387 }
0388 }
0389 if (interrupted) {
0390 AccessController.doPrivileged(new PrivilegedAction() {
0391 public Object run() {
0392 Thread.currentThread().interrupt();
0393 return null;
0394 }
0395 });
0396 }
0397 return entry;
0398 }
0399
0400 /**
0401 * Returns the thread that created this EntryFuture.
0402 */
0403 Thread getOwner() {
0404 return owner;
0405 }
0406 }
0407
0408 /**
0409 * Creates local class descriptor representing given class.
0410 */
0411 private ObjectStreamClass(final Class cl) {
0412 this .cl = cl;
0413 name = cl.getName();
0414 isProxy = Proxy.isProxyClass(cl);
0415 isEnum = Enum.class.isAssignableFrom(cl);
0416 serializable = Serializable.class.isAssignableFrom(cl);
0417 externalizable = Externalizable.class.isAssignableFrom(cl);
0418
0419 Class super Cl = cl.getSuperclass();
0420 super Desc = (super Cl != null) ? lookup(super Cl, false) : null;
0421 localDesc = this ;
0422
0423 if (serializable) {
0424 AccessController.doPrivileged(new PrivilegedAction() {
0425 public Object run() {
0426 if (isEnum) {
0427 suid = Long.valueOf(0);
0428 fields = NO_FIELDS;
0429 return null;
0430 }
0431 if (cl.isArray()) {
0432 fields = NO_FIELDS;
0433 return null;
0434 }
0435
0436 suid = getDeclaredSUID(cl);
0437 try {
0438 fields = getSerialFields(cl);
0439 computeFieldOffsets();
0440 } catch (InvalidClassException e) {
0441 serializeEx = deserializeEx = e;
0442 fields = NO_FIELDS;
0443 }
0444
0445 if (externalizable) {
0446 cons = getExternalizableConstructor(cl);
0447 } else {
0448 cons = getSerializableConstructor(cl);
0449 writeObjectMethod = getPrivateMethod(
0450 cl,
0451 "writeObject",
0452 new Class[] { ObjectOutputStream.class },
0453 Void.TYPE);
0454 readObjectMethod = getPrivateMethod(
0455 cl,
0456 "readObject",
0457 new Class[] { ObjectInputStream.class },
0458 Void.TYPE);
0459 readObjectNoDataMethod = getPrivateMethod(cl,
0460 "readObjectNoData", null, Void.TYPE);
0461 hasWriteObjectData = (writeObjectMethod != null);
0462 }
0463 writeReplaceMethod = getInheritableMethod(cl,
0464 "writeReplace", null, Object.class);
0465 readResolveMethod = getInheritableMethod(cl,
0466 "readResolve", null, Object.class);
0467 return null;
0468 }
0469 });
0470 } else {
0471 suid = Long.valueOf(0);
0472 fields = NO_FIELDS;
0473 }
0474
0475 try {
0476 fieldRefl = getReflector(fields, this );
0477 } catch (InvalidClassException ex) {
0478 // field mismatches impossible when matching local fields vs. self
0479 throw new InternalError();
0480 }
0481
0482 if (deserializeEx == null) {
0483 if (isEnum) {
0484 deserializeEx = new InvalidClassException(name,
0485 "enum type");
0486 } else if (cons == null) {
0487 deserializeEx = new InvalidClassException(name,
0488 "no valid constructor");
0489 }
0490 }
0491 for (int i = 0; i < fields.length; i++) {
0492 if (fields[i].getField() == null) {
0493 defaultSerializeEx = new InvalidClassException(name,
0494 "unmatched serializable field(s) declared");
0495 }
0496 }
0497 }
0498
0499 /**
0500 * Creates blank class descriptor which should be initialized via a
0501 * subsequent call to initProxy(), initNonProxy() or readNonProxy().
0502 */
0503 ObjectStreamClass() {
0504 }
0505
0506 /**
0507 * Initializes class descriptor representing a proxy class.
0508 */
0509 void initProxy(Class cl, ClassNotFoundException resolveEx,
0510 ObjectStreamClass super Desc) throws InvalidClassException {
0511 this .cl = cl;
0512 this .resolveEx = resolveEx;
0513 this .super Desc = super Desc;
0514 isProxy = true;
0515 serializable = true;
0516 suid = Long.valueOf(0);
0517 fields = NO_FIELDS;
0518
0519 if (cl != null) {
0520 localDesc = lookup(cl, true);
0521 if (!localDesc.isProxy) {
0522 throw new InvalidClassException(
0523 "cannot bind proxy descriptor to a non-proxy class");
0524 }
0525 name = localDesc.name;
0526 externalizable = localDesc.externalizable;
0527 cons = localDesc.cons;
0528 writeReplaceMethod = localDesc.writeReplaceMethod;
0529 readResolveMethod = localDesc.readResolveMethod;
0530 deserializeEx = localDesc.deserializeEx;
0531 }
0532 fieldRefl = getReflector(fields, localDesc);
0533 }
0534
0535 /**
0536 * Initializes class descriptor representing a non-proxy class.
0537 */
0538 void initNonProxy(ObjectStreamClass model, Class cl,
0539 ClassNotFoundException resolveEx,
0540 ObjectStreamClass super Desc) throws InvalidClassException {
0541 this .cl = cl;
0542 this .resolveEx = resolveEx;
0543 this .super Desc = super Desc;
0544 name = model.name;
0545 suid = Long.valueOf(model.getSerialVersionUID());
0546 isProxy = false;
0547 isEnum = model.isEnum;
0548 serializable = model.serializable;
0549 externalizable = model.externalizable;
0550 hasBlockExternalData = model.hasBlockExternalData;
0551 hasWriteObjectData = model.hasWriteObjectData;
0552 fields = model.fields;
0553 primDataSize = model.primDataSize;
0554 numObjFields = model.numObjFields;
0555
0556 if (cl != null) {
0557 localDesc = lookup(cl, true);
0558 if (localDesc.isProxy) {
0559 throw new InvalidClassException(
0560 "cannot bind non-proxy descriptor to a proxy class");
0561 }
0562 if (isEnum != localDesc.isEnum) {
0563 throw new InvalidClassException(
0564 isEnum ? "cannot bind enum descriptor to a non-enum class"
0565 : "cannot bind non-enum descriptor to an enum class");
0566 }
0567
0568 if (serializable == localDesc.serializable
0569 && !cl.isArray()
0570 && suid.longValue() != localDesc
0571 .getSerialVersionUID()) {
0572 throw new InvalidClassException(
0573 localDesc.name,
0574 "local class incompatible: "
0575 + "stream classdesc serialVersionUID = "
0576 + suid
0577 + ", local class serialVersionUID = "
0578 + localDesc.getSerialVersionUID());
0579 }
0580
0581 if (!classNamesEqual(name, localDesc.name)) {
0582 throw new InvalidClassException(localDesc.name,
0583 "local class name incompatible with stream class "
0584 + "name \"" + name + "\"");
0585 }
0586
0587 if (!isEnum) {
0588 if ((serializable == localDesc.serializable)
0589 && (externalizable != localDesc.externalizable)) {
0590 throw new InvalidClassException(localDesc.name,
0591 "Serializable incompatible with Externalizable");
0592 }
0593
0594 if ((serializable != localDesc.serializable)
0595 || (externalizable != localDesc.externalizable)
0596 || !(serializable || externalizable)) {
0597 deserializeEx = new InvalidClassException(
0598 localDesc.name,
0599 "class invalid for deserialization");
0600 }
0601 }
0602
0603 cons = localDesc.cons;
0604 writeObjectMethod = localDesc.writeObjectMethod;
0605 readObjectMethod = localDesc.readObjectMethod;
0606 readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
0607 writeReplaceMethod = localDesc.writeReplaceMethod;
0608 readResolveMethod = localDesc.readResolveMethod;
0609 if (deserializeEx == null) {
0610 deserializeEx = localDesc.deserializeEx;
0611 }
0612 }
0613 fieldRefl = getReflector(fields, localDesc);
0614 // reassign to matched fields so as to reflect local unshared settings
0615 fields = fieldRefl.getFields();
0616 }
0617
0618 /**
0619 * Reads non-proxy class descriptor information from given input stream.
0620 * The resulting class descriptor is not fully functional; it can only be
0621 * used as input to the ObjectInputStream.resolveClass() and
0622 * ObjectStreamClass.initNonProxy() methods.
0623 */
0624 void readNonProxy(ObjectInputStream in) throws IOException,
0625 ClassNotFoundException {
0626 name = in.readUTF();
0627 suid = Long.valueOf(in.readLong());
0628 isProxy = false;
0629
0630 byte flags = in.readByte();
0631 hasWriteObjectData = ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
0632 hasBlockExternalData = ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
0633 externalizable = ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
0634 boolean sflag = ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
0635 if (externalizable && sflag) {
0636 throw new InvalidClassException(name,
0637 "serializable and externalizable flags conflict");
0638 }
0639 serializable = externalizable || sflag;
0640 isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
0641 if (isEnum && suid.longValue() != 0L) {
0642 throw new InvalidClassException(name,
0643 "enum descriptor has non-zero serialVersionUID: "
0644 + suid);
0645 }
0646
0647 int numFields = in.readShort();
0648 if (isEnum && numFields != 0) {
0649 throw new InvalidClassException(name,
0650 "enum descriptor has non-zero field count: "
0651 + numFields);
0652 }
0653 fields = (numFields > 0) ? new ObjectStreamField[numFields]
0654 : NO_FIELDS;
0655 for (int i = 0; i < numFields; i++) {
0656 char tcode = (char) in.readByte();
0657 String fname = in.readUTF();
0658 String signature = ((tcode == 'L') || (tcode == '[')) ? in
0659 .readTypeString()
0660 : new String(new char[] { tcode });
0661 try {
0662 fields[i] = new ObjectStreamField(fname, signature,
0663 false);
0664 } catch (RuntimeException e) {
0665 throw (IOException) new InvalidClassException(name,
0666 "invalid descriptor for field " + fname)
0667 .initCause(e);
0668 }
0669 }
0670 computeFieldOffsets();
0671 }
0672
0673 /**
0674 * Writes non-proxy class descriptor information to given output stream.
0675 */
0676 void writeNonProxy(ObjectOutputStream out) throws IOException {
0677 out.writeUTF(name);
0678 out.writeLong(getSerialVersionUID());
0679
0680 byte flags = 0;
0681 if (externalizable) {
0682 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
0683 int protocol = out.getProtocolVersion();
0684 if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
0685 flags |= ObjectStreamConstants.SC_BLOCK_DATA;
0686 }
0687 } else if (serializable) {
0688 flags |= ObjectStreamConstants.SC_SERIALIZABLE;
0689 }
0690 if (hasWriteObjectData) {
0691 flags |= ObjectStreamConstants.SC_WRITE_METHOD;
0692 }
0693 if (isEnum) {
0694 flags |= ObjectStreamConstants.SC_ENUM;
0695 }
0696 out.writeByte(flags);
0697
0698 out.writeShort(fields.length);
0699 for (int i = 0; i < fields.length; i++) {
0700 ObjectStreamField f = fields[i];
0701 out.writeByte(f.getTypeCode());
0702 out.writeUTF(f.getName());
0703 if (!f.isPrimitive()) {
0704 out.writeTypeString(f.getTypeString());
0705 }
0706 }
0707 }
0708
0709 /**
0710 * Returns ClassNotFoundException (if any) thrown while attempting to
0711 * resolve local class corresponding to this class descriptor.
0712 */
0713 ClassNotFoundException getResolveException() {
0714 return resolveEx;
0715 }
0716
0717 /**
0718 * Throws an InvalidClassException if object instances referencing this
0719 * class descriptor should not be allowed to deserialize. This method does
0720 * not apply to deserialization of enum constants.
0721 */
0722 void checkDeserialize() throws InvalidClassException {
0723 if (deserializeEx != null) {
0724 InvalidClassException ice = new InvalidClassException(
0725 deserializeEx.classname, deserializeEx.getMessage());
0726 ice.initCause(deserializeEx);
0727 throw ice;
0728 }
0729 }
0730
0731 /**
0732 * Throws an InvalidClassException if objects whose class is represented by
0733 * this descriptor should not be allowed to serialize. This method does
0734 * not apply to serialization of enum constants.
0735 */
0736 void checkSerialize() throws InvalidClassException {
0737 if (serializeEx != null) {
0738 InvalidClassException ice = new InvalidClassException(
0739 serializeEx.classname, serializeEx.getMessage());
0740 ice.initCause(serializeEx);
0741 throw ice;
0742 }
0743 }
0744
0745 /**
0746 * Throws an InvalidClassException if objects whose class is represented by
0747 * this descriptor should not be permitted to use default serialization
0748 * (e.g., if the class declares serializable fields that do not correspond
0749 * to actual fields, and hence must use the GetField API). This method
0750 * does not apply to deserialization of enum constants.
0751 */
0752 void checkDefaultSerialize() throws InvalidClassException {
0753 if (defaultSerializeEx != null) {
0754 InvalidClassException ice = new InvalidClassException(
0755 defaultSerializeEx.classname, defaultSerializeEx
0756 .getMessage());
0757 ice.initCause(defaultSerializeEx);
0758 throw ice;
0759 }
0760 }
0761
0762 /**
0763 * Returns superclass descriptor. Note that on the receiving side, the
0764 * superclass descriptor may be bound to a class that is not a superclass
0765 * of the subclass descriptor's bound class.
0766 */
0767 ObjectStreamClass getSuperDesc() {
0768 return super Desc;
0769 }
0770
0771 /**
0772 * Returns the "local" class descriptor for the class associated with this
0773 * class descriptor (i.e., the result of
0774 * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
0775 * associated with this descriptor.
0776 */
0777 ObjectStreamClass getLocalDesc() {
0778 return localDesc;
0779 }
0780
0781 /**
0782 * Returns arrays of ObjectStreamFields representing the serializable
0783 * fields of the represented class. If copy is true, a clone of this class
0784 * descriptor's field array is returned, otherwise the array itself is
0785 * returned.
0786 */
0787 ObjectStreamField[] getFields(boolean copy) {
0788 return copy ? (ObjectStreamField[]) fields.clone() : fields;
0789 }
0790
0791 /**
0792 * Looks up a serializable field of the represented class by name and type.
0793 * A specified type of null matches all types, Object.class matches all
0794 * non-primitive types, and any other non-null type matches assignable
0795 * types only. Returns matching field, or null if no match found.
0796 */
0797 ObjectStreamField getField(String name, Class type) {
0798 for (int i = 0; i < fields.length; i++) {
0799 ObjectStreamField f = fields[i];
0800 if (f.getName().equals(name)) {
0801 if (type == null
0802 || (type == Object.class && !f.isPrimitive())) {
0803 return f;
0804 }
0805 Class ftype = f.getType();
0806 if (ftype != null && type.isAssignableFrom(ftype)) {
0807 return f;
0808 }
0809 }
0810 }
0811 return null;
0812 }
0813
0814 /**
0815 * Returns true if class descriptor represents a dynamic proxy class, false
0816 * otherwise.
0817 */
0818 boolean isProxy() {
0819 return isProxy;
0820 }
0821
0822 /**
0823 * Returns true if class descriptor represents an enum type, false
0824 * otherwise.
0825 */
0826 boolean isEnum() {
0827 return isEnum;
0828 }
0829
0830 /**
0831 * Returns true if represented class implements Externalizable, false
0832 * otherwise.
0833 */
0834 boolean isExternalizable() {
0835 return externalizable;
0836 }
0837
0838 /**
0839 * Returns true if represented class implements Serializable, false
0840 * otherwise.
0841 */
0842 boolean isSerializable() {
0843 return serializable;
0844 }
0845
0846 /**
0847 * Returns true if class descriptor represents externalizable class that
0848 * has written its data in 1.2 (block data) format, false otherwise.
0849 */
0850 boolean hasBlockExternalData() {
0851 return hasBlockExternalData;
0852 }
0853
0854 /**
0855 * Returns true if class descriptor represents serializable (but not
0856 * externalizable) class which has written its data via a custom
0857 * writeObject() method, false otherwise.
0858 */
0859 boolean hasWriteObjectData() {
0860 return hasWriteObjectData;
0861 }
0862
0863 /**
0864 * Returns true if represented class is serializable/externalizable and can
0865 * be instantiated by the serialization runtime--i.e., if it is
0866 * externalizable and defines a public no-arg constructor, or if it is
0867 * non-externalizable and its first non-serializable superclass defines an
0868 * accessible no-arg constructor. Otherwise, returns false.
0869 */
0870 boolean isInstantiable() {
0871 return (cons != null);
0872 }
0873
0874 /**
0875 * Returns true if represented class is serializable (but not
0876 * externalizable) and defines a conformant writeObject method. Otherwise,
0877 * returns false.
0878 */
0879 boolean hasWriteObjectMethod() {
0880 return (writeObjectMethod != null);
0881 }
0882
0883 /**
0884 * Returns true if represented class is serializable (but not
0885 * externalizable) and defines a conformant readObject method. Otherwise,
0886 * returns false.
0887 */
0888 boolean hasReadObjectMethod() {
0889 return (readObjectMethod != null);
0890 }
0891
0892 /**
0893 * Returns true if represented class is serializable (but not
0894 * externalizable) and defines a conformant readObjectNoData method.
0895 * Otherwise, returns false.
0896 */
0897 boolean hasReadObjectNoDataMethod() {
0898 return (readObjectNoDataMethod != null);
0899 }
0900
0901 /**
0902 * Returns true if represented class is serializable or externalizable and
0903 * defines a conformant writeReplace method. Otherwise, returns false.
0904 */
0905 boolean hasWriteReplaceMethod() {
0906 return (writeReplaceMethod != null);
0907 }
0908
0909 /**
0910 * Returns true if represented class is serializable or externalizable and
0911 * defines a conformant readResolve method. Otherwise, returns false.
0912 */
0913 boolean hasReadResolveMethod() {
0914 return (readResolveMethod != null);
0915 }
0916
0917 /**
0918 * Creates a new instance of the represented class. If the class is
0919 * externalizable, invokes its public no-arg constructor; otherwise, if the
0920 * class is serializable, invokes the no-arg constructor of the first
0921 * non-serializable superclass. Throws UnsupportedOperationException if
0922 * this class descriptor is not associated with a class, if the associated
0923 * class is non-serializable or if the appropriate no-arg constructor is
0924 * inaccessible/unavailable.
0925 */
0926 Object newInstance() throws InstantiationException,
0927 InvocationTargetException, UnsupportedOperationException {
0928 if (cons != null) {
0929 try {
0930 return cons.newInstance();
0931 } catch (IllegalAccessException ex) {
0932 // should not occur, as access checks have been suppressed
0933 throw new InternalError();
0934 }
0935 } else {
0936 throw new UnsupportedOperationException();
0937 }
0938 }
0939
0940 /**
0941 * Invokes the writeObject method of the represented serializable class.
0942 * Throws UnsupportedOperationException if this class descriptor is not
0943 * associated with a class, or if the class is externalizable,
0944 * non-serializable or does not define writeObject.
0945 */
0946 void invokeWriteObject(Object obj, ObjectOutputStream out)
0947 throws IOException, UnsupportedOperationException {
0948 if (writeObjectMethod != null) {
0949 try {
0950 writeObjectMethod.invoke(obj, new Object[] { out });
0951 } catch (InvocationTargetException ex) {
0952 Throwable th = ex.getTargetException();
0953 if (th instanceof IOException) {
0954 throw (IOException) th;
0955 } else {
0956 throwMiscException(th);
0957 }
0958 } catch (IllegalAccessException ex) {
0959 // should not occur, as access checks have been suppressed
0960 throw new InternalError();
0961 }
0962 } else {
0963 throw new UnsupportedOperationException();
0964 }
0965 }
0966
0967 /**
0968 * Invokes the readObject method of the represented serializable class.
0969 * Throws UnsupportedOperationException if this class descriptor is not
0970 * associated with a class, or if the class is externalizable,
0971 * non-serializable or does not define readObject.
0972 */
0973 void invokeReadObject(Object obj, ObjectInputStream in)
0974 throws ClassNotFoundException, IOException,
0975 UnsupportedOperationException {
0976 if (readObjectMethod != null) {
0977 try {
0978 readObjectMethod.invoke(obj, new Object[] { in });
0979 } catch (InvocationTargetException ex) {
0980 Throwable th = ex.getTargetException();
0981 if (th instanceof ClassNotFoundException) {
0982 throw (ClassNotFoundException) th;
0983 } else if (th instanceof IOException) {
0984 throw (IOException) th;
0985 } else {
0986 throwMiscException(th);
0987 }
0988 } catch (IllegalAccessException ex) {
0989 // should not occur, as access checks have been suppressed
0990 throw new InternalError();
0991 }
0992 } else {
0993 throw new UnsupportedOperationException();
0994 }
0995 }
0996
0997 /**
0998 * Invokes the readObjectNoData method of the represented serializable
0999 * class. Throws UnsupportedOperationException if this class descriptor is
1000 * not associated with a class, or if the class is externalizable,
1001 * non-serializable or does not define readObjectNoData.
1002 */
1003 void invokeReadObjectNoData(Object obj) throws IOException,
1004 UnsupportedOperationException {
1005 if (readObjectNoDataMethod != null) {
1006 try {
1007 readObjectNoDataMethod.invoke(obj, (Object[]) null);
1008 } catch (InvocationTargetException ex) {
1009 Throwable th = ex.getTargetException();
1010 if (th instanceof ObjectStreamException) {
1011 throw (ObjectStreamException) th;
1012 } else {
1013 throwMiscException(th);
1014 }
1015 } catch (IllegalAccessException ex) {
1016 // should not occur, as access checks have been suppressed
1017 throw new InternalError();
1018 }
1019 } else {
1020 throw new UnsupportedOperationException();
1021 }
1022 }
1023
1024 /**
1025 * Invokes the writeReplace method of the represented serializable class and
1026 * returns the result. Throws UnsupportedOperationException if this class
1027 * descriptor is not associated with a class, or if the class is
1028 * non-serializable or does not define writeReplace.
1029 */
1030 Object invokeWriteReplace(Object obj) throws IOException,
1031 UnsupportedOperationException {
1032 if (writeReplaceMethod != null) {
1033 try {
1034 return writeReplaceMethod.invoke(obj, (Object[]) null);
1035 } catch (InvocationTargetException ex) {
1036 Throwable th = ex.getTargetException();
1037 if (th instanceof ObjectStreamException) {
1038 throw (ObjectStreamException) th;
1039 } else {
1040 throwMiscException(th);
1041 throw new InternalError(); // never reached
1042 }
1043 } catch (IllegalAccessException ex) {
1044 // should not occur, as access checks have been suppressed
1045 throw new InternalError();
1046 }
1047 } else {
1048 throw new UnsupportedOperationException();
1049 }
1050 }
1051
1052 /**
1053 * Invokes the readResolve method of the represented serializable class and
1054 * returns the result. Throws UnsupportedOperationException if this class
1055 * descriptor is not associated with a class, or if the class is
1056 * non-serializable or does not define readResolve.
1057 */
1058 Object invokeReadResolve(Object obj) throws IOException,
1059 UnsupportedOperationException {
1060 if (readResolveMethod != null) {
1061 try {
1062 return readResolveMethod.invoke(obj, (Object[]) null);
1063 } catch (InvocationTargetException ex) {
1064 Throwable th = ex.getTargetException();
1065 if (th instanceof ObjectStreamException) {
1066 throw (ObjectStreamException) th;
1067 } else {
1068 throwMiscException(th);
1069 throw new InternalError(); // never reached
1070 }
1071 } catch (IllegalAccessException ex) {
1072 // should not occur, as access checks have been suppressed
1073 throw new InternalError();
1074 }
1075 } else {
1076 throw new UnsupportedOperationException();
1077 }
1078 }
1079
1080 /**
1081 * Class representing the portion of an object's serialized form allotted
1082 * to data described by a given class descriptor. If "hasData" is false,
1083 * the object's serialized form does not contain data associated with the
1084 * class descriptor.
1085 */
1086 static class ClassDataSlot {
1087
1088 /** class descriptor "occupying" this slot */
1089 final ObjectStreamClass desc;
1090 /** true if serialized form includes data for this slot's descriptor */
1091 final boolean hasData;
1092
1093 ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
1094 this .desc = desc;
1095 this .hasData = hasData;
1096 }
1097 }
1098
1099 /**
1100 * Returns array of ClassDataSlot instances representing the data layout
1101 * (including superclass data) for serialized objects described by this
1102 * class descriptor. ClassDataSlots are ordered by inheritance with those
1103 * containing "higher" superclasses appearing first. The final
1104 * ClassDataSlot contains a reference to this descriptor.
1105 */
1106 ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
1107 // REMIND: synchronize instead of relying on volatile?
1108 if (dataLayout == null) {
1109 dataLayout = getClassDataLayout0();
1110 }
1111 return dataLayout;
1112 }
1113
1114 private ClassDataSlot[] getClassDataLayout0()
1115 throws InvalidClassException {
1116 ArrayList slots = new ArrayList();
1117 Class start = cl, end = cl;
1118
1119 // locate closest non-serializable superclass
1120 while (end != null && Serializable.class.isAssignableFrom(end)) {
1121 end = end.getSuperclass();
1122 }
1123
1124 for (ObjectStreamClass d = this ; d != null; d = d.super Desc) {
1125
1126 // search up inheritance hierarchy for class with matching name
1127 String searchName = (d.cl != null) ? d.cl.getName()
1128 : d.name;
1129 Class match = null;
1130 for (Class c = start; c != end; c = c.getSuperclass()) {
1131 if (searchName.equals(c.getName())) {
1132 match = c;
1133 break;
1134 }
1135 }
1136
1137 // add "no data" slot for each unmatched class below match
1138 if (match != null) {
1139 for (Class c = start; c != match; c = c.getSuperclass()) {
1140 slots.add(new ClassDataSlot(ObjectStreamClass
1141 .lookup(c, true), false));
1142 }
1143 start = match.getSuperclass();
1144 }
1145
1146 // record descriptor/class pairing
1147 slots.add(new ClassDataSlot(d.getVariantFor(match), true));
1148 }
1149
1150 // add "no data" slot for any leftover unmatched classes
1151 for (Class c = start; c != end; c = c.getSuperclass()) {
1152 slots.add(new ClassDataSlot(ObjectStreamClass.lookup(c,
1153 true), false));
1154 }
1155
1156 // order slots from superclass -> subclass
1157 Collections.reverse(slots);
1158 return (ClassDataSlot[]) slots.toArray(new ClassDataSlot[slots
1159 .size()]);
1160 }
1161
1162 /**
1163 * Returns aggregate size (in bytes) of marshalled primitive field values
1164 * for represented class.
1165 */
1166 int getPrimDataSize() {
1167 return primDataSize;
1168 }
1169
1170 /**
1171 * Returns number of non-primitive serializable fields of represented
1172 * class.
1173 */
1174 int getNumObjFields() {
1175 return numObjFields;
1176 }
1177
1178 /**
1179 * Fetches the serializable primitive field values of object obj and
1180 * marshals them into byte array buf starting at offset 0. It is the
1181 * responsibility of the caller to ensure that obj is of the proper type if
1182 * non-null.
1183 */
1184 void getPrimFieldValues(Object obj, byte[] buf) {
1185 fieldRefl.getPrimFieldValues(obj, buf);
1186 }
1187
1188 /**
1189 * Sets the serializable primitive fields of object obj using values
1190 * unmarshalled from byte array buf starting at offset 0. It is the
1191 * responsibility of the caller to ensure that obj is of the proper type if
1192 * non-null.
1193 */
1194 void setPrimFieldValues(Object obj, byte[] buf) {
1195 fieldRefl.setPrimFieldValues(obj, buf);
1196 }
1197
1198 /**
1199 * Fetches the serializable object field values of object obj and stores
1200 * them in array vals starting at offset 0. It is the responsibility of
1201 * the caller to ensure that obj is of the proper type if non-null.
1202 */
1203 void getObjFieldValues(Object obj, Object[] vals) {
1204 fieldRefl.getObjFieldValues(obj, vals);
1205 }
1206
1207 /**
1208 * Sets the serializable object fields of object obj using values from
1209 * array vals starting at offset 0. It is the responsibility of the caller
1210 * to ensure that obj is of the proper type if non-null.
1211 */
1212 void setObjFieldValues(Object obj, Object[] vals) {
1213 fieldRefl.setObjFieldValues(obj, vals);
1214 }
1215
1216 /**
1217 * Calculates and sets serializable field offsets, as well as primitive
1218 * data size and object field count totals. Throws InvalidClassException
1219 * if fields are illegally ordered.
1220 */
1221 private void computeFieldOffsets() throws InvalidClassException {
1222 primDataSize = 0;
1223 numObjFields = 0;
1224 int firstObjIndex = -1;
1225
1226 for (int i = 0; i < fields.length; i++) {
1227 ObjectStreamField f = fields[i];
1228 switch (f.getTypeCode()) {
1229 case 'Z':
1230 case 'B':
1231 f.setOffset(primDataSize++);
1232 break;
1233
1234 case 'C':
1235 case 'S':
1236 f.setOffset(primDataSize);
1237 primDataSize += 2;
1238 break;
1239
1240 case 'I':
1241 case 'F':
1242 f.setOffset(primDataSize);
1243 primDataSize += 4;
1244 break;
1245
1246 case 'J':
1247 case 'D':
1248 f.setOffset(primDataSize);
1249 primDataSize += 8;
1250 break;
1251
1252 case '[':
1253 case 'L':
1254 f.setOffset(numObjFields++);
1255 if (firstObjIndex == -1) {
1256 firstObjIndex = i;
1257 }
1258 break;
1259
1260 default:
1261 throw new InternalError();
1262 }
1263 }
1264 if (firstObjIndex != -1
1265 && firstObjIndex + numObjFields != fields.length) {
1266 throw new InvalidClassException(name, "illegal field order");
1267 }
1268 }
1269
1270 /**
1271 * If given class is the same as the class associated with this class
1272 * descriptor, returns reference to this class descriptor. Otherwise,
1273 * returns variant of this class descriptor bound to given class.
1274 */
1275 private ObjectStreamClass getVariantFor(Class cl)
1276 throws InvalidClassException {
1277 if (this .cl == cl) {
1278 return this ;
1279 }
1280 ObjectStreamClass desc = new ObjectStreamClass();
1281 if (isProxy) {
1282 desc.initProxy(cl, null, super Desc);
1283 } else {
1284 desc.initNonProxy(this , cl, null, super Desc);
1285 }
1286 return desc;
1287 }
1288
1289 /**
1290 * Returns public no-arg constructor of given class, or null if none found.
1291 * Access checks are disabled on the returned constructor (if any), since
1292 * the defining class may still be non-public.
1293 */
1294 private static Constructor getExternalizableConstructor(Class cl) {
1295 try {
1296 Constructor cons = cl
1297 .getDeclaredConstructor((Class[]) null);
1298 cons.setAccessible(true);
1299 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? cons
1300 : null;
1301 } catch (NoSuchMethodException ex) {
1302 return null;
1303 }
1304 }
1305
1306 /**
1307 * Returns subclass-accessible no-arg constructor of first non-serializable
1308 * superclass, or null if none found. Access checks are disabled on the
1309 * returned constructor (if any).
1310 */
1311 private static Constructor getSerializableConstructor(Class cl) {
1312 Class initCl = cl;
1313 while (Serializable.class.isAssignableFrom(initCl)) {
1314 if ((initCl = initCl.getSuperclass()) == null) {
1315 return null;
1316 }
1317 }
1318 try {
1319 Constructor cons = initCl
1320 .getDeclaredConstructor((Class[]) null);
1321 int mods = cons.getModifiers();
1322 if ((mods & Modifier.PRIVATE) != 0
1323 || ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 && !packageEquals(
1324 cl, initCl))) {
1325 return null;
1326 }
1327 cons = reflFactory.newConstructorForSerialization(cl, cons);
1328 cons.setAccessible(true);
1329 return cons;
1330 } catch (NoSuchMethodException ex) {
1331 return null;
1332 }
1333 }
1334
1335 /**
1336 * Returns non-static, non-abstract method with given signature provided it
1337 * is defined by or accessible (via inheritance) by the given class, or
1338 * null if no match found. Access checks are disabled on the returned
1339 * method (if any).
1340 */
1341 private static Method getInheritableMethod(Class cl, String name,
1342 Class[] argTypes, Class returnType) {
1343 Method meth = null;
1344 Class defCl = cl;
1345 while (defCl != null) {
1346 try {
1347 meth = defCl.getDeclaredMethod(name, argTypes);
1348 break;
1349 } catch (NoSuchMethodException ex) {
1350 defCl = defCl.getSuperclass();
1351 }
1352 }
1353
1354 if ((meth == null) || (meth.getReturnType() != returnType)) {
1355 return null;
1356 }
1357 meth.setAccessible(true);
1358 int mods = meth.getModifiers();
1359 if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
1360 return null;
1361 } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
1362 return meth;
1363 } else if ((mods & Modifier.PRIVATE) != 0) {
1364 return (cl == defCl) ? meth : null;
1365 } else {
1366 return packageEquals(cl, defCl) ? meth : null;
1367 }
1368 }
1369
1370 /**
1371 * Returns non-static private method with given signature defined by given
1372 * class, or null if none found. Access checks are disabled on the
1373 * returned method (if any).
1374 */
1375 private static Method getPrivateMethod(Class cl, String name,
1376 Class[] argTypes, Class returnType) {
1377 try {
1378 Method meth = cl.getDeclaredMethod(name, argTypes);
1379 meth.setAccessible(true);
1380 int mods = meth.getModifiers();
1381 return ((meth.getReturnType() == returnType)
1382 && ((mods & Modifier.STATIC) == 0) && ((mods & Modifier.PRIVATE) != 0)) ? meth
1383 : null;
1384 } catch (NoSuchMethodException ex) {
1385 return null;
1386 }
1387 }
1388
1389 /**
1390 * Returns true if classes are defined in the same runtime package, false
1391 * otherwise.
1392 */
1393 private static boolean packageEquals(Class cl1, Class cl2) {
1394 return (cl1.getClassLoader() == cl2.getClassLoader() && getPackageName(
1395 cl1).equals(getPackageName(cl2)));
1396 }
1397
1398 /**
1399 * Returns package name of given class.
1400 */
1401 private static String getPackageName(Class cl) {
1402 String s = cl.getName();
1403 int i = s.lastIndexOf('[');
1404 if (i >= 0) {
1405 s = s.substring(i + 2);
1406 }
1407 i = s.lastIndexOf('.');
1408 return (i >= 0) ? s.substring(0, i) : "";
1409 }
1410
1411 /**
1412 * Compares class names for equality, ignoring package names. Returns true
1413 * if class names equal, false otherwise.
1414 */
1415 private static boolean classNamesEqual(String name1, String name2) {
1416 name1 = name1.substring(name1.lastIndexOf('.') + 1);
1417 name2 = name2.substring(name2.lastIndexOf('.') + 1);
1418 return name1.equals(name2);
1419 }
1420
1421 /**
1422 * Returns JVM type signature for given class.
1423 */
1424 static String getClassSignature(Class cl) {
1425 StringBuilder sbuf = new StringBuilder();
1426 while (cl.isArray()) {
1427 sbuf.append('[');
1428 cl = cl.getComponentType();
1429 }
1430 if (cl.isPrimitive()) {
1431 if (cl == Integer.TYPE) {
1432 sbuf.append('I');
1433 } else if (cl == Byte.TYPE) {
1434 sbuf.append('B');
1435 } else if (cl == Long.TYPE) {
1436 sbuf.append('J');
1437 } else if (cl == Float.TYPE) {
1438 sbuf.append('F');
1439 } else if (cl == Double.TYPE) {
1440 sbuf.append('D');
1441 } else if (cl == Short.TYPE) {
1442 sbuf.append('S');
1443 } else if (cl == Character.TYPE) {
1444 sbuf.append('C');
1445 } else if (cl == Boolean.TYPE) {
1446 sbuf.append('Z');
1447 } else if (cl == Void.TYPE) {
1448 sbuf.append('V');
1449 } else {
1450 throw new InternalError();
1451 }
1452 } else {
1453 sbuf.append('L' + cl.getName().replace('.', '/') + ';');
1454 }
1455 return sbuf.toString();
1456 }
1457
1458 /**
1459 * Returns JVM type signature for given list of parameters and return type.
1460 */
1461 private static String getMethodSignature(Class[] paramTypes,
1462 Class retType) {
1463 StringBuilder sbuf = new StringBuilder();
1464 sbuf.append('(');
1465 for (int i = 0; i < paramTypes.length; i++) {
1466 sbuf.append(getClassSignature(paramTypes[i]));
1467 }
1468 sbuf.append(')');
1469 sbuf.append(getClassSignature(retType));
1470 return sbuf.toString();
1471 }
1472
1473 /**
1474 * Convenience method for throwing an exception that is either a
1475 * RuntimeException, Error, or of some unexpected type (in which case it is
1476 * wrapped inside an IOException).
1477 */
1478 private static void throwMiscException(Throwable th)
1479 throws IOException {
1480 if (th instanceof RuntimeException) {
1481 throw (RuntimeException) th;
1482 } else if (th instanceof Error) {
1483 throw (Error) th;
1484 } else {
1485 IOException ex = new IOException(
1486 "unexpected exception type");
1487 ex.initCause(th);
1488 throw ex;
1489 }
1490 }
1491
1492 /**
1493 * Returns ObjectStreamField array describing the serializable fields of
1494 * the given class. Serializable fields backed by an actual field of the
1495 * class are represented by ObjectStreamFields with corresponding non-null
1496 * Field objects. Throws InvalidClassException if the (explicitly
1497 * declared) serializable fields are invalid.
1498 */
1499 private static ObjectStreamField[] getSerialFields(Class cl)
1500 throws InvalidClassException {
1501 ObjectStreamField[] fields;
1502 if (Serializable.class.isAssignableFrom(cl)
1503 && !Externalizable.class.isAssignableFrom(cl)
1504 && !Proxy.isProxyClass(cl) && !cl.isInterface()) {
1505 if ((fields = getDeclaredSerialFields(cl)) == null) {
1506 fields = getDefaultSerialFields(cl);
1507 }
1508 Arrays.sort(fields);
1509 } else {
1510 fields = NO_FIELDS;
1511 }
1512 return fields;
1513 }
1514
1515 /**
1516 * Returns serializable fields of given class as defined explicitly by a
1517 * "serialPersistentFields" field, or null if no appropriate
1518 * "serialPersistentFields" field is defined. Serializable fields backed
1519 * by an actual field of the class are represented by ObjectStreamFields
1520 * with corresponding non-null Field objects. For compatibility with past
1521 * releases, a "serialPersistentFields" field with a null value is
1522 * considered equivalent to not declaring "serialPersistentFields". Throws
1523 * InvalidClassException if the declared serializable fields are
1524 * invalid--e.g., if multiple fields share the same name.
1525 */
1526 private static ObjectStreamField[] getDeclaredSerialFields(Class cl)
1527 throws InvalidClassException {
1528 ObjectStreamField[] serialPersistentFields = null;
1529 try {
1530 Field f = cl.getDeclaredField("serialPersistentFields");
1531 int mask = Modifier.PRIVATE | Modifier.STATIC
1532 | Modifier.FINAL;
1533 if ((f.getModifiers() & mask) == mask) {
1534 f.setAccessible(true);
1535 serialPersistentFields = (ObjectStreamField[]) f
1536 .get(null);
1537 }
1538 } catch (Exception ex) {
1539 }
1540 if (serialPersistentFields == null) {
1541 return null;
1542 } else if (serialPersistentFields.length == 0) {
1543 return NO_FIELDS;
1544 }
1545
1546 ObjectStreamField[] boundFields = new ObjectStreamField[serialPersistentFields.length];
1547 Set fieldNames = new HashSet(serialPersistentFields.length);
1548
1549 for (int i = 0; i < serialPersistentFields.length; i++) {
1550 ObjectStreamField spf = serialPersistentFields[i];
1551
1552 String fname = spf.getName();
1553 if (fieldNames.contains(fname)) {
1554 throw new InvalidClassException(
1555 "multiple serializable fields named " + fname);
1556 }
1557 fieldNames.add(fname);
1558
1559 try {
1560 Field f = cl.getDeclaredField(fname);
1561 if ((f.getType() == spf.getType())
1562 && ((f.getModifiers() & Modifier.STATIC) == 0)) {
1563 boundFields[i] = new ObjectStreamField(f, spf
1564 .isUnshared(), true);
1565 }
1566 } catch (NoSuchFieldException ex) {
1567 }
1568 if (boundFields[i] == null) {
1569 boundFields[i] = new ObjectStreamField(fname, spf
1570 .getType(), spf.isUnshared());
1571 }
1572 }
1573 return boundFields;
1574 }
1575
1576 /**
1577 * Returns array of ObjectStreamFields corresponding to all non-static
1578 * non-transient fields declared by given class. Each ObjectStreamField
1579 * contains a Field object for the field it represents. If no default
1580 * serializable fields exist, NO_FIELDS is returned.
1581 */
1582 private static ObjectStreamField[] getDefaultSerialFields(Class cl) {
1583 Field[] clFields = cl.getDeclaredFields();
1584 ArrayList list = new ArrayList();
1585 int mask = Modifier.STATIC | Modifier.TRANSIENT;
1586
1587 for (int i = 0; i < clFields.length; i++) {
1588 if ((clFields[i].getModifiers() & mask) == 0) {
1589 list
1590 .add(new ObjectStreamField(clFields[i], false,
1591 true));
1592 }
1593 }
1594 int size = list.size();
1595 return (size == 0) ? NO_FIELDS : (ObjectStreamField[]) list
1596 .toArray(new ObjectStreamField[size]);
1597 }
1598
1599 /**
1600 * Returns explicit serial version UID value declared by given class, or
1601 * null if none.
1602 */
1603 private static Long getDeclaredSUID(Class cl) {
1604 try {
1605 Field f = cl.getDeclaredField("serialVersionUID");
1606 int mask = Modifier.STATIC | Modifier.FINAL;
1607 if ((f.getModifiers() & mask) == mask) {
1608 f.setAccessible(true);
1609 return Long.valueOf(f.getLong(null));
1610 }
1611 } catch (Exception ex) {
1612 }
1613 return null;
1614 }
1615
1616 /**
1617 * Computes the default serial version UID value for the given class.
1618 */
1619 private static long computeDefaultSUID(Class cl) {
1620 if (!Serializable.class.isAssignableFrom(cl)
1621 || Proxy.isProxyClass(cl)) {
1622 return 0L;
1623 }
1624
1625 try {
1626 ByteArrayOutputStream bout = new ByteArrayOutputStream();
1627 DataOutputStream dout = new DataOutputStream(bout);
1628
1629 dout.writeUTF(cl.getName());
1630
1631 int classMods = cl.getModifiers()
1632 & (Modifier.PUBLIC | Modifier.FINAL
1633 | Modifier.INTERFACE | Modifier.ABSTRACT);
1634
1635 /*
1636 * compensate for javac bug in which ABSTRACT bit was set for an
1637 * interface only if the interface declared methods
1638 */
1639 Method[] methods = cl.getDeclaredMethods();
1640 if ((classMods & Modifier.INTERFACE) != 0) {
1641 classMods = (methods.length > 0) ? (classMods | Modifier.ABSTRACT)
1642 : (classMods & ~Modifier.ABSTRACT);
1643 }
1644 dout.writeInt(classMods);
1645
1646 if (!cl.isArray()) {
1647 /*
1648 * compensate for change in 1.2FCS in which
1649 * Class.getInterfaces() was modified to return Cloneable and
1650 * Serializable for array classes.
1651 */
1652 Class[] interfaces = cl.getInterfaces();
1653 String[] ifaceNames = new String[interfaces.length];
1654 for (int i = 0; i < interfaces.length; i++) {
1655 ifaceNames[i] = interfaces[i].getName();
1656 }
1657 Arrays.sort(ifaceNames);
1658 for (int i = 0; i < ifaceNames.length; i++) {
1659 dout.writeUTF(ifaceNames[i]);
1660 }
1661 }
1662
1663 Field[] fields = cl.getDeclaredFields();
1664 MemberSignature[] fieldSigs = new MemberSignature[fields.length];
1665 for (int i = 0; i < fields.length; i++) {
1666 fieldSigs[i] = new MemberSignature(fields[i]);
1667 }
1668 Arrays.sort(fieldSigs, new Comparator() {
1669 public int compare(Object o1, Object o2) {
1670 String name1 = ((MemberSignature) o1).name;
1671 String name2 = ((MemberSignature) o2).name;
1672 return name1.compareTo(name2);
1673 }
1674 });
1675 for (int i = 0; i < fieldSigs.length; i++) {
1676 MemberSignature sig = fieldSigs[i];
1677 int mods = sig.member.getModifiers()
1678 & (Modifier.PUBLIC | Modifier.PRIVATE
1679 | Modifier.PROTECTED | Modifier.STATIC
1680 | Modifier.FINAL | Modifier.VOLATILE | Modifier.TRANSIENT);
1681 if (((mods & Modifier.PRIVATE) == 0)
1682 || ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) {
1683 dout.writeUTF(sig.name);
1684 dout.writeInt(mods);
1685 dout.writeUTF(sig.signature);
1686 }
1687 }
1688
1689 if (hasStaticInitializer(cl)) {
1690 dout.writeUTF("<clinit>");
1691 dout.writeInt(Modifier.STATIC);
1692 dout.writeUTF("()V");
1693 }
1694
1695 Constructor[] cons = cl.getDeclaredConstructors();
1696 MemberSignature[] consSigs = new MemberSignature[cons.length];
1697 for (int i = 0; i < cons.length; i++) {
1698 consSigs[i] = new MemberSignature(cons[i]);
1699 }
1700 Arrays.sort(consSigs, new Comparator() {
1701 public int compare(Object o1, Object o2) {
1702 String sig1 = ((MemberSignature) o1).signature;
1703 String sig2 = ((MemberSignature) o2).signature;
1704 return sig1.compareTo(sig2);
1705 }
1706 });
1707 for (int i = 0; i < consSigs.length; i++) {
1708 MemberSignature sig = consSigs[i];
1709 int mods = sig.member.getModifiers()
1710 & (Modifier.PUBLIC | Modifier.PRIVATE
1711 | Modifier.PROTECTED | Modifier.STATIC
1712 | Modifier.FINAL
1713 | Modifier.SYNCHRONIZED
1714 | Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT);
1715 if ((mods & Modifier.PRIVATE) == 0) {
1716 dout.writeUTF("<init>");
1717 dout.writeInt(mods);
1718 dout.writeUTF(sig.signature.replace('/', '.'));
1719 }
1720 }
1721
1722 MemberSignature[] methSigs = new MemberSignature[methods.length];
1723 for (int i = 0; i < methods.length; i++) {
1724 methSigs[i] = new MemberSignature(methods[i]);
1725 }
1726 Arrays.sort(methSigs, new Comparator() {
1727 public int compare(Object o1, Object o2) {
1728 MemberSignature ms1 = (MemberSignature) o1;
1729 MemberSignature ms2 = (MemberSignature) o2;
1730 int comp = ms1.name.compareTo(ms2.name);
1731 if (comp == 0) {
1732 comp = ms1.signature.compareTo(ms2.signature);
1733 }
1734 return comp;
1735 }
1736 });
1737 for (int i = 0; i < methSigs.length; i++) {
1738 MemberSignature sig = methSigs[i];
1739 int mods = sig.member.getModifiers()
1740 & (Modifier.PUBLIC | Modifier.PRIVATE
1741 | Modifier.PROTECTED | Modifier.STATIC
1742 | Modifier.FINAL
1743 | Modifier.SYNCHRONIZED
1744 | Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT);
1745 if ((mods & Modifier.PRIVATE) == 0) {
1746 dout.writeUTF(sig.name);
1747 dout.writeInt(mods);
1748 dout.writeUTF(sig.signature.replace('/', '.'));
1749 }
1750 }
1751
1752 dout.flush();
1753
1754 MessageDigest md = MessageDigest.getInstance("SHA");
1755 byte[] hashBytes = md.digest(bout.toByteArray());
1756 long hash = 0;
1757 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
1758 hash = (hash << 8) | (hashBytes[i] & 0xFF);
1759 }
1760 return hash;
1761 } catch (IOException ex) {
1762 throw new InternalError();
1763 } catch (NoSuchAlgorithmException ex) {
1764 throw new SecurityException(ex.getMessage());
1765 }
1766 }
1767
1768 /**
1769 * Returns true if the given class defines a static initializer method,
1770 * false otherwise.
1771 */
1772 private native static boolean hasStaticInitializer(Class cl);
1773
1774 /**
1775 * Class for computing and caching field/constructor/method signatures
1776 * during serialVersionUID calculation.
1777 */
1778 private static class MemberSignature {
1779
1780 public final Member member;
1781 public final String name;
1782 public final String signature;
1783
1784 public MemberSignature(Field field) {
1785 member = field;
1786 name = field.getName();
1787 signature = getClassSignature(field.getType());
1788 }
1789
1790 public MemberSignature(Constructor cons) {
1791 member = cons;
1792 name = cons.getName();
1793 signature = getMethodSignature(cons.getParameterTypes(),
1794 Void.TYPE);
1795 }
1796
1797 public MemberSignature(Method meth) {
1798 member = meth;
1799 name = meth.getName();
1800 signature = getMethodSignature(meth.getParameterTypes(),
1801 meth.getReturnType());
1802 }
1803 }
1804
1805 /**
1806 * Class for setting and retrieving serializable field values in batch.
1807 */
1808 // REMIND: dynamically generate these?
1809 private static class FieldReflector {
1810
1811 /** handle for performing unsafe operations */
1812 private static final Unsafe unsafe = Unsafe.getUnsafe();
1813
1814 /** fields to operate on */
1815 private final ObjectStreamField[] fields;
1816 /** number of primitive fields */
1817 private final int numPrimFields;
1818 /** unsafe field keys */
1819 private final long[] keys;
1820 /** field data offsets */
1821 private final int[] offsets;
1822 /** field type codes */
1823 private final char[] typeCodes;
1824 /** field types */
1825 private final Class[] types;
1826
1827 /**
1828 * Constructs FieldReflector capable of setting/getting values from the
1829 * subset of fields whose ObjectStreamFields contain non-null
1830 * reflective Field objects. ObjectStreamFields with null Fields are
1831 * treated as filler, for which get operations return default values
1832 * and set operations discard given values.
1833 */
1834 FieldReflector(ObjectStreamField[] fields) {
1835 this .fields = fields;
1836 int nfields = fields.length;
1837 keys = new long[nfields];
1838 offsets = new int[nfields];
1839 typeCodes = new char[nfields];
1840 ArrayList typeList = new ArrayList();
1841
1842 for (int i = 0; i < nfields; i++) {
1843 ObjectStreamField f = fields[i];
1844 Field rf = f.getField();
1845 keys[i] = (rf != null) ? unsafe.objectFieldOffset(rf)
1846 : Unsafe.INVALID_FIELD_OFFSET;
1847 offsets[i] = f.getOffset();
1848 typeCodes[i] = f.getTypeCode();
1849 if (!f.isPrimitive()) {
1850 typeList.add((rf != null) ? rf.getType() : null);
1851 }
1852 }
1853
1854 types = (Class[]) typeList.toArray(new Class[typeList
1855 .size()]);
1856 numPrimFields = nfields - types.length;
1857 }
1858
1859 /**
1860 * Returns list of ObjectStreamFields representing fields operated on
1861 * by this reflector. The shared/unshared values and Field objects
1862 * contained by ObjectStreamFields in the list reflect their bindings
1863 * to locally defined serializable fields.
1864 */
1865 ObjectStreamField[] getFields() {
1866 return fields;
1867 }
1868
1869 /**
1870 * Fetches the serializable primitive field values of object obj and
1871 * marshals them into byte array buf starting at offset 0. The caller
1872 * is responsible for ensuring that obj is of the proper type.
1873 */
1874 void getPrimFieldValues(Object obj, byte[] buf) {
1875 if (obj == null) {
1876 throw new NullPointerException();
1877 }
1878 /* assuming checkDefaultSerialize() has been called on the class
1879 * descriptor this FieldReflector was obtained from, no field keys
1880 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
1881 */
1882 for (int i = 0; i < numPrimFields; i++) {
1883 long key = keys[i];
1884 int off = offsets[i];
1885 switch (typeCodes[i]) {
1886 case 'Z':
1887 Bits.putBoolean(buf, off, unsafe.getBoolean(obj,
1888 key));
1889 break;
1890
1891 case 'B':
1892 buf[off] = unsafe.getByte(obj, key);
1893 break;
1894
1895 case 'C':
1896 Bits.putChar(buf, off, unsafe.getChar(obj, key));
1897 break;
1898
1899 case 'S':
1900 Bits.putShort(buf, off, unsafe.getShort(obj, key));
1901 break;
1902
1903 case 'I':
1904 Bits.putInt(buf, off, unsafe.getInt(obj, key));
1905 break;
1906
1907 case 'F':
1908 Bits.putFloat(buf, off, unsafe.getFloat(obj, key));
1909 break;
1910
1911 case 'J':
1912 Bits.putLong(buf, off, unsafe.getLong(obj, key));
1913 break;
1914
1915 case 'D':
1916 Bits
1917 .putDouble(buf, off, unsafe.getDouble(obj,
1918 key));
1919 break;
1920
1921 default:
1922 throw new InternalError();
1923 }
1924 }
1925 }
1926
1927 /**
1928 * Sets the serializable primitive fields of object obj using values
1929 * unmarshalled from byte array buf starting at offset 0. The caller
1930 * is responsible for ensuring that obj is of the proper type.
1931 */
1932 void setPrimFieldValues(Object obj, byte[] buf) {
1933 if (obj == null) {
1934 throw new NullPointerException();
1935 }
1936 for (int i = 0; i < numPrimFields; i++) {
1937 long key = keys[i];
1938 if (key == Unsafe.INVALID_FIELD_OFFSET) {
1939 continue; // discard value
1940 }
1941 int off = offsets[i];
1942 switch (typeCodes[i]) {
1943 case 'Z':
1944 unsafe.putBoolean(obj, key, Bits.getBoolean(buf,
1945 off));
1946 break;
1947
1948 case 'B':
1949 unsafe.putByte(obj, key, buf[off]);
1950 break;
1951
1952 case 'C':
1953 unsafe.putChar(obj, key, Bits.getChar(buf, off));
1954 break;
1955
1956 case 'S':
1957 unsafe.putShort(obj, key, Bits.getShort(buf, off));
1958 break;
1959
1960 case 'I':
1961 unsafe.putInt(obj, key, Bits.getInt(buf, off));
1962 break;
1963
1964 case 'F':
1965 unsafe.putFloat(obj, key, Bits.getFloat(buf, off));
1966 break;
1967
1968 case 'J':
1969 unsafe.putLong(obj, key, Bits.getLong(buf, off));
1970 break;
1971
1972 case 'D':
1973 unsafe
1974 .putDouble(obj, key, Bits.getDouble(buf,
1975 off));
1976 break;
1977
1978 default:
1979 throw new InternalError();
1980 }
1981 }
1982 }
1983
1984 /**
1985 * Fetches the serializable object field values of object obj and
1986 * stores them in array vals starting at offset 0. The caller is
1987 * responsible for ensuring that obj is of the proper type.
1988 */
1989 void getObjFieldValues(Object obj, Object[] vals) {
1990 if (obj == null) {
1991 throw new NullPointerException();
1992 }
1993 /* assuming checkDefaultSerialize() has been called on the class
1994 * descriptor this FieldReflector was obtained from, no field keys
1995 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
1996 */
1997 for (int i = numPrimFields; i < fields.length; i++) {
1998 switch (typeCodes[i]) {
1999 case 'L':
2000 case '[':
2001 vals[offsets[i]] = unsafe.getObject(obj, keys[i]);
2002 break;
2003
2004 default:
2005 throw new InternalError();
2006 }
2007 }
2008 }
2009
2010 /**
2011 * Sets the serializable object fields of object obj using values from
2012 * array vals starting at offset 0. The caller is responsible for
2013 * ensuring that obj is of the proper type; however, attempts to set a
2014 * field with a value of the wrong type will trigger an appropriate
2015 * ClassCastException.
2016 */
2017 void setObjFieldValues(Object obj, Object[] vals) {
2018 if (obj == null) {
2019 throw new NullPointerException();
2020 }
2021 for (int i = numPrimFields; i < fields.length; i++) {
2022 long key = keys[i];
2023 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2024 continue; // discard value
2025 }
2026 switch (typeCodes[i]) {
2027 case 'L':
2028 case '[':
2029 Object val = vals[offsets[i]];
2030 if (val != null
2031 && !types[i - numPrimFields]
2032 .isInstance(val)) {
2033 Field f = fields[i].getField();
2034 throw new ClassCastException(
2035 "cannot assign instance of "
2036 + val.getClass().getName()
2037 + " to field "
2038 + f.getDeclaringClass()
2039 .getName() + "."
2040 + f.getName() + " of type "
2041 + f.getType().getName()
2042 + " in instance of "
2043 + obj.getClass().getName());
2044 }
2045 unsafe.putObject(obj, key, val);
2046 break;
2047
2048 default:
2049 throw new InternalError();
2050 }
2051 }
2052 }
2053 }
2054
2055 /**
2056 * Matches given set of serializable fields with serializable fields
2057 * described by the given local class descriptor, and returns a
2058 * FieldReflector instance capable of setting/getting values from the
2059 * subset of fields that match (non-matching fields are treated as filler,
2060 * for which get operations return default values and set operations
2061 * discard given values). Throws InvalidClassException if unresolvable
2062 * type conflicts exist between the two sets of fields.
2063 */
2064 private static FieldReflector getReflector(
2065 ObjectStreamField[] fields, ObjectStreamClass localDesc)
2066 throws InvalidClassException {
2067 // class irrelevant if no fields
2068 Class cl = (localDesc != null && fields.length > 0) ? localDesc.cl
2069 : null;
2070 processQueue(Caches.reflectorsQueue, Caches.reflectors);
2071 FieldReflectorKey key = new FieldReflectorKey(cl, fields,
2072 Caches.reflectorsQueue);
2073 Reference<?> ref = Caches.reflectors.get(key);
2074 Object entry = null;
2075 if (ref != null) {
2076 entry = ref.get();
2077 }
2078 EntryFuture future = null;
2079 if (entry == null) {
2080 EntryFuture newEntry = new EntryFuture();
2081 Reference<?> newRef = new SoftReference<EntryFuture>(
2082 newEntry);
2083 do {
2084 if (ref != null) {
2085 Caches.reflectors.remove(key, ref);
2086 }
2087 ref = Caches.reflectors.putIfAbsent(key, newRef);
2088 if (ref != null) {
2089 entry = ref.get();
2090 }
2091 } while (ref != null && entry == null);
2092 if (entry == null) {
2093 future = newEntry;
2094 }
2095 }
2096
2097 if (entry instanceof FieldReflector) { // check common case first
2098 return (FieldReflector) entry;
2099 } else if (entry instanceof EntryFuture) {
2100 entry = ((EntryFuture) entry).get();
2101 } else if (entry == null) {
2102 try {
2103 entry = new FieldReflector(matchFields(fields,
2104 localDesc));
2105 } catch (Throwable th) {
2106 entry = th;
2107 }
2108 future.set(entry);
2109 Caches.reflectors
2110 .put(key, new SoftReference<Object>(entry));
2111 }
2112
2113 if (entry instanceof FieldReflector) {
2114 return (FieldReflector) entry;
2115 } else if (entry instanceof InvalidClassException) {
2116 throw (InvalidClassException) entry;
2117 } else if (entry instanceof RuntimeException) {
2118 throw (RuntimeException) entry;
2119 } else if (entry instanceof Error) {
2120 throw (Error) entry;
2121 } else {
2122 throw new InternalError("unexpected entry: " + entry);
2123 }
2124 }
2125
2126 /**
2127 * FieldReflector cache lookup key. Keys are considered equal if they
2128 * refer to the same class and equivalent field formats.
2129 */
2130 private static class FieldReflectorKey extends
2131 WeakReference<Class<?>> {
2132
2133 private final String sigs;
2134 private final int hash;
2135 private final boolean nullClass;
2136
2137 FieldReflectorKey(Class cl, ObjectStreamField[] fields,
2138 ReferenceQueue<Class<?>> queue) {
2139 super (cl, queue);
2140 nullClass = (cl == null);
2141 StringBuilder sbuf = new StringBuilder();
2142 for (int i = 0; i < fields.length; i++) {
2143 ObjectStreamField f = fields[i];
2144 sbuf.append(f.getName()).append(f.getSignature());
2145 }
2146 sigs = sbuf.toString();
2147 hash = System.identityHashCode(cl) + sigs.hashCode();
2148 }
2149
2150 public int hashCode() {
2151 return hash;
2152 }
2153
2154 public boolean equals(Object obj) {
2155 if (obj == this ) {
2156 return true;
2157 }
2158
2159 if (obj instanceof FieldReflectorKey) {
2160 FieldReflectorKey other = (FieldReflectorKey) obj;
2161 Class<?> referent;
2162 return (nullClass ? other.nullClass
2163 : ((referent = get()) != null)
2164 && (referent == other.get()))
2165 && sigs.equals(other.sigs);
2166 } else {
2167 return false;
2168 }
2169 }
2170 }
2171
2172 /**
2173 * Matches given set of serializable fields with serializable fields
2174 * obtained from the given local class descriptor (which contain bindings
2175 * to reflective Field objects). Returns list of ObjectStreamFields in
2176 * which each ObjectStreamField whose signature matches that of a local
2177 * field contains a Field object for that field; unmatched
2178 * ObjectStreamFields contain null Field objects. Shared/unshared settings
2179 * of the returned ObjectStreamFields also reflect those of matched local
2180 * ObjectStreamFields. Throws InvalidClassException if unresolvable type
2181 * conflicts exist between the two sets of fields.
2182 */
2183 private static ObjectStreamField[] matchFields(
2184 ObjectStreamField[] fields, ObjectStreamClass localDesc)
2185 throws InvalidClassException {
2186 ObjectStreamField[] localFields = (localDesc != null) ? localDesc.fields
2187 : NO_FIELDS;
2188
2189 /*
2190 * Even if fields == localFields, we cannot simply return localFields
2191 * here. In previous implementations of serialization,
2192 * ObjectStreamField.getType() returned Object.class if the
2193 * ObjectStreamField represented a non-primitive field and belonged to
2194 * a non-local class descriptor. To preserve this (questionable)
2195 * behavior, the ObjectStreamField instances returned by matchFields
2196 * cannot report non-primitive types other than Object.class; hence
2197 * localFields cannot be returned directly.
2198 */
2199
2200 ObjectStreamField[] matches = new ObjectStreamField[fields.length];
2201 for (int i = 0; i < fields.length; i++) {
2202 ObjectStreamField f = fields[i], m = null;
2203 for (int j = 0; j < localFields.length; j++) {
2204 ObjectStreamField lf = localFields[j];
2205 if (f.getName().equals(lf.getName())) {
2206 if ((f.isPrimitive() || lf.isPrimitive())
2207 && f.getTypeCode() != lf.getTypeCode()) {
2208 throw new InvalidClassException(localDesc.name,
2209 "incompatible types for field "
2210 + f.getName());
2211 }
2212 if (lf.getField() != null) {
2213 m = new ObjectStreamField(lf.getField(), lf
2214 .isUnshared(), false);
2215 } else {
2216 m = new ObjectStreamField(lf.getName(), lf
2217 .getSignature(), lf.isUnshared());
2218 }
2219 }
2220 }
2221 if (m == null) {
2222 m = new ObjectStreamField(f.getName(),
2223 f.getSignature(), false);
2224 }
2225 m.setOffset(f.getOffset());
2226 matches[i] = m;
2227 }
2228 return matches;
2229 }
2230
2231 /**
2232 * Removes from the specified map any keys that have been enqueued
2233 * on the specified reference queue.
2234 */
2235 static void processQueue(ReferenceQueue<Class<?>> queue,
2236 ConcurrentMap<? extends WeakReference<Class<?>>, ?> map) {
2237 Reference<? extends Class<?>> ref;
2238 while ((ref = queue.poll()) != null) {
2239 map.remove(ref);
2240 }
2241 }
2242
2243 /**
2244 * Weak key for Class objects.
2245 *
2246 **/
2247 static class WeakClassKey extends WeakReference<Class<?>> {
2248 /**
2249 * saved value of the referent's identity hash code, to maintain
2250 * a consistent hash code after the referent has been cleared
2251 */
2252 private final int hash;
2253
2254 /**
2255 * Create a new WeakClassKey to the given object, registered
2256 * with a queue.
2257 */
2258 WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
2259 super (cl, refQueue);
2260 hash = System.identityHashCode(cl);
2261 }
2262
2263 /**
2264 * Returns the identity hash code of the original referent.
2265 */
2266 public int hashCode() {
2267 return hash;
2268 }
2269
2270 /**
2271 * Returns true if the given object is this identical
2272 * WeakClassKey instance, or, if this object's referent has not
2273 * been cleared, if the given object is another WeakClassKey
2274 * instance with the identical non-null referent as this one.
2275 */
2276 public boolean equals(Object obj) {
2277 if (obj == this ) {
2278 return true;
2279 }
2280
2281 if (obj instanceof WeakClassKey) {
2282 Object referent = get();
2283 return (referent != null)
2284 && (referent == ((WeakClassKey) obj).get());
2285 } else {
2286 return false;
2287 }
2288 }
2289 }
2290 }
|