FileDocCategorySizeDatePackage
ObjectStreamClass.javaAPI DocJava SE 6 API71530Tue Jun 10 00:25:34 BST 2008java.io

ObjectStreamClass

public class ObjectStreamClass extends Object implements Serializable
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
version
1.152, 04/21/06
see
ObjectStreamField
see
Object Serialization Specification, Section 4, Class Descriptors
since
JDK1.1

Fields Summary
public static final ObjectStreamField[]
NO_FIELDS
serialPersistentFields value indicating no serializable fields
private static final long
serialVersionUID
private static final ObjectStreamField[]
serialPersistentFields
private static final ReflectionFactory
reflFactory
reflection factory for obtaining serialization constructors
private Class
cl
class associated with this descriptor (if any)
private String
name
name of class represented by this descriptor
private volatile Long
suid
serialVersionUID of represented class (null if not computed yet)
private boolean
isProxy
true if represents dynamic proxy class
private boolean
isEnum
true if represents enum type
private boolean
serializable
true if represented class implements Serializable
private boolean
externalizable
true if represented class implements Externalizable
private boolean
hasWriteObjectData
true if desc has data written by class-defined writeObject method
private boolean
hasBlockExternalData
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 ClassNotFoundException
resolveEx
exception (if any) thrown while attempting to resolve class
private InvalidClassException
deserializeEx
exception (if any) to throw if non-enum deserialization attempted
private InvalidClassException
serializeEx
exception (if any) to throw if non-enum serialization attempted
private InvalidClassException
defaultSerializeEx
exception (if any) to throw if default serialization attempted
private ObjectStreamField[]
fields
serializable fields
private int
primDataSize
aggregate marshalled size of primitive fields
private int
numObjFields
number of non-primitive fields
private FieldReflector
fieldRefl
reflector for setting/getting serializable field values
private volatile ClassDataSlot[]
dataLayout
data layout of serialized objects described by this class desc
private Constructor
cons
serialization-appropriate constructor, or null if none
private Method
writeObjectMethod
class-defined writeObject method, or null if none
private Method
readObjectMethod
class-defined readObject method, or null if none
private Method
readObjectNoDataMethod
class-defined readObjectNoData method, or null if none
private Method
writeReplaceMethod
class-defined writeReplace method, or null if none
private Method
readResolveMethod
class-defined readResolve method, or null if none
private ObjectStreamClass
localDesc
local class descriptor for represented class (may point to self)
private ObjectStreamClass
superDesc
superclass descriptor appearing in stream
Constructors Summary
private ObjectStreamClass(Class cl)
Creates local class descriptor representing given class.

	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;

	if (serializable) {
	    AccessController.doPrivileged(new PrivilegedAction() {
		public Object run() {
		    if (isEnum) {
			suid = Long.valueOf(0);
			fields = NO_FIELDS;
			return null;
		    }
		    if (cl.isArray()) {
			fields = NO_FIELDS;
			return null;
		    }
	
		    suid = getDeclaredSUID(cl);
		    try {
			fields = getSerialFields(cl);
			computeFieldOffsets();
		    } catch (InvalidClassException e) {
			serializeEx = deserializeEx = e;
			fields = NO_FIELDS;
		    }
		    
		    if (externalizable) {
			cons = getExternalizableConstructor(cl);
		    } else {
			cons = getSerializableConstructor(cl);
			writeObjectMethod = getPrivateMethod(cl, "writeObject", 
			    new Class[] { ObjectOutputStream.class }, 
			    Void.TYPE);
			readObjectMethod = getPrivateMethod(cl, "readObject", 
			    new Class[] { ObjectInputStream.class }, 
			    Void.TYPE);
			readObjectNoDataMethod = getPrivateMethod(
			    cl, "readObjectNoData", null, Void.TYPE);
			hasWriteObjectData = (writeObjectMethod != null);
		    }
		    writeReplaceMethod = getInheritableMethod(
			cl, "writeReplace", null, Object.class);
		    readResolveMethod = getInheritableMethod(
			cl, "readResolve", null, Object.class);
		    return null;
		}
	    });
	} else {
	    suid = Long.valueOf(0);
	    fields = NO_FIELDS;
	}

	try {
	    fieldRefl = getReflector(fields, this);
	} catch (InvalidClassException ex) {
	    // field mismatches impossible when matching local fields vs. self
	    throw new InternalError();
	}

	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");
	    }
	}
    
