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