FileDocCategorySizeDatePackage
ObjectStreamClass.javaAPI DocJava SE 6 API58268Tue Jun 10 00:21:34 BST 2008com.sun.corba.se.impl.io

ObjectStreamClass

public class ObjectStreamClass extends Object implements Serializable
A ObjectStreamClass describes a class that can be serialized to a stream or a class that was serialized to a stream. It contains the name and the serialVersionUID of the class.
The ObjectStreamClass for a specific class loaded in this Java VM can be found using the lookup method.
author
Roger Riggs
(#)ObjectStreamClass.java
1.17 99/06/07
since
JDK1.1

Fields Summary
private static final boolean
DEBUG_SVUID
public static final long
kDefaultUID
private static Object[]
noArgsList
private static Class[]
noTypesList
private static Hashtable
translatedFields
private static final Bridge
bridge
public static final int
CLASS_MASK
public static final int
FIELD_MASK
public static final int
METHOD_MASK
private static ObjectStreamClassEntry[]
descriptorFor
private String
name
private ObjectStreamClass
superclass
private boolean
serializable
private boolean
externalizable
private ObjectStreamField[]
fields
private Class
ofClass
boolean
forProxyClass
private long
suid
private String
suidStr
private long
actualSuid
private String
actualSuidStr
int
primBytes
int
objFields
private boolean
initialized
Flag indicating whether or not this instance has successfully completed initialization. This is to try to fix bug 4373844. Working to move to reusing java.io.ObjectStreamClass for JDK 1.5.
private Object
lock
private boolean
hasExternalizableBlockData
Method
writeObjectMethod
Method
readObjectMethod
private Method
writeReplaceObjectMethod
private Method
readResolveObjectMethod
private Constructor
cons
private String
rmiiiopOptionalDataRepId
Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a stream format version 2 which puts a fake valuetype around a Serializable's optional custom data. This valuetype has a special repository ID made from the Serializable's information which we are pre-computing and storing here.
private ObjectStreamClass
localClassDesc
private static Method
hasStaticInitializerMethod
private static Class
classSerializable
private static Class
classExternalizable
private static final long
serialVersionUID
use serialVersionUID from JDK 1.1. for interoperability
public static final ObjectStreamField[]
NO_FIELDS
Set serialPersistentFields of a Serializable class to this value to denote that the class has no Serializable fields.
private static Comparator
compareClassByName
private static final Comparator
compareObjStrFieldsByName
Comparator for ObjectStreamFields by name
private static Comparator
compareMemberByName
Constructors Summary
private ObjectStreamClass(Class cl, ObjectStreamClass superdesc, boolean serial, boolean extern)

	ofClass = cl;		/* created from this class */

        if (Proxy.isProxyClass(cl)) {
            forProxyClass = true;
        }

	name = cl.getName();
	superclass = superdesc;
	serializable = serial;
        if (!forProxyClass) {
            // proxy classes are never externalizable
            externalizable = extern;
        }

	/*
	 * Enter this class in the table of known descriptors.
	 * Otherwise, when the fields are read it may recurse
	 * trying to find the descriptor for itself.
	 */
	insertDescriptorFor(this);

        /*
         * The remainder of initialization occurs in init(), which is called
         * after the lock on the global class descriptor table has been
         * released.
         */
    
ObjectStreamClass(String n, long s)

	name = n;
	suid = s;
	superclass = null;
    
Methods Summary
private static long_computeSerialVersionUID(java.lang.Class cl)

    
    /*
     * Compute a hash for the specified class.  Incrementally add
     * items to the hash accumulating in the digest stream.
     * Fold the hash into a long.  Use the SHA secure hash function.
     */
         
	if (DEBUG_SVUID)
	    msg( "Computing SerialVersionUID for " + cl ) ; 
	ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);

	long h = 0;
	try {
	    MessageDigest md = MessageDigest.getInstance("SHA");
	    DigestOutputStream mdo = new DigestOutputStream(devnull, md);
	    DataOutputStream data = new DataOutputStream(mdo);

	    if (DEBUG_SVUID)
		msg( "\twriteUTF( \"" + cl.getName() + "\" )" ) ;
	    data.writeUTF(cl.getName());

	    int classaccess = cl.getModifiers();
	    classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
			    Modifier.INTERFACE | Modifier.ABSTRACT);

	    /* Workaround for javac bug that only set ABSTRACT for
	     * interfaces if the interface had some methods.
	     * The ABSTRACT bit reflects that the number of methods > 0.
	     * This is required so correct hashes can be computed
	     * for existing class files.
	     * Previously this hack was previously present in the VM.
	     */
            Method[] method = cl.getDeclaredMethods();
	    if ((classaccess & Modifier.INTERFACE) != 0) {
		classaccess &= (~Modifier.ABSTRACT);
		if (method.length > 0) {
		    classaccess |= Modifier.ABSTRACT;
		}
	    }

	    // Mask out any post-1.4 attributes
	    classaccess &= CLASS_MASK ;

	    if (DEBUG_SVUID)
		msg( "\twriteInt( " + classaccess + " ) " ) ;
	    data.writeInt(classaccess);

	    /*
	     * Get the list of interfaces supported,
	     * Accumulate their names their names in Lexical order
	     * and add them to the hash
	     */
            if (!cl.isArray()) {
                /* In 1.2fcs, getInterfaces() was modified to return
                 * {java.lang.Cloneable, java.io.Serializable} when
                 * called on array classes.  These values would upset
                 * the computation of the hash, so we explicitly omit
                 * them from its computation.
                 */

	        Class interfaces[] = cl.getInterfaces();
	        Arrays.sort(interfaces, compareClassByName);

	        for (int i = 0; i < interfaces.length; i++) {
		    if (DEBUG_SVUID)
			msg( "\twriteUTF( \"" + interfaces[i].getName() + "\" ) " ) ;
		    data.writeUTF(interfaces[i].getName());
	        }
	    }

	    /* Sort the field names to get a deterministic order */
            Field[] field = cl.getDeclaredFields();
	    Arrays.sort(field, compareMemberByName);

	    for (int i = 0; i < field.length; i++) {
		Field f = field[i];

		/* Include in the hash all fields except those that are
		 * private transient and private static.
		 */
		int m = f.getModifiers();
		if (Modifier.isPrivate(m) &&
		    (Modifier.isTransient(m) || Modifier.isStatic(m)))
		    continue;

		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"" + f.getName() + "\" ) " ) ;
		data.writeUTF(f.getName());

		// Mask out any post-1.4 bits
		m &= FIELD_MASK ;

		if (DEBUG_SVUID)
		    msg( "\twriteInt( " + m + " ) " ) ;
		data.writeInt(m);

		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"" + getSignature(f.getType()) + "\" ) " ) ;
		data.writeUTF(getSignature(f.getType()));
	    }

	    if (hasStaticInitializer(cl)) {
		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"<clinit>\" ) " ) ;
		data.writeUTF("<clinit>");

		if (DEBUG_SVUID)
		    msg( "\twriteInt( " + Modifier.STATIC + " )" ) ;
		data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have

		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"()V\" )" ) ;
		data.writeUTF("()V");
	    }

	    /*
	     * Get the list of constructors including name and signature
	     * Sort lexically, add all except the private constructors
	     * to the hash with their access flags
	     */

	    MethodSignature[] constructors =
		MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
	    for (int i = 0; i < constructors.length; i++) {
		MethodSignature c = constructors[i];
		String mname = "<init>";
		String desc = c.signature;
		desc = desc.replace('/", '.");
		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"" + mname + "\" )" ) ;
		data.writeUTF(mname);

		// mask out post-1.4 modifiers
		int modifier = c.member.getModifiers() & METHOD_MASK ;

		if (DEBUG_SVUID)
		    msg( "\twriteInt( " + modifier + " ) " ) ;
		data.writeInt( modifier ) ;

		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"" + desc+ "\" )" ) ;
		data.writeUTF(desc);
	    }

	    /* Include in the hash all methods except those that are
	     * private transient and private static.
	     */
	    MethodSignature[] methods =
		MethodSignature.removePrivateAndSort(method);
	    for (int i = 0; i < methods.length; i++ ) {
		MethodSignature m = methods[i];
		String desc = m.signature;
		desc = desc.replace('/", '.");

		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"" + m.member.getName()+ "\" )" ) ;
		data.writeUTF(m.member.getName());

		// mask out post-1.4 modifiers
		int modifier = m.member.getModifiers() & METHOD_MASK ;

		if (DEBUG_SVUID)
		    msg( "\twriteInt( " + modifier + " ) " ) ;
		data.writeInt( modifier ) ;

		if (DEBUG_SVUID)
		    msg( "\twriteUTF( \"" + desc + "\" )" ) ;
		data.writeUTF(desc);
	    }

	    /* Compute the hash value for this class.
	     * Use only the first 64 bits of the hash.
	     */
	    data.flush();
	    byte hasharray[] = md.digest();
	    for (int i = 0; i < Math.min(8, hasharray.length); i++) {
		h += (long)(hasharray[i] & 255) << (i * 8);
	    }
	} catch (IOException ignore) {
	    /* can't happen, but be deterministic anyway. */
	    h = -1;
	} catch (NoSuchAlgorithmException complain) {
	    SecurityException se = new SecurityException() ;
	    se.initCause( complain ) ;
	    throw se ;
	}

	return h;
    