ObjectStreamClass()
Creates blank class descriptor which should be initialized via a subsequent call to initProxy(), initNonProxy() or readNonProxy().

    
Methods Summary
voidcheckDefaultSerialize()
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.

	if (defaultSerializeEx != null) {
	    InvalidClassException ice = 
		new InvalidClassException(defaultSerializeEx.classname,
					  defaultSerializeEx.getMessage());
	    ice.initCause(defaultSerializeEx);
	    throw ice;
	}
    
voidcheckDeserialize()
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.

	if (deserializeEx != null) {
	    InvalidClassException ice = 
		new InvalidClassException(deserializeEx.classname,
					  deserializeEx.getMessage());
	    ice.initCause(deserializeEx);
	    throw ice;
	}
    
voidcheckSerialize()
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.

	if (serializeEx != null) {
	    InvalidClassException ice = 
		new InvalidClassException(serializeEx.classname,
					  serializeEx.getMessage());
	    ice.initCause(serializeEx);
	    throw ice;
	}
    
private static booleanclassNamesEqual(java.lang.String name1, java.lang.String name2)
Compares class names for equality, ignoring package names. Returns true if class names equal, false otherwise.

	name1 = name1.substring(name1.lastIndexOf('.") + 1);
	name2 = name2.substring(name2.lastIndexOf('.") + 1);
	return name1.equals(name2);
    
private static longcomputeDefaultSUID(java.lang.Class cl)
Computes the default serial version UID value for the given class.

	if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
	{
	    return 0L;
	}

	try {
	    ByteArrayOutputStream bout = new ByteArrayOutputStream();
	    DataOutputStream dout = new DataOutputStream(bout);

	    dout.writeUTF(cl.getName());
	    
	    int classMods = cl.getModifiers() &
		(Modifier.PUBLIC | Modifier.FINAL |
		 Modifier.INTERFACE | Modifier.ABSTRACT);

	    /*
	     * compensate for javac bug in which ABSTRACT bit was set for an
	     * interface only if the interface declared methods
	     */
	    Method[] methods = cl.getDeclaredMethods();
	    if ((classMods & Modifier.INTERFACE) != 0) {
		classMods = (methods.length > 0) ?
		    (classMods | Modifier.ABSTRACT) :
		    (classMods & ~Modifier.ABSTRACT);
	    }
	    dout.writeInt(classMods);
	    
	    if (!cl.isArray()) {
		/*
		 * compensate for change in 1.2FCS in which
		 * Class.getInterfaces() was modified to return Cloneable and
		 * Serializable for array classes.
		 */
		Class[] interfaces = cl.getInterfaces();
		String[] ifaceNames = new String[interfaces.length];
		for (int i = 0; i < interfaces.length; i++) {
		    ifaceNames[i] = interfaces[i].getName();
		}
		Arrays.sort(ifaceNames);
		for (int i = 0; i < ifaceNames.length; i++) {
		    dout.writeUTF(ifaceNames[i]);
		}
	    }
	    
	    Field[] fields = cl.getDeclaredFields();
	    MemberSignature[] fieldSigs = new MemberSignature[fields.length];
	    for (int i = 0; i < fields.length; i++) {
		fieldSigs[i] = new MemberSignature(fields[i]);
	    }
	    Arrays.sort(fieldSigs, new Comparator() {
		public int compare(Object o1, Object o2) {
		    String name1 = ((MemberSignature) o1).name;
		    String name2 = ((MemberSignature) o2).name;
		    return name1.compareTo(name2);
		}
	    });
	    for (int i = 0; i < fieldSigs.length; i++) {
		MemberSignature sig = fieldSigs[i];
		int mods = sig.member.getModifiers() &
		    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
		     Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
		     Modifier.TRANSIENT);
		if (((mods & Modifier.PRIVATE) == 0) ||
		    ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
		{
		    dout.writeUTF(sig.name);
		    dout.writeInt(mods);
		    dout.writeUTF(sig.signature);
		}
	    }
	    
	    if (hasStaticInitializer(cl)) {
		dout.writeUTF("<clinit>");
		dout.writeInt(Modifier.STATIC);
		dout.writeUTF("()V");
	    }

	    Constructor[] cons = cl.getDeclaredConstructors();
	    MemberSignature[] consSigs = new MemberSignature[cons.length];
	    for (int i = 0; i < cons.length; i++) {
		consSigs[i] = new MemberSignature(cons[i]);
	    }
	    Arrays.sort(consSigs, new Comparator() {
		public int compare(Object o1, Object o2) {
		    String sig1 = ((MemberSignature) o1).signature;
		    String sig2 = ((MemberSignature) o2).signature;
		    return sig1.compareTo(sig2);
		}
	    });
	    for (int i = 0; i < consSigs.length; i++) {
		MemberSignature sig = consSigs[i];
		int mods = sig.member.getModifiers() &
		    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
		     Modifier.STATIC | Modifier.FINAL |
		     Modifier.SYNCHRONIZED | Modifier.NATIVE |
		     Modifier.ABSTRACT | Modifier.STRICT);
		if ((mods & Modifier.PRIVATE) == 0) {
		    dout.writeUTF("<init>");
		    dout.writeInt(mods);
		    dout.writeUTF(sig.signature.replace('/", '."));
		}
	    }
	    
	    MemberSignature[] methSigs = new MemberSignature[methods.length];
	    for (int i = 0; i < methods.length; i++) {
		methSigs[i] = new MemberSignature(methods[i]);
	    }
	    Arrays.sort(methSigs, new Comparator() {
		public int compare(Object o1, Object o2) {
		    MemberSignature ms1 = (MemberSignature) o1;
		    MemberSignature ms2 = (MemberSignature) o2;
		    int comp = ms1.name.compareTo(ms2.name);
		    if (comp == 0) {
			comp = ms1.signature.compareTo(ms2.signature);
		    }
		    return comp;
		}
	    });
	    for (int i = 0; i < methSigs.length; i++) {
		MemberSignature sig = methSigs[i];
		int mods = sig.member.getModifiers() &
		    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
		     Modifier.STATIC | Modifier.FINAL |
		     Modifier.SYNCHRONIZED | Modifier.NATIVE |
		     Modifier.ABSTRACT | Modifier.STRICT);
		if ((mods & Modifier.PRIVATE) == 0) {
		    dout.writeUTF(sig.name);
		    dout.writeInt(mods);
		    dout.writeUTF(sig.signature.replace('/", '."));
		}
	    }

	    dout.flush();

	    MessageDigest md = MessageDigest.getInstance("SHA");
	    byte[] hashBytes = md.digest(bout.toByteArray());
	    long hash = 0;
	    for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
		hash = (hash << 8) | (hashBytes[i] & 0xFF);
	    }
	    return hash;
	} catch (IOException ex) {
	    throw new InternalError();
	} catch (NoSuchAlgorithmException ex) {
	    throw new SecurityException(ex.getMessage());
	}
    
private voidcomputeFieldOffsets()
Calculates and sets serializable field offsets, as well as primitive data size and object field count totals. Throws InvalidClassException if fields are illegally ordered.

	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");
	}
    
public java.lang.ClassforClass()
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

	return cl;
    
java.io.ObjectStreamClass$ClassDataSlot[]getClassDataLayout()
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.

	// REMIND: synchronize instead of relying on volatile?
	if (dataLayout == null) {
	    dataLayout = getClassDataLayout0();
	}
	return dataLayout;
    
private java.io.ObjectStreamClass$ClassDataSlot[]getClassDataLayout0()

	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 (ClassDataSlot[]) 
	    slots.toArray(new ClassDataSlot[slots.size()]);
    
static java.lang.StringgetClassSignature(java.lang.Class cl)
Returns JVM type signature for given class.

	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();
    
private static java.lang.LonggetDeclaredSUID(java.lang.Class cl)
Returns explicit serial version UID value declared by given class, or null if none.

	try {
	    Field f = cl.getDeclaredField("serialVersionUID");
	    int mask = Modifier.STATIC | Modifier.FINAL;
	    if ((f.getModifiers() & mask) == mask) {
		f.setAccessible(true);
		return Long.valueOf(f.getLong(null));
	    }
	} catch (Exception ex) {
	}
	return null;
    
private static java.io.ObjectStreamField[]getDeclaredSerialFields(java.lang.Class cl)
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.

	ObjectStreamField[] serialPersistentFields = null;
	try {
	    Field f = cl.getDeclaredField("serialPersistentFields");
	    int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
	    if ((f.getModifiers() & mask) == mask) {
		f.setAccessible(true);
		serialPersistentFields = (ObjectStreamField[]) f.get(null);
	    }
	} catch (Exception ex) {
	}
	if (serialPersistentFields == null) {
	    return null;
	} else if (serialPersistentFields.length == 0) {
	    return NO_FIELDS;
	}
	
	ObjectStreamField[] boundFields = 
	    new ObjectStreamField[serialPersistentFields.length];
	Set fieldNames = new HashSet(serialPersistentFields.length);

	for (int i = 0; i < serialPersistentFields.length; i++) {
	    ObjectStreamField spf = serialPersistentFields[i];

	    String fname = spf.getName();
	    if (fieldNames.contains(fname)) {
		throw new InvalidClassException(
		    "multiple serializable fields named " + fname);
	    }
	    fieldNames.add(fname);

	    try {
		Field f = cl.getDeclaredField(fname);
		if ((f.getType() == spf.getType()) &&
		    ((f.getModifiers() & Modifier.STATIC) == 0))
		{
		    boundFields[i] = 
			new ObjectStreamField(f, spf.isUnshared(), true);
		}
	    } catch (NoSuchFieldException ex) {
	    }
	    if (boundFields[i] == null) {
		boundFields[i] = new ObjectStreamField(
		    fname, spf.getType(), spf.isUnshared());
	    }
	}
	return boundFields;
    
private static java.io.ObjectStreamField[]getDefaultSerialFields(java.lang.Class cl)
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.

	Field[] clFields = cl.getDeclaredFields();
	ArrayList list = new ArrayList();
	int mask = Modifier.STATIC | Modifier.TRANSIENT;

	for (int i = 0; i < clFields.length; i++) {
	    if ((clFields[i].getModifiers() & mask) == 0) {
		list.add(new ObjectStreamField(clFields[i], false, true));
	    }
	}
	int size = list.size();
	return (size == 0) ? NO_FIELDS :
	    (ObjectStreamField[]) list.toArray(new ObjectStreamField[size]);
    
private static java.lang.reflect.ConstructorgetExternalizableConstructor(java.lang.Class cl)
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.

	try {
	    Constructor cons = cl.getDeclaredConstructor((Class[]) null);
	    cons.setAccessible(true);
	    return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? 
		cons : null;
	} catch (NoSuchMethodException ex) {
	    return null;
	}
    
java.io.ObjectStreamFieldgetField(java.lang.String name, java.lang.Class type)
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.

	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;
    
public java.io.ObjectStreamFieldgetField(java.lang.String name)
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.

	return getField(name, null);
    
java.io.ObjectStreamField[]getFields(boolean copy)
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.

	return copy ? (ObjectStreamField[]) fields.clone() : fields;
    
public java.io.ObjectStreamField[]getFields()
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

	return getFields(true);
    
private static java.lang.reflect.MethodgetInheritableMethod(java.lang.Class cl, java.lang.String name, java.lang.Class[] argTypes, java.lang.Class returnType)
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).

	Method meth = null;
	Class defCl = cl;
	while (defCl != null) {
	    try {
		meth = defCl.getDeclaredMethod(name, argTypes);
		break;
	    } catch (NoSuchMethodException ex) {
		defCl = defCl.getSuperclass();
	    }
	}

	if ((meth == null) || (meth.getReturnType() != returnType)) {
	    return null;
	}
	meth.setAccessible(true);
	int mods = meth.getModifiers();
	if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
	    return null;
	} else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
	    return meth;
	} else if ((mods & Modifier.PRIVATE) != 0) {
	    return (cl == defCl) ? meth : null;
	} else {
	    return packageEquals(cl, defCl) ? meth : null;
	}
    
java.io.ObjectStreamClassgetLocalDesc()
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.

	return localDesc;
    
private static java.lang.StringgetMethodSignature(java.lang.Class[] paramTypes, java.lang.Class retType)
Returns JVM type signature for given list of parameters and return type.

	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();
    
public java.lang.StringgetName()
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

	return name;
    
intgetNumObjFields()
Returns number of non-primitive serializable fields of represented class.

	return numObjFields;
    
voidgetObjFieldValues(java.lang.Object obj, java.lang.Object[] vals)
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.

	fieldRefl.getObjFieldValues(obj, vals);
    
private static java.lang.StringgetPackageName(java.lang.Class cl)
Returns package name of given class.

	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) : "";
    
