Source Code Cross Referenced for ObjectStreamClass.java in  » 6.0-JDK-Core » io-nio » java » io » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » io nio » java.io 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.