diff -r 3392f250c784 -r ecbd252fd3a7 emul/compact/src/main/java/java/io/ObjectStreamClass.java --- a/emul/compact/src/main/java/java/io/ObjectStreamClass.java Fri Mar 22 16:59:47 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1396 +0,0 @@ -/* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.io; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; - -/** - * Serialization's descriptor for classes. It contains the name and - * serialVersionUID of the class. The ObjectStreamClass for a specific class - * loaded in this Java VM can be found/created using the lookup method. - * - *

The algorithm to compute the SerialVersionUID is described in - * Object - * Serialization Specification, Section 4.6, Stream Unique Identifiers. - * - * @author Mike Warres - * @author Roger Riggs - * @see ObjectStreamField - * @see Object Serialization Specification, Section 4, Class Descriptors - * @since JDK1.1 - */ -public class ObjectStreamClass implements Serializable { - - /** serialPersistentFields value indicating no serializable fields */ - public static final ObjectStreamField[] NO_FIELDS = - new ObjectStreamField[0]; - - private static final long serialVersionUID = -6120832682080437368L; - private static final ObjectStreamField[] serialPersistentFields = - NO_FIELDS; - - - /** class associated with this descriptor (if any) */ - private Class cl; - /** name of class represented by this descriptor */ - private String name; - /** serialVersionUID of represented class (null if not computed yet) */ - private volatile Long suid; - - /** true if represents dynamic proxy class */ - private boolean isProxy; - /** true if represents enum type */ - private boolean isEnum; - /** true if represented class implements Serializable */ - private boolean serializable; - /** true if represented class implements Externalizable */ - private boolean externalizable; - /** true if desc has data written by class-defined writeObject method */ - private boolean hasWriteObjectData; - /** - * true if desc has externalizable data written in block data format; this - * must be true by default to accommodate ObjectInputStream subclasses which - * override readClassDescriptor() to return class descriptors obtained from - * ObjectStreamClass.lookup() (see 4461737) - */ - private boolean hasBlockExternalData = true; - - /** exception (if any) thrown while attempting to resolve class */ - private ClassNotFoundException resolveEx; - /** exception (if any) to throw if non-enum deserialization attempted */ - private InvalidClassException deserializeEx; - /** exception (if any) to throw if non-enum serialization attempted */ - private InvalidClassException serializeEx; - /** exception (if any) to throw if default serialization attempted */ - private InvalidClassException defaultSerializeEx; - - /** serializable fields */ - private ObjectStreamField[] fields; - /** aggregate marshalled size of primitive fields */ - private int primDataSize; - /** number of non-primitive fields */ - private int numObjFields; - /** reflector for setting/getting serializable field values */ -// private FieldReflector fieldRefl; - /** data layout of serialized objects described by this class desc */ - private volatile ClassDataSlot[] dataLayout; - - /** serialization-appropriate constructor, or null if none */ - private Constructor cons; - /** class-defined writeObject method, or null if none */ - private Method writeObjectMethod; - /** class-defined readObject method, or null if none */ - private Method readObjectMethod; - /** class-defined readObjectNoData method, or null if none */ - private Method readObjectNoDataMethod; - /** class-defined writeReplace method, or null if none */ - private Method writeReplaceMethod; - /** class-defined readResolve method, or null if none */ - private Method readResolveMethod; - - /** local class descriptor for represented class (may point to self) */ - private ObjectStreamClass localDesc; - /** superclass descriptor appearing in stream */ - private ObjectStreamClass superDesc; - - /** - * Initializes native code. - */ - private static native void initNative(); - static { - initNative(); - } - - /** - * Find the descriptor for a class that can be serialized. Creates an - * ObjectStreamClass instance if one does not exist yet for class. Null is - * returned if the specified class does not implement java.io.Serializable - * or java.io.Externalizable. - * - * @param cl class for which to get the descriptor - * @return the class descriptor for the specified class - */ - public static ObjectStreamClass lookup(Class cl) { - return lookup(cl, false); - } - - /** - * Returns the descriptor for any class, regardless of whether it - * implements {@link Serializable}. - * - * @param cl class for which to get the descriptor - * @return the class descriptor for the specified class - * @since 1.6 - */ - public static ObjectStreamClass lookupAny(Class cl) { - return lookup(cl, true); - } - - /** - * Returns the name of the class described by this descriptor. - * This method returns the name of the class in the format that - * is used by the {@link Class#getName} method. - * - * @return a string representing the name of the class - */ - public String getName() { - return name; - } - - /** - * Return the serialVersionUID for this class. The serialVersionUID - * defines a set of classes all with the same name that have evolved from a - * common root class and agree to be serialized and deserialized using a - * common format. NonSerializable classes have a serialVersionUID of 0L. - * - * @return the SUID of the class described by this descriptor - */ - public long getSerialVersionUID() { - // REMIND: synchronize instead of relying on volatile? - if (suid == null) { - return computeDefaultSUID(cl); - } - return suid.longValue(); - } - - /** - * Return the class in the local VM that this version is mapped to. Null - * is returned if there is no corresponding local class. - * - * @return the Class instance that this descriptor represents - */ - public Class forClass() { - return cl; - } - - /** - * Return an array of the fields of this serializable class. - * - * @return an array containing an element for each persistent field of - * this class. Returns an array of length zero if there are no - * fields. - * @since 1.2 - */ - public ObjectStreamField[] getFields() { - return getFields(true); - } - - /** - * Get the field of this class by name. - * - * @param name the name of the data field to look for - * @return The ObjectStreamField object of the named field or null if - * there is no such named field. - */ - public ObjectStreamField getField(String name) { - return getField(name, null); - } - - /** - * Return a string describing this ObjectStreamClass. - */ - public String toString() { - return name + ": static final long serialVersionUID = " + - getSerialVersionUID() + "L;"; - } - - /** - * Looks up and returns class descriptor for given class, or null if class - * is non-serializable and "all" is set to false. - * - * @param cl class to look up - * @param all if true, return descriptors for all classes; if false, only - * return descriptors for serializable classes - */ - static ObjectStreamClass lookup(Class cl, boolean all) { - if (!(all || Serializable.class.isAssignableFrom(cl))) { - return null; - } - Object entry = null; - EntryFuture future = null; - if (entry == null) { - EntryFuture newEntry = new EntryFuture(); - Reference newRef = new SoftReference<>(newEntry); - if (entry == null) { - future = newEntry; - } - } - - if (entry instanceof ObjectStreamClass) { // check common case first - return (ObjectStreamClass) entry; - } - if (entry instanceof EntryFuture) { - future = (EntryFuture) entry; - if (true) { - /* - * Handle nested call situation described by 4803747: waiting - * for future value to be set by a lookup() call further up the - * stack will result in deadlock, so calculate and set the - * future value here instead. - */ - entry = null; - } else { - entry = future.get(); - } - } - if (entry == null) { - try { - entry = new ObjectStreamClass(cl); - } catch (Throwable th) { - entry = th; - } - // nested lookup call already set future - entry = future.get(); - } - - if (entry instanceof ObjectStreamClass) { - return (ObjectStreamClass) entry; - } else if (entry instanceof RuntimeException) { - throw (RuntimeException) entry; - } else if (entry instanceof Error) { - throw (Error) entry; - } else { - throw new InternalError("unexpected entry: " + entry); - } - } - - /** - * Placeholder used in class descriptor and field reflector lookup tables - * for an entry in the process of being initialized. (Internal) callers - * which receive an EntryFuture belonging to another thread as the result - * of a lookup should call the get() method of the EntryFuture; this will - * return the actual entry once it is ready for use and has been set(). To - * conserve objects, EntryFutures synchronize on themselves. - */ - private static class EntryFuture { - - private static final Object unset = new Object(); - private Object entry = unset; - - /** - * Attempts to set the value contained by this EntryFuture. If the - * EntryFuture's value has not been set already, then the value is - * saved, any callers blocked in the get() method are notified, and - * true is returned. If the value has already been set, then no saving - * or notification occurs, and false is returned. - */ - synchronized boolean set(Object entry) { - if (this.entry != unset) { - return false; - } - this.entry = entry; - notifyAll(); - return true; - } - - /** - * Returns the value contained by this EntryFuture, blocking if - * necessary until a value is set. - */ - synchronized Object get() { - boolean interrupted = false; - while (entry == unset) { - try { - wait(); - } catch (InterruptedException ex) { - interrupted = true; - } - } - return entry; - } - } - - /** - * Creates local class descriptor representing given class. - */ - private ObjectStreamClass(final Class cl) { - this.cl = cl; - name = cl.getName(); - isProxy = Proxy.isProxyClass(cl); - isEnum = Enum.class.isAssignableFrom(cl); - serializable = Serializable.class.isAssignableFrom(cl); - externalizable = Externalizable.class.isAssignableFrom(cl); - - Class superCl = cl.getSuperclass(); - superDesc = (superCl != null) ? lookup(superCl, false) : null; - localDesc = this; - - suid = Long.valueOf(0); - fields = NO_FIELDS; - - - if (deserializeEx == null) { - if (isEnum) { - deserializeEx = new InvalidClassException(name, "enum type"); - } else if (cons == null) { - deserializeEx = new InvalidClassException( - name, "no valid constructor"); - } - } - for (int i = 0; i < fields.length; i++) { - if (fields[i].getField() == null) { - defaultSerializeEx = new InvalidClassException( - name, "unmatched serializable field(s) declared"); - } - } - } - - /** - * Creates blank class descriptor which should be initialized via a - * subsequent call to initProxy(), initNonProxy() or readNonProxy(). - */ - ObjectStreamClass() { - } - - /** - * Initializes class descriptor representing a proxy class. - */ - void initProxy(Class cl, - ClassNotFoundException resolveEx, - ObjectStreamClass superDesc) - throws InvalidClassException - { - this.cl = cl; - this.resolveEx = resolveEx; - this.superDesc = superDesc; - isProxy = true; - serializable = true; - suid = Long.valueOf(0); - fields = NO_FIELDS; - - if (cl != null) { - localDesc = lookup(cl, true); - if (!localDesc.isProxy) { - throw new InvalidClassException( - "cannot bind proxy descriptor to a non-proxy class"); - } - name = localDesc.name; - externalizable = localDesc.externalizable; - cons = localDesc.cons; - writeReplaceMethod = localDesc.writeReplaceMethod; - readResolveMethod = localDesc.readResolveMethod; - deserializeEx = localDesc.deserializeEx; - } - } - - /** - * Initializes class descriptor representing a non-proxy class. - */ - void initNonProxy(ObjectStreamClass model, - Class cl, - ClassNotFoundException resolveEx, - ObjectStreamClass superDesc) - throws InvalidClassException - { - this.cl = cl; - this.resolveEx = resolveEx; - this.superDesc = superDesc; - name = model.name; - suid = Long.valueOf(model.getSerialVersionUID()); - isProxy = false; - isEnum = model.isEnum; - serializable = model.serializable; - externalizable = model.externalizable; - hasBlockExternalData = model.hasBlockExternalData; - hasWriteObjectData = model.hasWriteObjectData; - fields = model.fields; - primDataSize = model.primDataSize; - numObjFields = model.numObjFields; - - if (cl != null) { - localDesc = lookup(cl, true); - if (localDesc.isProxy) { - throw new InvalidClassException( - "cannot bind non-proxy descriptor to a proxy class"); - } - if (isEnum != localDesc.isEnum) { - throw new InvalidClassException(isEnum ? - "cannot bind enum descriptor to a non-enum class" : - "cannot bind non-enum descriptor to an enum class"); - } - - if (serializable == localDesc.serializable && - !cl.isArray() && - suid.longValue() != localDesc.getSerialVersionUID()) - { - throw new InvalidClassException(localDesc.name, - "local class incompatible: " + - "stream classdesc serialVersionUID = " + suid + - ", local class serialVersionUID = " + - localDesc.getSerialVersionUID()); - } - - if (!classNamesEqual(name, localDesc.name)) { - throw new InvalidClassException(localDesc.name, - "local class name incompatible with stream class " + - "name \"" + name + "\""); - } - - if (!isEnum) { - if ((serializable == localDesc.serializable) && - (externalizable != localDesc.externalizable)) - { - throw new InvalidClassException(localDesc.name, - "Serializable incompatible with Externalizable"); - } - - if ((serializable != localDesc.serializable) || - (externalizable != localDesc.externalizable) || - !(serializable || externalizable)) - { - deserializeEx = new InvalidClassException(localDesc.name, - "class invalid for deserialization"); - } - } - - cons = localDesc.cons; - writeObjectMethod = localDesc.writeObjectMethod; - readObjectMethod = localDesc.readObjectMethod; - readObjectNoDataMethod = localDesc.readObjectNoDataMethod; - writeReplaceMethod = localDesc.writeReplaceMethod; - readResolveMethod = localDesc.readResolveMethod; - if (deserializeEx == null) { - deserializeEx = localDesc.deserializeEx; - } - } - // reassign to matched fields so as to reflect local unshared settings - fields = null; - } - - /** - * Reads non-proxy class descriptor information from given input stream. - * The resulting class descriptor is not fully functional; it can only be - * used as input to the ObjectInputStream.resolveClass() and - * ObjectStreamClass.initNonProxy() methods. - */ - void readNonProxy(ObjectInputStream in) - throws IOException, ClassNotFoundException - { - name = in.readUTF(); - suid = Long.valueOf(in.readLong()); - isProxy = false; - - byte flags = in.readByte(); - hasWriteObjectData = - ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); - hasBlockExternalData = - ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); - externalizable = - ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); - boolean sflag = - ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); - if (externalizable && sflag) { - throw new InvalidClassException( - name, "serializable and externalizable flags conflict"); - } - serializable = externalizable || sflag; - isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); - if (isEnum && suid.longValue() != 0L) { - throw new InvalidClassException(name, - "enum descriptor has non-zero serialVersionUID: " + suid); - } - - int numFields = in.readShort(); - if (isEnum && numFields != 0) { - throw new InvalidClassException(name, - "enum descriptor has non-zero field count: " + numFields); - } - fields = (numFields > 0) ? - new ObjectStreamField[numFields] : NO_FIELDS; - for (int i = 0; i < numFields; i++) { - char tcode = (char) in.readByte(); - String fname = in.readUTF(); - String signature = ((tcode == 'L') || (tcode == '[')) ? - in.readTypeString() : new String(new char[] { tcode }); - try { - fields[i] = new ObjectStreamField(fname, signature, false); - } catch (RuntimeException e) { - throw (IOException) new InvalidClassException(name, - "invalid descriptor for field " + fname).initCause(e); - } - } - computeFieldOffsets(); - } - - /** - * Writes non-proxy class descriptor information to given output stream. - */ - void writeNonProxy(ObjectOutputStream out) throws IOException { - out.writeUTF(name); - out.writeLong(getSerialVersionUID()); - - byte flags = 0; - if (externalizable) { - flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; - int protocol = out.getProtocolVersion(); - if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { - flags |= ObjectStreamConstants.SC_BLOCK_DATA; - } - } else if (serializable) { - flags |= ObjectStreamConstants.SC_SERIALIZABLE; - } - if (hasWriteObjectData) { - flags |= ObjectStreamConstants.SC_WRITE_METHOD; - } - if (isEnum) { - flags |= ObjectStreamConstants.SC_ENUM; - } - out.writeByte(flags); - - out.writeShort(fields.length); - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - out.writeByte(f.getTypeCode()); - out.writeUTF(f.getName()); - if (!f.isPrimitive()) { - out.writeTypeString(f.getTypeString()); - } - } - } - - /** - * Returns ClassNotFoundException (if any) thrown while attempting to - * resolve local class corresponding to this class descriptor. - */ - ClassNotFoundException getResolveException() { - return resolveEx; - } - - /** - * Throws an InvalidClassException if object instances referencing this - * class descriptor should not be allowed to deserialize. This method does - * not apply to deserialization of enum constants. - */ - void checkDeserialize() throws InvalidClassException { - if (deserializeEx != null) { - InvalidClassException ice = - new InvalidClassException(deserializeEx.classname, - deserializeEx.getMessage()); - ice.initCause(deserializeEx); - throw ice; - } - } - - /** - * Throws an InvalidClassException if objects whose class is represented by - * this descriptor should not be allowed to serialize. This method does - * not apply to serialization of enum constants. - */ - void checkSerialize() throws InvalidClassException { - if (serializeEx != null) { - InvalidClassException ice = - new InvalidClassException(serializeEx.classname, - serializeEx.getMessage()); - ice.initCause(serializeEx); - throw ice; - } - } - - /** - * Throws an InvalidClassException if objects whose class is represented by - * this descriptor should not be permitted to use default serialization - * (e.g., if the class declares serializable fields that do not correspond - * to actual fields, and hence must use the GetField API). This method - * does not apply to deserialization of enum constants. - */ - void checkDefaultSerialize() throws InvalidClassException { - if (defaultSerializeEx != null) { - InvalidClassException ice = - new InvalidClassException(defaultSerializeEx.classname, - defaultSerializeEx.getMessage()); - ice.initCause(defaultSerializeEx); - throw ice; - } - } - - /** - * Returns superclass descriptor. Note that on the receiving side, the - * superclass descriptor may be bound to a class that is not a superclass - * of the subclass descriptor's bound class. - */ - ObjectStreamClass getSuperDesc() { - return superDesc; - } - - /** - * Returns the "local" class descriptor for the class associated with this - * class descriptor (i.e., the result of - * ObjectStreamClass.lookup(this.forClass())) or null if there is no class - * associated with this descriptor. - */ - ObjectStreamClass getLocalDesc() { - return localDesc; - } - - /** - * Returns arrays of ObjectStreamFields representing the serializable - * fields of the represented class. If copy is true, a clone of this class - * descriptor's field array is returned, otherwise the array itself is - * returned. - */ - ObjectStreamField[] getFields(boolean copy) { - return copy ? fields.clone() : fields; - } - - /** - * Looks up a serializable field of the represented class by name and type. - * A specified type of null matches all types, Object.class matches all - * non-primitive types, and any other non-null type matches assignable - * types only. Returns matching field, or null if no match found. - */ - ObjectStreamField getField(String name, Class type) { - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - if (f.getName().equals(name)) { - if (type == null || - (type == Object.class && !f.isPrimitive())) - { - return f; - } - Class ftype = f.getType(); - if (ftype != null && type.isAssignableFrom(ftype)) { - return f; - } - } - } - return null; - } - - /** - * Returns true if class descriptor represents a dynamic proxy class, false - * otherwise. - */ - boolean isProxy() { - return isProxy; - } - - /** - * Returns true if class descriptor represents an enum type, false - * otherwise. - */ - boolean isEnum() { - return isEnum; - } - - /** - * Returns true if represented class implements Externalizable, false - * otherwise. - */ - boolean isExternalizable() { - return externalizable; - } - - /** - * Returns true if represented class implements Serializable, false - * otherwise. - */ - boolean isSerializable() { - return serializable; - } - - /** - * Returns true if class descriptor represents externalizable class that - * has written its data in 1.2 (block data) format, false otherwise. - */ - boolean hasBlockExternalData() { - return hasBlockExternalData; - } - - /** - * Returns true if class descriptor represents serializable (but not - * externalizable) class which has written its data via a custom - * writeObject() method, false otherwise. - */ - boolean hasWriteObjectData() { - return hasWriteObjectData; - } - - /** - * Returns true if represented class is serializable/externalizable and can - * be instantiated by the serialization runtime--i.e., if it is - * externalizable and defines a public no-arg constructor, or if it is - * non-externalizable and its first non-serializable superclass defines an - * accessible no-arg constructor. Otherwise, returns false. - */ - boolean isInstantiable() { - return (cons != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant writeObject method. Otherwise, - * returns false. - */ - boolean hasWriteObjectMethod() { - return (writeObjectMethod != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant readObject method. Otherwise, - * returns false. - */ - boolean hasReadObjectMethod() { - return (readObjectMethod != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant readObjectNoData method. - * Otherwise, returns false. - */ - boolean hasReadObjectNoDataMethod() { - return (readObjectNoDataMethod != null); - } - - /** - * Returns true if represented class is serializable or externalizable and - * defines a conformant writeReplace method. Otherwise, returns false. - */ - boolean hasWriteReplaceMethod() { - return (writeReplaceMethod != null); - } - - /** - * Returns true if represented class is serializable or externalizable and - * defines a conformant readResolve method. Otherwise, returns false. - */ - boolean hasReadResolveMethod() { - return (readResolveMethod != null); - } - - /** - * Creates a new instance of the represented class. If the class is - * externalizable, invokes its public no-arg constructor; otherwise, if the - * class is serializable, invokes the no-arg constructor of the first - * non-serializable superclass. Throws UnsupportedOperationException if - * this class descriptor is not associated with a class, if the associated - * class is non-serializable or if the appropriate no-arg constructor is - * inaccessible/unavailable. - */ - Object newInstance() - throws InstantiationException, InvocationTargetException, - UnsupportedOperationException - { - if (cons != null) { - try { - return cons.newInstance(); - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the writeObject method of the represented serializable class. - * Throws UnsupportedOperationException if this class descriptor is not - * associated with a class, or if the class is externalizable, - * non-serializable or does not define writeObject. - */ - void invokeWriteObject(Object obj, ObjectOutputStream out) - throws IOException, UnsupportedOperationException - { - if (writeObjectMethod != null) { - try { - writeObjectMethod.invoke(obj, new Object[]{ out }); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof IOException) { - throw (IOException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readObject method of the represented serializable class. - * Throws UnsupportedOperationException if this class descriptor is not - * associated with a class, or if the class is externalizable, - * non-serializable or does not define readObject. - */ - void invokeReadObject(Object obj, ObjectInputStream in) - throws ClassNotFoundException, IOException, - UnsupportedOperationException - { - if (readObjectMethod != null) { - try { - readObjectMethod.invoke(obj, new Object[]{ in }); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ClassNotFoundException) { - throw (ClassNotFoundException) th; - } else if (th instanceof IOException) { - throw (IOException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readObjectNoData method of the represented serializable - * class. Throws UnsupportedOperationException if this class descriptor is - * not associated with a class, or if the class is externalizable, - * non-serializable or does not define readObjectNoData. - */ - void invokeReadObjectNoData(Object obj) - throws IOException, UnsupportedOperationException - { - if (readObjectNoDataMethod != null) { - try { - readObjectNoDataMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the writeReplace method of the represented serializable class and - * returns the result. Throws UnsupportedOperationException if this class - * descriptor is not associated with a class, or if the class is - * non-serializable or does not define writeReplace. - */ - Object invokeWriteReplace(Object obj) - throws IOException, UnsupportedOperationException - { - if (writeReplaceMethod != null) { - try { - return writeReplaceMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - throw new InternalError(); // never reached - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readResolve method of the represented serializable class and - * returns the result. Throws UnsupportedOperationException if this class - * descriptor is not associated with a class, or if the class is - * non-serializable or does not define readResolve. - */ - Object invokeReadResolve(Object obj) - throws IOException, UnsupportedOperationException - { - if (readResolveMethod != null) { - try { - return readResolveMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - throw new InternalError(); // never reached - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Class representing the portion of an object's serialized form allotted - * to data described by a given class descriptor. If "hasData" is false, - * the object's serialized form does not contain data associated with the - * class descriptor. - */ - static class ClassDataSlot { - - /** class descriptor "occupying" this slot */ - final ObjectStreamClass desc; - /** true if serialized form includes data for this slot's descriptor */ - final boolean hasData; - - ClassDataSlot(ObjectStreamClass desc, boolean hasData) { - this.desc = desc; - this.hasData = hasData; - } - } - - /** - * Returns array of ClassDataSlot instances representing the data layout - * (including superclass data) for serialized objects described by this - * class descriptor. ClassDataSlots are ordered by inheritance with those - * containing "higher" superclasses appearing first. The final - * ClassDataSlot contains a reference to this descriptor. - */ - ClassDataSlot[] getClassDataLayout() throws InvalidClassException { - // REMIND: synchronize instead of relying on volatile? - if (dataLayout == null) { - dataLayout = getClassDataLayout0(); - } - return dataLayout; - } - - private ClassDataSlot[] getClassDataLayout0() - throws InvalidClassException - { - ArrayList slots = new ArrayList<>(); - Class start = cl, end = cl; - - // locate closest non-serializable superclass - while (end != null && Serializable.class.isAssignableFrom(end)) { - end = end.getSuperclass(); - } - - for (ObjectStreamClass d = this; d != null; d = d.superDesc) { - - // search up inheritance hierarchy for class with matching name - String searchName = (d.cl != null) ? d.cl.getName() : d.name; - Class match = null; - for (Class c = start; c != end; c = c.getSuperclass()) { - if (searchName.equals(c.getName())) { - match = c; - break; - } - } - - // add "no data" slot for each unmatched class below match - if (match != null) { - for (Class c = start; c != match; c = c.getSuperclass()) { - slots.add(new ClassDataSlot( - ObjectStreamClass.lookup(c, true), false)); - } - start = match.getSuperclass(); - } - - // record descriptor/class pairing - slots.add(new ClassDataSlot(d.getVariantFor(match), true)); - } - - // add "no data" slot for any leftover unmatched classes - for (Class c = start; c != end; c = c.getSuperclass()) { - slots.add(new ClassDataSlot( - ObjectStreamClass.lookup(c, true), false)); - } - - // order slots from superclass -> subclass - Collections.reverse(slots); - return slots.toArray(new ClassDataSlot[slots.size()]); - } - - /** - * Returns aggregate size (in bytes) of marshalled primitive field values - * for represented class. - */ - int getPrimDataSize() { - return primDataSize; - } - - /** - * Returns number of non-primitive serializable fields of represented - * class. - */ - int getNumObjFields() { - return numObjFields; - } - - /** - * Fetches the serializable primitive field values of object obj and - * marshals them into byte array buf starting at offset 0. It is the - * responsibility of the caller to ensure that obj is of the proper type if - * non-null. - */ - void getPrimFieldValues(Object obj, byte[] buf) { - } - - /** - * Sets the serializable primitive fields of object obj using values - * unmarshalled from byte array buf starting at offset 0. It is the - * responsibility of the caller to ensure that obj is of the proper type if - * non-null. - */ - void setPrimFieldValues(Object obj, byte[] buf) { - } - - /** - * Fetches the serializable object field values of object obj and stores - * them in array vals starting at offset 0. It is the responsibility of - * the caller to ensure that obj is of the proper type if non-null. - */ - void getObjFieldValues(Object obj, Object[] vals) { - } - - /** - * Sets the serializable object fields of object obj using values from - * array vals starting at offset 0. It is the responsibility of the caller - * to ensure that obj is of the proper type if non-null. - */ - void setObjFieldValues(Object obj, Object[] vals) { - } - - /** - * Calculates and sets serializable field offsets, as well as primitive - * data size and object field count totals. Throws InvalidClassException - * if fields are illegally ordered. - */ - private void computeFieldOffsets() throws InvalidClassException { - primDataSize = 0; - numObjFields = 0; - int firstObjIndex = -1; - - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - switch (f.getTypeCode()) { - case 'Z': - case 'B': - f.setOffset(primDataSize++); - break; - - case 'C': - case 'S': - f.setOffset(primDataSize); - primDataSize += 2; - break; - - case 'I': - case 'F': - f.setOffset(primDataSize); - primDataSize += 4; - break; - - case 'J': - case 'D': - f.setOffset(primDataSize); - primDataSize += 8; - break; - - case '[': - case 'L': - f.setOffset(numObjFields++); - if (firstObjIndex == -1) { - firstObjIndex = i; - } - break; - - default: - throw new InternalError(); - } - } - if (firstObjIndex != -1 && - firstObjIndex + numObjFields != fields.length) - { - throw new InvalidClassException(name, "illegal field order"); - } - } - - /** - * If given class is the same as the class associated with this class - * descriptor, returns reference to this class descriptor. Otherwise, - * returns variant of this class descriptor bound to given class. - */ - private ObjectStreamClass getVariantFor(Class cl) - throws InvalidClassException - { - if (this.cl == cl) { - return this; - } - ObjectStreamClass desc = new ObjectStreamClass(); - if (isProxy) { - desc.initProxy(cl, null, superDesc); - } else { - desc.initNonProxy(this, cl, null, superDesc); - } - return desc; - } - - /** - * Returns public no-arg constructor of given class, or null if none found. - * Access checks are disabled on the returned constructor (if any), since - * the defining class may still be non-public. - */ - private static Constructor getExternalizableConstructor(Class cl) { - throw new SecurityException(); - } - - /** - * Returns subclass-accessible no-arg constructor of first non-serializable - * superclass, or null if none found. Access checks are disabled on the - * returned constructor (if any). - */ - private static Constructor getSerializableConstructor(Class cl) { - Class initCl = cl; - while (Serializable.class.isAssignableFrom(initCl)) { - if ((initCl = initCl.getSuperclass()) == null) { - return null; - } - } - throw new SecurityException(); - } - - /** - * Returns non-static, non-abstract method with given signature provided it - * is defined by or accessible (via inheritance) by the given class, or - * null if no match found. Access checks are disabled on the returned - * method (if any). - */ - private static Method getInheritableMethod(Class cl, String name, - Class[] argTypes, - Class returnType) - { - throw new SecurityException(); - } - - /** - * Returns non-static private method with given signature defined by given - * class, or null if none found. Access checks are disabled on the - * returned method (if any). - */ - private static Method getPrivateMethod(Class cl, String name, - Class[] argTypes, - Class returnType) - { - throw new SecurityException(); - } - - /** - * Returns true if classes are defined in the same runtime package, false - * otherwise. - */ - private static boolean packageEquals(Class cl1, Class cl2) { - return (cl1.getClassLoader() == cl2.getClassLoader() && - getPackageName(cl1).equals(getPackageName(cl2))); - } - - /** - * Returns package name of given class. - */ - private static String getPackageName(Class cl) { - String s = cl.getName(); - int i = s.lastIndexOf('['); - if (i >= 0) { - s = s.substring(i + 2); - } - i = s.lastIndexOf('.'); - return (i >= 0) ? s.substring(0, i) : ""; - } - - /** - * Compares class names for equality, ignoring package names. Returns true - * if class names equal, false otherwise. - */ - private static boolean classNamesEqual(String name1, String name2) { - name1 = name1.substring(name1.lastIndexOf('.') + 1); - name2 = name2.substring(name2.lastIndexOf('.') + 1); - return name1.equals(name2); - } - - /** - * Returns JVM type signature for given class. - */ - private static String getClassSignature(Class cl) { - StringBuilder sbuf = new StringBuilder(); - while (cl.isArray()) { - sbuf.append('['); - cl = cl.getComponentType(); - } - if (cl.isPrimitive()) { - if (cl == Integer.TYPE) { - sbuf.append('I'); - } else if (cl == Byte.TYPE) { - sbuf.append('B'); - } else if (cl == Long.TYPE) { - sbuf.append('J'); - } else if (cl == Float.TYPE) { - sbuf.append('F'); - } else if (cl == Double.TYPE) { - sbuf.append('D'); - } else if (cl == Short.TYPE) { - sbuf.append('S'); - } else if (cl == Character.TYPE) { - sbuf.append('C'); - } else if (cl == Boolean.TYPE) { - sbuf.append('Z'); - } else if (cl == Void.TYPE) { - sbuf.append('V'); - } else { - throw new InternalError(); - } - } else { - sbuf.append('L' + cl.getName().replace('.', '/') + ';'); - } - return sbuf.toString(); - } - - /** - * Returns JVM type signature for given list of parameters and return type. - */ - private static String getMethodSignature(Class[] paramTypes, - Class retType) - { - StringBuilder sbuf = new StringBuilder(); - sbuf.append('('); - for (int i = 0; i < paramTypes.length; i++) { - sbuf.append(getClassSignature(paramTypes[i])); - } - sbuf.append(')'); - sbuf.append(getClassSignature(retType)); - return sbuf.toString(); - } - - /** - * Convenience method for throwing an exception that is either a - * RuntimeException, Error, or of some unexpected type (in which case it is - * wrapped inside an IOException). - */ - private static void throwMiscException(Throwable th) throws IOException { - if (th instanceof RuntimeException) { - throw (RuntimeException) th; - } else if (th instanceof Error) { - throw (Error) th; - } else { - IOException ex = new IOException("unexpected exception type"); - ex.initCause(th); - throw ex; - } - } - - /** - * Returns ObjectStreamField array describing the serializable fields of - * the given class. Serializable fields backed by an actual field of the - * class are represented by ObjectStreamFields with corresponding non-null - * Field objects. Throws InvalidClassException if the (explicitly - * declared) serializable fields are invalid. - */ - private static ObjectStreamField[] getSerialFields(Class cl) - throws InvalidClassException - { - ObjectStreamField[] fields; - if (Serializable.class.isAssignableFrom(cl) && - !Externalizable.class.isAssignableFrom(cl) && - !Proxy.isProxyClass(cl) && - !cl.isInterface()) - { - if ((fields = getDeclaredSerialFields(cl)) == null) { - fields = getDefaultSerialFields(cl); - } - Arrays.sort(fields); - } else { - fields = NO_FIELDS; - } - return fields; - } - - /** - * Returns serializable fields of given class as defined explicitly by a - * "serialPersistentFields" field, or null if no appropriate - * "serialPersistentFields" field is defined. Serializable fields backed - * by an actual field of the class are represented by ObjectStreamFields - * with corresponding non-null Field objects. For compatibility with past - * releases, a "serialPersistentFields" field with a null value is - * considered equivalent to not declaring "serialPersistentFields". Throws - * InvalidClassException if the declared serializable fields are - * invalid--e.g., if multiple fields share the same name. - */ - private static ObjectStreamField[] getDeclaredSerialFields(Class cl) - throws InvalidClassException - { - throw new SecurityException(); - } - - /** - * Returns array of ObjectStreamFields corresponding to all non-static - * non-transient fields declared by given class. Each ObjectStreamField - * contains a Field object for the field it represents. If no default - * serializable fields exist, NO_FIELDS is returned. - */ - private static ObjectStreamField[] getDefaultSerialFields(Class cl) { - throw new SecurityException(); - } - - /** - * Returns explicit serial version UID value declared by given class, or - * null if none. - */ - private static Long getDeclaredSUID(Class cl) { - return null; - } - - /** - * Computes the default serial version UID value for the given class. - */ - private static long computeDefaultSUID(Class cl) { - throw new SecurityException(); - } - -}