static booleancompareClassNames(java.lang.String streamName, java.lang.String localName, char pkgSeparator)

	/* compare the class names, stripping off package names. */
	int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
	if (streamNameIndex < 0)
	    streamNameIndex = 0;

	int localNameIndex = localName.lastIndexOf(pkgSeparator);
	if (localNameIndex < 0)
	    localNameIndex = 0;

	return streamName.regionMatches(false, streamNameIndex,
					localName, localNameIndex,
					streamName.length() - streamNameIndex);
    
private voidcomputeFieldInfo()

	primBytes = 0;
	objFields = 0;

	for (int i = 0; i < fields.length; i++ ) {
	    switch (fields[i].getTypeCode()) {
	    case 'B":
	    case 'Z":
	    	primBytes += 1;
	    	break;
	    case 'C":
	    case 'S":
	    	primBytes += 2;
	    	break;

	    case 'I":
	    case 'F":
	    	primBytes += 4;
	    	break;
	    case 'J":
	    case 'D" :
	    	primBytes += 8;
	    	break;

	    case 'L":
	    case '[":
	    	objFields += 1;
	    	break;
	    }
	}
    
private java.lang.StringcomputeRMIIIOPOptionalDataRepId()
Java to IDL ptc-02-01-12 1.5.1 "The rep_id string passed to the start_value method must be 'RMI:org.omg.custom.class:hashcode:suid' where class is the fully-qualified name of the class whose writeObject method is being invoked and hashcode and suid are the class's hashcode and SUID."


        StringBuffer sbuf = new StringBuffer("RMI:org.omg.custom.");
        sbuf.append(RepositoryId.convertToISOLatin1(this.getName()));
        sbuf.append(':");
        sbuf.append(this.getActualSerialVersionUIDStr());
        sbuf.append(':");
        sbuf.append(this.getSerialVersionUIDStr());

        return sbuf.toString();
    
private static longcomputeStructuralUID(com.sun.corba.se.impl.io.ObjectStreamClass osc, java.lang.Class cl)

	ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
		
	long h = 0;
	try {

	    if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
		(cl.isInterface())){
		return 0;
	    }
			
	    if (java.io.Externalizable.class.isAssignableFrom(cl)) {
		return 1;
	    }

	    MessageDigest md = MessageDigest.getInstance("SHA");
	    DigestOutputStream mdo = new DigestOutputStream(devnull, md);
	    DataOutputStream data = new DataOutputStream(mdo);

	    // Get SUID of parent
	    Class parent = cl.getSuperclass();
	    if ((parent != null))  
	    // SerialBug 1; acc. to spec the one for 
	    // java.lang.object
	    // should be computed and put
	    //     && (parent != java.lang.Object.class)) 
	    {
				//data.writeLong(computeSerialVersionUID(null,parent));
		data.writeLong(computeStructuralUID(lookup(parent), parent));
	    }

	    if (osc.hasWriteObject())
		data.writeInt(2);
	    else
		data.writeInt(1);

            // CORBA formal 00-11-03 10.6.2:  For each field of the
            // class that is mapped to IDL, sorted lexicographically
            // by Java field name, in increasing order...
            ObjectStreamField[] field = osc.getFields();
            if (field.length > 1) {
                Arrays.sort(field, compareObjStrFieldsByName);
            }

            // ...Java field name in UTF encoding, field
            // descriptor, as defined by the JVM spec...
            for (int i = 0; i < field.length; i++) {
                data.writeUTF(field[i].getName());
                data.writeUTF(field[i].getSignature());
            }
			
	    /* Compute the hash value for this class.
	     * Use only the first 64 bits of the hash.
	     */
	    data.flush();
	    byte hasharray[] = md.digest();
	    // int minimum = Math.min(8, hasharray.length);
	    // SerialBug 3: SHA computation is wrong; for loop reversed
	    //for (int i = minimum; i > 0; i--) 
	    for (int i = 0; i < Math.min(8, hasharray.length); i++) {
		h += (long)(hasharray[i] & 255) << (i * 8);
	    }
	} catch (IOException ignore) {
	    /* can't happen, but be deterministic anyway. */
	    h = -1;
	} catch (NoSuchAlgorithmException complain) {
	    SecurityException se = new SecurityException();
	    se.initCause( complain ) ;
	    throw se ;
	}
	return h;
    
private static com.sun.corba.se.impl.io.ObjectStreamClassfindDescriptorFor(java.lang.Class cl)


    /*
     * findDescriptorFor a Class.  This looks in the cache for a
     * mapping from Class -> ObjectStreamClass mappings.  The hashCode
     * of the Class is used for the lookup since the Class is the key.
     * The entries are extended from java.lang.ref.SoftReference so the
     * gc will be able to free them if needed.
     */
         

	int hash = cl.hashCode();
	int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
	ObjectStreamClassEntry e;
	ObjectStreamClassEntry prev;

	/* Free any initial entries whose refs have been cleared */
	while ((e = descriptorFor[index]) != null && e.get() == null) {
	    descriptorFor[index] = e.next;
	}

	/* Traverse the chain looking for a descriptor with ofClass == cl.
	 * unlink entries that are unresolved.
	 */
	prev = e;
	while (e != null ) {
	    ObjectStreamClass desc = (ObjectStreamClass)(e.get());
	    if (desc == null) {
		// This entry has been cleared,  unlink it
		prev.next = e.next;
	    } else {
		if (desc.ofClass == cl)
		    return desc;
		prev = e;
	    }
	    e = e.next;
	}
	return null;
    
public final 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 ofClass;
    
public static final longgetActualSerialVersionUID(java.lang.Class clazz)
Return the actual (computed) serialVersionUID for this class.

	ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
	if( theosc != null )
	{
		return theosc.getActualSerialVersionUID( );
	}
	return 0;
    
public final longgetActualSerialVersionUID()
Return the actual (computed) serialVersionUID for this class.

	return actualSuid;
    
public final java.lang.StringgetActualSerialVersionUIDStr()
Return the actual (computed) serialVersionUID for this class.

	if (actualSuidStr == null)
	    actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
	return actualSuidStr;
    
private static java.lang.reflect.Field[]getDeclaredFields(java.lang.Class clz)

        return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                return clz.getDeclaredFields();
            }
        });
    
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(new Class[0]);
	    cons.setAccessible(true);
	    return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? 
		cons : null;
	} catch (NoSuchMethodException ex) {
	    return null;
	}
    