intgetPrimDataSize()
Returns aggregate size (in bytes) of marshalled primitive field values for represented class.

	return primDataSize;
    
voidgetPrimFieldValues(java.lang.Object obj, byte[] buf)
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.

	fieldRefl.getPrimFieldValues(obj, buf);
    
private static java.lang.reflect.MethodgetPrivateMethod(java.lang.Class cl, java.lang.String name, java.lang.Class[] argTypes, java.lang.Class returnType)
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).

	try {
	    Method meth = cl.getDeclaredMethod(name, argTypes);
	    meth.setAccessible(true);
	    int mods = meth.getModifiers();
	    return ((meth.getReturnType() == returnType) &&
		    ((mods & Modifier.STATIC) == 0) &&
		    ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
	} catch (NoSuchMethodException ex) {
	    return null;
	}
    
private static java.io.ObjectStreamClass$FieldReflectorgetReflector(java.io.ObjectStreamField[] fields, java.io.ObjectStreamClass localDesc)
Matches given set of serializable fields with serializable fields described by the given local class descriptor, and returns a FieldReflector instance capable of setting/getting values from the subset of fields that match (non-matching fields are treated as filler, for which get operations return default values and set operations discard given values). Throws InvalidClassException if unresolvable type conflicts exist between the two sets of fields.

	// class irrelevant if no fields
	Class cl = (localDesc != null && fields.length > 0) ? 
	    localDesc.cl : null;
	processQueue(Caches.reflectorsQueue, Caches.reflectors);
	FieldReflectorKey key = new FieldReflectorKey(cl, fields, 
						      Caches.reflectorsQueue);
	Reference<?> ref = Caches.reflectors.get(key);
	Object entry = null;
	if (ref != null) {
	    entry = ref.get();
	}
	EntryFuture future = null;
	if (entry == null) {
	    EntryFuture newEntry = new EntryFuture();
	    Reference<?> newRef = new SoftReference<EntryFuture>(newEntry);
	    do {
		if (ref != null) {
		    Caches.reflectors.remove(key, ref);
		}
		ref = Caches.reflectors.putIfAbsent(key, newRef);
		if (ref != null) {
		    entry = ref.get();
		}
	    } while (ref != null && entry == null);
	    if (entry == null) {
		future = newEntry;
	    }
	}
	
	if (entry instanceof FieldReflector) {	// check common case first
	    return (FieldReflector) entry;
	} else if (entry instanceof EntryFuture) {
	    entry = ((EntryFuture) entry).get();
	} else if (entry == null) {
	    try {
		entry = new FieldReflector(matchFields(fields, localDesc));
	    } catch (Throwable th) {
		entry = th;
	    }
	    future.set(entry);
	    Caches.reflectors.put(key, new SoftReference<Object>(entry));
	}
	
	if (entry instanceof FieldReflector) {
	    return (FieldReflector) entry;
	} else if (entry instanceof InvalidClassException) {
	    throw (InvalidClassException) entry;
	} else if (entry instanceof RuntimeException) {
	    throw (RuntimeException) entry;
	} else if (entry instanceof Error) {
	    throw (Error) entry;
	} else {
	    throw new InternalError("unexpected entry: " + entry);
	}
    
java.lang.ClassNotFoundExceptiongetResolveException()
Returns ClassNotFoundException (if any) thrown while attempting to resolve local class corresponding to this class descriptor.

	return resolveEx;
    
private static java.io.ObjectStreamField[]getSerialFields(java.lang.Class cl)
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.

	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;
    
public longgetSerialVersionUID()
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

	// REMIND: synchronize instead of relying on volatile?
	if (suid == null) {
	    suid = (Long) AccessController.doPrivileged(
		new PrivilegedAction() {
		    public Object run() {
			return Long.valueOf(computeDefaultSUID(cl));
		    }
		}
	    );
	}
	return suid.longValue();
    
private static java.lang.reflect.ConstructorgetSerializableConstructor(java.lang.Class cl)
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).

	Class initCl = cl;
	while (Serializable.class.isAssignableFrom(initCl)) {
	    if ((initCl = initCl.getSuperclass()) == null) {
		return null;
	    }
	}
	try {
	    Constructor cons = initCl.getDeclaredConstructor((Class[]) null);
	    int mods = cons.getModifiers();
	    if ((mods & Modifier.PRIVATE) != 0 ||
		((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
		 !packageEquals(cl, initCl)))
	    {
		return null;
	    }
	    cons = reflFactory.newConstructorForSerialization(cl, cons);
	    cons.setAccessible(true);
	    return cons;
	} catch (NoSuchMethodException ex) {
	    return null;
	}
    
java.io.ObjectStreamClassgetSuperDesc()
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.

	return superDesc;
    
private java.io.ObjectStreamClassgetVariantFor(java.lang.Class cl)
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.

	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;
    
booleanhasBlockExternalData()
Returns true if class descriptor represents externalizable class that has written its data in 1.2 (block data) format, false otherwise.

	return hasBlockExternalData;
    
booleanhasReadObjectMethod()
Returns true if represented class is serializable (but not externalizable) and defines a conformant readObject method. Otherwise, returns false.

	return (readObjectMethod != null);
    
booleanhasReadObjectNoDataMethod()
Returns true if represented class is serializable (but not externalizable) and defines a conformant readObjectNoData method. Otherwise, returns false.

	return (readObjectNoDataMethod != null);
    
booleanhasReadResolveMethod()
Returns true if represented class is serializable or externalizable and defines a conformant readResolve method. Otherwise, returns false.

	return (readResolveMethod != null);
    
private static native booleanhasStaticInitializer(java.lang.Class cl)
Returns true if the given class defines a static initializer method, false otherwise.

booleanhasWriteObjectData()
Returns true if class descriptor represents serializable (but not externalizable) class which has written its data via a custom writeObject() method, false otherwise.

	return hasWriteObjectData;
    
booleanhasWriteObjectMethod()
Returns true if represented class is serializable (but not externalizable) and defines a conformant writeObject method. Otherwise, returns false.

	return (writeObjectMethod != null);
    
booleanhasWriteReplaceMethod()
Returns true if represented class is serializable or externalizable and defines a conformant writeReplace method. Otherwise, returns false.

	return (writeReplaceMethod != null);
    
private static native voidinitNative()
Initializes native code.

voidinitNonProxy(java.io.ObjectStreamClass model, java.lang.Class cl, java.lang.ClassNotFoundException resolveEx, java.io.ObjectStreamClass superDesc)
Initializes class descriptor representing a non-proxy class.

	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;
	    }
	}
	fieldRefl = getReflector(fields, localDesc);
	// reassign to matched fields so as to reflect local unshared settings
	fields = fieldRefl.getFields();
    