public final com.sun.corba.se.impl.io.ObjectStreamFieldgetField(java.lang.String name)
Get the field of this class by name.

return
The ObjectStreamField object of the named field or null if there is no such named field.

    	/* Binary search of fields by name.
	 */
    	for (int i = fields.length-1; i >= 0; i--) {
    	    if (name.equals(fields[i].getName())) {
    	    	return fields[i];
	    }
    	}
	return null;
    
public com.sun.corba.se.impl.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
JDK1.2

    	// Return a copy so the caller can't change the fields.
	if (fields.length > 0) {
	    ObjectStreamField[] dup = new ObjectStreamField[fields.length];
	    System.arraycopy(fields, 0, dup, 0, fields.length);
	    return dup;
	} else {
	    return fields;
	}
    
final com.sun.corba.se.impl.io.ObjectStreamField[]getFieldsNoCopy()

	return fields;
    
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). Copied from the Merlin java.io.ObjectStreamClass.

	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;
	}
    
public final java.lang.StringgetName()
The name of the class described by this descriptor.

	return name;
    
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;
	}
    
public final java.lang.StringgetRMIIIOPOptionalDataRepId()
This will return null if there is no writeObject method.

        return rmiiiopOptionalDataRepId;
    
public static final longgetSerialVersionUID(java.lang.Class clazz)
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.

	ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
        if( theosc != null )
	{
		return theosc.getSerialVersionUID( );
	}
	return 0;
    
public final 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.

	return suid;
    
public final java.lang.StringgetSerialVersionUIDStr()
Return the serialVersionUID string 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.

	if (suidStr == null)
	    suidStr = Long.toHexString(suid).toUpperCase();
	return suidStr;
    
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(new Class[0]);
	    int mods = cons.getModifiers();
	    if ((mods & Modifier.PRIVATE) != 0 ||
		((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
		 !packageEquals(cl, initCl)))
	    {
		return null;
	    }
	    cons = bridge.newConstructorForSerialization(cl, cons);
	    cons.setAccessible(true);
	    return cons;
	} catch (NoSuchMethodException ex) {
	    return null;
	}
    
static java.lang.StringgetSignature(java.lang.Class clazz)
Compute the JVM signature for the class.

	String type = null;
	if (clazz.isArray()) {
	    Class cl = clazz;
	    int dimensions = 0;
	    while (cl.isArray()) {
		dimensions++;
		cl = cl.getComponentType();
	    }
	    StringBuffer sb = new StringBuffer();
	    for (int i = 0; i < dimensions; i++) {
		sb.append("[");
	    }
	    sb.append(getSignature(cl));
	    type = sb.toString();
	} else if (clazz.isPrimitive()) {
	    if (clazz == Integer.TYPE) {
		type = "I";
	    } else if (clazz == Byte.TYPE) {
		type = "B";
	    } else if (clazz == Long.TYPE) {
		type = "J";
	    } else if (clazz == Float.TYPE) {
		type = "F";
	    } else if (clazz == Double.TYPE) {
		type = "D";
	    } else if (clazz == Short.TYPE) {
		type = "S";
	    } else if (clazz == Character.TYPE) {
		type = "C";
	    } else if (clazz == Boolean.TYPE) {
		type = "Z";
	    } else if (clazz == Void.TYPE) {
		type = "V";
	    }
	} else {
	    type = "L" + clazz.getName().replace('.", '/") + ";";
	}
	return type;
    
static java.lang.StringgetSignature(java.lang.reflect.Method meth)

	StringBuffer sb = new StringBuffer();

	sb.append("(");

	Class[] params = meth.getParameterTypes(); // avoid clone
	for (int j = 0; j < params.length; j++) {
	    sb.append(getSignature(params[j]));
	}
	sb.append(")");
	sb.append(getSignature(meth.getReturnType()));
	return sb.toString();
    
static java.lang.StringgetSignature(java.lang.reflect.Constructor cons)

	StringBuffer sb = new StringBuffer();

	sb.append("(");

	Class[] params = cons.getParameterTypes(); // avoid clone
	for (int j = 0; j < params.length; j++) {
	    sb.append(getSignature(params[j]));
	}
	sb.append(")V");
	return sb.toString();
    
final com.sun.corba.se.impl.io.ObjectStreamClassgetSuperclass()

	return superclass;
    
booleanhasExternalizableBlockDataMode()

	return hasExternalizableBlockData;
    
public booleanhasField(org.omg.CORBA.ValueMember field)

	try {
	    for (int i = 0; i < fields.length; i++) {
		if (fields[i].getName().equals(field.name)) {
		    if (fields[i].getSignature().equals(
			ValueUtility.getSignature(field)))
			return true;
		}
	    }
	} catch (Exception exc) {
	    // Ignore this; all we want to do is return false
	    // Note that ValueUtility.getSignature can throw checked exceptions.
	}

	return false;
    
final booleanhasReadObject()
Return whether the class has a readObject method

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

                      
         
        if (hasStaticInitializerMethod == null) {
            Class classWithThisMethod = null;
            
            try {
                try {
                    // When using rip-int with Merlin or when this is a Merlin
                    // workspace, the method we want is in sun.misc.ClassReflector
                    // and absent from java.io.ObjectStreamClass.
                    //
                    // When compiling rip-int with JDK 1.3.x, we have to get it
                    // from java.io.ObjectStreamClass.
                    classWithThisMethod = Class.forName("sun.misc.ClassReflector");
                } catch (ClassNotFoundException cnfe) {
                    // Do nothing.  This is either not a Merlin workspace,
                    // or rip-int is being compiled with something other than
                    // Merlin, probably JDK 1.3.  Fall back on java.io.ObjectStreaClass.
                }
                if (classWithThisMethod == null)
                    classWithThisMethod = java.io.ObjectStreamClass.class;
                
                hasStaticInitializerMethod =
                    classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
                                                          new Class[] { Class.class });
            } catch (NoSuchMethodException ex) {
            }
            
            if (hasStaticInitializerMethod == null) {
		// XXX I18N, logging needed
                throw new InternalError("Can't find hasStaticInitializer method on "
                                        + classWithThisMethod.getName());
            }
            hasStaticInitializerMethod.setAccessible(true);
        }

        try {
            Boolean retval = (Boolean)
                hasStaticInitializerMethod.invoke(null, new Object[] { cl });
            return retval.booleanValue();
        } catch (Exception ex) {
	    // XXX I18N, logging needed
            InternalError ie = new InternalError( "Error invoking hasStaticInitializer" ) ;
	    ie.initCause( ex ) ;
	    throw ie ;
        }
    