voidinitProxy(java.lang.Class cl, java.lang.ClassNotFoundException resolveEx, java.io.ObjectStreamClass superDesc)
Initializes class descriptor representing a proxy class.

	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;
	}
	fieldRefl = getReflector(fields, localDesc);
    
voidinvokeReadObject(java.lang.Object obj, java.io.ObjectInputStream in)
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.

	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();
	}
    
voidinvokeReadObjectNoData(java.lang.Object obj)
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.

	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();
	}
    
java.lang.ObjectinvokeReadResolve(java.lang.Object obj)
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.

	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();
	}
    
voidinvokeWriteObject(java.lang.Object obj, java.io.ObjectOutputStream out)
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.

	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();
	}
    
java.lang.ObjectinvokeWriteReplace(java.lang.Object obj)
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.

	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();
	}
    
booleanisEnum()
Returns true if class descriptor represents an enum type, false otherwise.

	return isEnum;
    
booleanisExternalizable()
Returns true if represented class implements Externalizable, false otherwise.

	return externalizable;
    
booleanisInstantiable()
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.

	return (cons != null);
    
booleanisProxy()
Returns true if class descriptor represents a dynamic proxy class, false otherwise.

	return isProxy;
    
booleanisSerializable()
Returns true if represented class implements Serializable, false otherwise.

	return serializable;
    