final booleanhasWriteObject()

	return writeObjectMethod != null ;
    
private voidinit()

      synchronized (lock) {

        // See description at definition of initialized.
        if (initialized)
            return;

	final Class cl = ofClass;

	if (!serializable ||
	    externalizable ||
	    forProxyClass ||
	    name.equals("java.lang.String")) {
	    fields = NO_FIELDS;
	} else if (serializable) {
            /* Ask for permission to override field access checks.
             */
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
		/* Fill in the list of persistent fields.
		 * If it is declared, use the declared serialPersistentFields.
		 * Otherwise, extract the fields from the class itself.
		 */
		try {
                    Field pf = cl.getDeclaredField("serialPersistentFields");
	            // serial bug 7; the serialPersistentFields were not
	            // being read and stored as Accessible bit was not set
		    pf.setAccessible(true);
	            // serial bug 7; need to find if the field is of type
	            // java.io.ObjectStreamField
                    java.io.ObjectStreamField[] f =
                           (java.io.ObjectStreamField[])pf.get(cl);
		    int mods = pf.getModifiers();
		    if ((Modifier.isPrivate(mods)) &&
			(Modifier.isStatic(mods)) &&
			(Modifier.isFinal(mods)))
	            {
			fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl));
		    }
		} catch (NoSuchFieldException e) {
		    fields = null;
		} catch (IllegalAccessException e) {
		    fields = null;
		} catch (IllegalArgumentException e) {
		    fields = null;
                } catch (ClassCastException e) {
                    /* Thrown if a field serialPersistentField exists
                     * but it is not of type ObjectStreamField.
                     */
                    fields = null;
                }


		if (fields == null) {
		    /* Get all of the declared fields for this
		     * Class. setAccessible on all fields so they
		     * can be accessed later.  Create a temporary
		     * ObjectStreamField array to hold each
		     * non-static, non-transient field. Then copy the
		     * temporary array into an array of the correct
		     * size once the number of fields is known.
		     */
                    Field[] actualfields = cl.getDeclaredFields();

		    int numFields = 0;
		    ObjectStreamField[] tempFields =
			new ObjectStreamField[actualfields.length];
		    for (int i = 0; i < actualfields.length; i++) {
			Field fld = actualfields[i] ;
			int modifiers = fld.getModifiers();
			if (!Modifier.isStatic(modifiers) &&
			    !Modifier.isTransient(modifiers)) {
			    fld.setAccessible(true) ;
			    tempFields[numFields++] = new ObjectStreamField(fld);
			}
		    }

		    fields = new ObjectStreamField[numFields];
		    System.arraycopy(tempFields, 0, fields, 0, numFields);

		} else {
		    // For each declared persistent field, look for an actual
		    // reflected Field. If there is one, make sure it's the correct
		    // type and cache it in the ObjectStreamClass for that field.
		    for (int j = fields.length-1; j >= 0; j--) {
			try {
                            Field reflField = cl.getDeclaredField(fields[j].getName());
			    if (fields[j].getType() == reflField.getType()) {
				reflField.setAccessible(true);
				fields[j].setField(reflField);
			    }
			} catch (NoSuchFieldException e) {
			    // Nothing to do
			}
		    }
		}
	        return null;
	    }
	    });

	    if (fields.length > 1)
		Arrays.sort(fields);

	    /* Set up field data for use while writing using the API api. */
	    computeFieldInfo();
	}

        /* Get the serialVersionUID from the class.
         * It uses the access override mechanism so make sure
         * the field objects is only used here.
         *
         * NonSerializable classes have a serialVerisonUID of 0L.
         */
         if (isNonSerializable()) {
             suid = 0L;
         } else {
             // Lookup special Serializable members using reflection.
             AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                if (forProxyClass) {
                    // proxy classes always have serialVersionUID of 0L
                    suid = 0L;
                } else {
	            try {
                        final Field f = cl.getDeclaredField("serialVersionUID");
	                int mods = f.getModifiers();
			// SerialBug 5:  static final SUID should be read
	                if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) {
                            f.setAccessible(true);
		            suid = f.getLong(cl);
			    // SerialBug 2: should be computed after writeObject
			    // actualSuid = computeStructuralUID(cl);
	                } else {
		            suid = _computeSerialVersionUID(cl);
	                    // SerialBug 2: should be computed after writeObject
	                    // actualSuid = computeStructuralUID(cl);
	                }
	            } catch (NoSuchFieldException ex) {
	                suid = _computeSerialVersionUID(cl);
	                // SerialBug 2: should be computed after writeObject
	                // actualSuid = computeStructuralUID(cl);
                    } catch (IllegalAccessException ex) {
                        suid = _computeSerialVersionUID(cl);
                    }
	        }

                writeReplaceObjectMethod = ObjectStreamClass.getInheritableMethod(cl, 
		    "writeReplace", noTypesList, Object.class);

                readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl, 
		    "readResolve", noTypesList, Object.class);
	
		if (externalizable) 
		    cons = getExternalizableConstructor(cl) ;
		else
		    cons = getSerializableConstructor(cl) ;

                if (serializable && !forProxyClass) {
	            /* Look for the writeObject method
	             * Set the accessible flag on it here. ObjectOutputStream
	             * will call it as necessary.
	             */
		    writeObjectMethod = getPrivateMethod( cl, "writeObject",
			new Class[] { java.io.ObjectOutputStream.class }, Void.TYPE ) ;
		    readObjectMethod = getPrivateMethod( cl, "readObject",
			new Class[] { java.io.ObjectInputStream.class }, Void.TYPE ) ;
	        }
	        return null;
	    }
	  });
	}

        // This call depends on a lot of information computed above!
        actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);

        // If we have a write object method, precompute the
        // RMI-IIOP stream format version 2 optional data
        // repository ID.  
        if (hasWriteObject())
            rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId();

        // This must be done last.
        initialized = true;
      }
    
private static voidinsertDescriptorFor(com.sun.corba.se.impl.io.ObjectStreamClass desc)

	// Make sure not already present
	if (findDescriptorFor(desc.ofClass) != null) {
	    return;
	}

	int hash = desc.ofClass.hashCode();
	int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
	ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
	e.next = descriptorFor[index];
       	descriptorFor[index] = e;
    
final booleanisCustomMarshaled()
Returns when or not this class should be custom marshaled (use chunking). This should happen if it is Externalizable OR if it or any of its superclasses has a writeObject method,

	return (hasWriteObject() || isExternalizable())
            || (superclass != null && superclass.isCustomMarshaled());
    
booleanisExternalizable()

	return externalizable;
    
booleanisNonSerializable()

        return ! (externalizable || serializable);
    
booleanisSerializable()

	return serializable;
    
final com.sun.corba.se.impl.io.ObjectStreamClasslocalClassDescriptor()

	return localClassDesc;
    
static final com.sun.corba.se.impl.io.ObjectStreamClasslookup(java.lang.Class cl)
Find the descriptor for a class that can be serialized. Null is returned if the specified class does not implement java.io.Serializable or java.io.Externalizable.


                                 
        
    
	ObjectStreamClass desc = lookupInternal(cl);
	if (desc.isSerializable() || desc.isExternalizable())
	    return desc;
	return null;
    