static java.io.ObjectStreamClasslookup(java.lang.Class cl, boolean all)
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

	if (!(all || Serializable.class.isAssignableFrom(cl))) {
	    return null;
	}
	processQueue(Caches.localDescsQueue, Caches.localDescs);
	WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
	Reference<?> ref = Caches.localDescs.get(key);
	Object entry = null;
	if (ref != null) {
	    entry = ref.get();
	}
	EntryFuture future = null;
	if (entry == null) {
	    EntryFuture newEntry = new EntryFuture();
	    Reference<?> newRef = new SoftReference<EntryFuture>(newEntry);
	    do {
		if (ref != null) {
		    Caches.localDescs.remove(key, ref);
		}
		ref = Caches.localDescs.putIfAbsent(key, newRef);
		if (ref != null) {
		    entry = ref.get();
		}
	    } while (ref != null && entry == null);
	    if (entry == null) {
		future = newEntry;
	    }
	}
	
	if (entry instanceof ObjectStreamClass) {  // check common case first
	    return (ObjectStreamClass) entry;
	}
	if (entry instanceof EntryFuture) {
	    future = (EntryFuture) entry;
	    if (future.getOwner() == Thread.currentThread()) {
		/*
		 * 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;
	    }
	    if (future.set(entry)) {
		Caches.localDescs.put(key, new SoftReference<Object>(entry));
	    } else {
		// 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);
	}
    
public static java.io.ObjectStreamClasslookup(java.lang.Class cl)
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

    
            
        
     
	initNative();
    
	return lookup(cl, false);
    
public static java.io.ObjectStreamClasslookupAny(java.lang.Class cl)
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

	return lookup(cl, true);
    
private static java.io.ObjectStreamField[]matchFields(java.io.ObjectStreamField[] fields, java.io.ObjectStreamClass localDesc)
Matches given set of serializable fields with serializable fields obtained from the given local class descriptor (which contain bindings to reflective Field objects). Returns list of ObjectStreamFields in which each ObjectStreamField whose signature matches that of a local field contains a Field object for that field; unmatched ObjectStreamFields contain null Field objects. Shared/unshared settings of the returned ObjectStreamFields also reflect those of matched local ObjectStreamFields. Throws InvalidClassException if unresolvable type conflicts exist between the two sets of fields.

	ObjectStreamField[] localFields = (localDesc != null) ?
	    localDesc.fields : NO_FIELDS;
	
	/*
	 * Even if fields == localFields, we cannot simply return localFields
	 * here.  In previous implementations of serialization,
	 * ObjectStreamField.getType() returned Object.class if the
	 * ObjectStreamField represented a non-primitive field and belonged to
	 * a non-local class descriptor.  To preserve this (questionable)
	 * behavior, the ObjectStreamField instances returned by matchFields
	 * cannot report non-primitive types other than Object.class; hence
	 * localFields cannot be returned directly.
	 */
	
	ObjectStreamField[] matches = new ObjectStreamField[fields.length];
	for (int i = 0; i < fields.length; i++) {
	    ObjectStreamField f = fields[i], m = null;
	    for (int j = 0; j < localFields.length; j++) {
		ObjectStreamField lf = localFields[j];
		if (f.getName().equals(lf.getName())) {
		    if ((f.isPrimitive() || lf.isPrimitive()) &&
			f.getTypeCode() != lf.getTypeCode())
		    {
			throw new InvalidClassException(localDesc.name,
			    "incompatible types for field " + f.getName());
		    }
		    if (lf.getField() != null) {
			m = new ObjectStreamField(
			    lf.getField(), lf.isUnshared(), false);
		    } else {
			m = new ObjectStreamField(
			    lf.getName(), lf.getSignature(), lf.isUnshared());
		    }
		}
	    }
	    if (m == null) {
		m = new ObjectStreamField(
		    f.getName(), f.getSignature(), false);
	    }
	    m.setOffset(f.getOffset());
	    matches[i] = m;
	}
	return matches;
    
java.lang.ObjectnewInstance()
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.

	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();
	}
    
private static booleanpackageEquals(java.lang.Class cl1, java.lang.Class cl2)
Returns true if classes are defined in the same runtime package, false otherwise.

	return (cl1.getClassLoader() == cl2.getClassLoader() &&
		getPackageName(cl1).equals(getPackageName(cl2)));
    
static voidprocessQueue(java.lang.ref.ReferenceQueue queue, java.util.concurrent.ConcurrentMap map)
Removes from the specified map any keys that have been enqueued on the specified reference queue.

	Reference<? extends Class<?>> ref;
	while((ref = queue.poll()) != null) {
	    map.remove(ref);
	}    
    
voidreadNonProxy(java.io.ObjectInputStream in)
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.

	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();
    
voidsetObjFieldValues(java.lang.Object obj, java.lang.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.

	fieldRefl.setObjFieldValues(obj, vals);
    
voidsetPrimFieldValues(java.lang.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.

	fieldRefl.setPrimFieldValues(obj, buf);
    
private static voidthrowMiscException(java.lang.Throwable th)
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).

	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;
	}
    
public java.lang.StringtoString()
Return a string describing this ObjectStreamClass.

	return name + ": static final long serialVersionUID = " + 
	    getSerialVersionUID() + "L;";
    
voidwriteNonProxy(java.io.ObjectOutputStream out)
Writes non-proxy class descriptor information to given output stream.

	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());
	    }
	}