static com.sun.corba.se.impl.io.ObjectStreamClasslookupInternal(java.lang.Class cl)

	/* Synchronize on the hashtable so no two threads will do
	 * this at the same time.
	 */
	ObjectStreamClass desc = null;
	synchronized (descriptorFor) {
	    /* Find the matching descriptor if it already known */
	    desc = findDescriptorFor(cl);
	    if (desc == null) {
                /* Check if it's serializable */
                boolean serializable = classSerializable.isAssignableFrom(cl);

                /* If the class is only Serializable,
                 * lookup the descriptor for the superclass.
                 */
                ObjectStreamClass superdesc = null;
                if (serializable) {
                    Class superclass = cl.getSuperclass();
                    if (superclass != null)
                        superdesc = lookup(superclass);
                }

                /* Check if its' externalizable.
                 * If it's Externalizable, clear the serializable flag.
                 * Only one or the other may be set in the protocol.
                 */
                boolean externalizable = false;
                if (serializable) {
                    externalizable =
                        ((superdesc != null) && superdesc.isExternalizable()) ||
                        classExternalizable.isAssignableFrom(cl);
                    if (externalizable) {
                        serializable = false;
                    }
                }

                /* Create a new version descriptor,
                 * it put itself in the known table.
                 */
                desc = new ObjectStreamClass(cl, superdesc,
                                             serializable, externalizable);
            }
            // Must always call init.  See bug 4488137.  This code was
            // incorrectly changed to return immediately on a non-null
            // cache result.  That allowed threads to gain access to
            // unintialized instances.
            //
            // History: Note, the following init() call was originally within 
            // the synchronization block, as it currently is now. Later, the 
            // init() call was moved outside the synchronization block, and 
            // the init() method used a private member variable lock, to 
            // avoid performance problems. See bug 4165204. But that lead to 
            // a deadlock situation, see bug 5104239. Hence, the init() method 
            // has now been moved back into the synchronization block. The 
            // right approach to solving these problems would be to rewrite 
            // this class, based on the latest java.io.ObjectStreamClass. 
            desc.init();
	}

	return desc;
    
private static voidmsg(java.lang.String str)

	System.out.println( str ) ;
    
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(new Object[0]);
	    } catch (IllegalAccessException ex) {
		// should not occur, as access checks have been suppressed
		InternalError ie = new InternalError();
		ie.initCause( ex ) ;
		throw ie ;
	    }
	} else {
	    throw new UnsupportedOperationException();
	}
    
private static booleanpackageEquals(java.lang.Class cl1, java.lang.Class cl2)
Returns true if classes are defined in the same package, false otherwise. Copied from the Merlin java.io.ObjectStreamClass.

	Package pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage();
	return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2))));
    
public java.lang.ObjectreadResolve(java.lang.Object value)

	if (readResolveObjectMethod != null) {
	    try {
		return readResolveObjectMethod.invoke(value,noArgsList);
	    } catch(Throwable t) {
		throw new RuntimeException(t);
	    }
	}
	else return value;
    
final voidsetClass(java.lang.Class cl)


	if (cl == null) {
	    localClassDesc = null;
	    ofClass = null;
	    computeFieldInfo();
	    return;
	}

	localClassDesc = lookupInternal(cl);
	if (localClassDesc == null)
	    // XXX I18N, logging needed
	    throw new InvalidClassException(cl.getName(),
					    "Local class not compatible");
	if (suid != localClassDesc.suid) {

            /* Check for exceptional cases that allow mismatched suid. */

            /* Allow adding Serializable or Externalizable
             * to a later release of the class.
             */
            boolean addedSerialOrExtern =
                isNonSerializable() || localClassDesc.isNonSerializable();

	    /* Disregard the serialVersionUID of an array
	     * when name and cl.Name differ. If resolveClass() returns
	     * an array with a different package name,
	     * the serialVersionUIDs will not match since the fully
	     * qualified array class is used in the
	     * computation of the array's serialVersionUID. There is
	     * no way to set a permanent serialVersionUID for an array type.
	     */

            boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));

            if (! arraySUID && ! addedSerialOrExtern ) {
		// XXX I18N, logging needed
		throw new InvalidClassException(cl.getName(),
						"Local class not compatible:" +
						" stream classdesc serialVersionUID=" + suid +
						" local class serialVersionUID=" + localClassDesc.suid);
	    }
        }

	/* compare the class names, stripping off package names. */
	if (! compareClassNames(name, cl.getName(), '."))
	    // XXX I18N, logging needed
            throw new InvalidClassException(cl.getName(),
                         "Incompatible local class name. " +
                         "Expected class name compatible with " +
                         name);

	/*
	 * Test that both implement either serializable or externalizable.
	 */

	// The next check is more generic, since it covers the
	// Proxy case, the JDK 1.3 serialization code has
	// both checks
        //if ((serializable && localClassDesc.externalizable) ||
        //    (externalizable && localClassDesc.serializable))
        //    throw new InvalidClassException(localCl.getName(),
        //            "Serializable is incompatible with Externalizable");

        if ((serializable != localClassDesc.serializable) ||
            (externalizable != localClassDesc.externalizable) ||
	    (!serializable && !externalizable))

	    // XXX I18N, logging needed
	    throw new InvalidClassException(cl.getName(),
					    "Serialization incompatible with Externalization");

	/* Set up the reflected Fields in the class where the value of each
	 * field in this descriptor should be stored.
	 * Each field in this ObjectStreamClass (the source) is located (by
	 * name) in the ObjectStreamClass of the class(the destination).
	 * In the usual (non-versioned case) the field is in both
	 * descriptors and the types match, so the reflected Field is copied.
	 * If the type does not match, a InvalidClass exception is thrown.
	 * If the field is not present in the class, the reflected Field
	 * remains null so the field will be read but discarded.
	 * If extra fields are present in the class they are ignored. Their
	 * values will be set to the default value by the object allocator.
	 * Both the src and dest field list are sorted by type and name.
	 */

	ObjectStreamField[] destfield =
	    (ObjectStreamField[])localClassDesc.fields;
	ObjectStreamField[] srcfield =
	    (ObjectStreamField[])fields;

	int j = 0;
    nextsrc:
	for (int i = 0; i < srcfield.length; i++ ) {
	    /* Find this field in the dest*/
	    for (int k = j; k < destfield.length; k++) {
		if (srcfield[i].getName().equals(destfield[k].getName())) {
		    /* found match */
		    if (srcfield[i].isPrimitive() &&
			!srcfield[i].typeEquals(destfield[k])) {
			// XXX I18N, logging needed
			throw new InvalidClassException(cl.getName(),
							"The type of field " +
							srcfield[i].getName() +
							" of class " + name +
							" is incompatible.");
		    }

		    /* Skip over any fields in the dest that are not in the src */
		    j = k;

		    srcfield[i].setField(destfield[j].getField());
		    // go on to the next source field
		    continue nextsrc;
		}
	    }
	}

	/* Set up field data for use while reading from the input stream. */
	computeFieldInfo();

	/* Remember the class this represents */
	ofClass = cl;

        /* get the cache of these methods from the local class
         * implementation.
         */
        readObjectMethod = localClassDesc.readObjectMethod;
        readResolveObjectMethod = localClassDesc.readResolveObjectMethod;
    
final voidsetSuperclass(com.sun.corba.se.impl.io.ObjectStreamClass s)

	superclass = s;
    
public final java.lang.StringtoString()
Return a string describing this ObjectStreamClass.

	StringBuffer sb = new StringBuffer();

	sb.append(name);
	sb.append(": static final long serialVersionUID = ");
	sb.append(Long.toString(suid));
	sb.append("L;");
	return sb.toString();
    
private static java.lang.Object[]translateFields(java.lang.Object[] objs)

        try{
            java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs;
            Object translation[] = null;
                       
            if (translatedFields == null)
                translatedFields = new Hashtable();
                       
            translation = (Object[])translatedFields.get(fields);
                       
            if (translation != null)
                return translation;
            else {
                Class osfClass = Class.forName("com.sun.corba.se.impl.io.ObjectStreamField");
                translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
                Object arg[] = new Object[2];
                Class types[] = {String.class, Class.class};
                Constructor constructor = osfClass.getDeclaredConstructor(types);
                for (int i = fields.length -1; i >= 0; i--){
                    arg[0] = fields[i].getName();
                    arg[1] = fields[i].getType();
                       
                    translation[i] = constructor.newInstance(arg);
                }
                translatedFields.put(fields, translation);
                       
            }

            return (Object[])translation;
        }
        catch(Throwable t){
            NoSuchFieldException nsfe = new NoSuchFieldException();
	    nsfe.initCause( t ) ;
	    throw nsfe ;
        }
    
final booleantypeEquals(com.sun.corba.se.impl.io.ObjectStreamClass other)

	return (suid == other.suid) &&
	    compareClassNames(name, other.name, '.");
    
public java.io.SerializablewriteReplace(java.io.Serializable value)

	if (writeReplaceObjectMethod != null) {
	    try {
		return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
	    } catch(Throwable t) {
		throw new RuntimeException(t);
	    }
	}
	else return value;