- /*
- * @(#)ObjectStreamClass_1_3_1.java 1.3 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- /*
- * Licensed Materials - Property of IBM
- * RMI-IIOP v1.0
- * Copyright IBM Corp. 1998 1999 All Rights Reserved
- *
- * US Government Users Restricted Rights - Use, duplication or
- * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
- */
-
- package com.sun.corba.se.internal.orbutil;
-
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.security.DigestOutputStream;
- import java.security.AccessController;
- import java.security.PrivilegedExceptionAction;
- import java.security.PrivilegedActionException;
- import java.security.PrivilegedAction;
-
- import java.lang.reflect.Modifier;
- import java.lang.reflect.Array;
- import java.lang.reflect.Field;
- import java.lang.reflect.Member;
- import java.lang.reflect.Method;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Proxy;
- import java.lang.reflect.InvocationTargetException;
-
- import java.io.IOException;
- import java.io.DataOutputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.InvalidClassException;
- import java.io.Serializable;
-
- import java.util.Arrays;
- import java.util.Comparator;
- import java.util.Hashtable;
-
- import org.omg.CORBA.ValueMember;
-
- import com.sun.corba.se.internal.io.ValueUtility;
- import com.sun.corba.se.internal.io.ObjectStreamClass;
-
- /**
- * This is duplicated here to preserve the JDK 1.3.1FCS behavior
- * of calculating the OMG hash code incorrectly when serialPersistentFields
- * is used, but some of the fields no longer exist in the class itself.
- *
- * We have to duplicate it since we aren't allowed to modify the
- * com.sun.corba.se.internal.io version further, and can't make it
- * public outside of its package for security reasons.
- */
- /**
- * A ObjectStreamClass_1_3_1 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.
- * <br>
- * The ObjectStreamClass_1_3_1 for a specific class loaded in this Java VM can
- * be found using the lookup method.
- *
- * @author Roger Riggs
- * @(#)ObjectStreamClass_1_3_1.java 1.17 99/06/07
- * @since JDK1.1
- */
- public class ObjectStreamClass_1_3_1 implements java.io.Serializable {
-
- public static final long kDefaultUID = -1;
-
- private static Object noArgsList[] = {};
- private static Class noTypesList[] = {};
-
- private static Hashtable translatedFields;
-
- static {
- try{
- Class.forName("com.sun.corba.se.internal.io.LibraryManager").getDeclaredMethod("load",null).invoke(null,null);
- }
- catch(Throwable t){}
- }
-
- /** 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.
- */
- static final ObjectStreamClass_1_3_1 lookup(Class cl)
- {
- ObjectStreamClass_1_3_1 desc = lookupInternal(cl);
- if (desc.isSerializable() || desc.isExternalizable())
- return desc;
- return null;
- }
-
- /*
- * Find the class descriptor for the specified class.
- * Package access only so it can be called from ObjectIn/OutStream.
- */
- static ObjectStreamClass_1_3_1 lookupInternal(Class cl)
- {
- /* Synchronize on the hashtable so no two threads will do
- * this at the same time.
- */
- ObjectStreamClass_1_3_1 desc = null;
- synchronized (descriptorFor) {
- /* Find the matching descriptor if it already known */
- desc = findDescriptorFor(cl);
- if (desc != null) {
- return desc;
- }
-
- /* Check if it's serializable */
- boolean serializable = classSerializable.isAssignableFrom(cl);
- /* If the class is only Serializable,
- * lookup the descriptor for the superclass.
- */
- ObjectStreamClass_1_3_1 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_1_3_1(cl, superdesc,
- serializable, externalizable);
- }
- desc.init();
- return desc;
- }
-
- /**
- * The name of the class described by this descriptor.
- */
- public final String getName() {
- return name;
- }
-
- /**
- * Return the serialVersionUID for this class.
- * The serialVersionUID defines a set of classes all with the same name
- * that have evolved from a common root class and agree to be serialized
- * and deserialized using a common format.
- */
- public static final long getSerialVersionUID( java.lang.Class clazz) {
- ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
- if( theosc != null )
- {
- return theosc.getSerialVersionUID( );
- }
- return 0;
- }
-
- /**
- * 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.
- */
- public final long getSerialVersionUID() {
- return suid;
- }
-
- /**
- * 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.
- */
- public final String getSerialVersionUIDStr() {
- if (suidStr == null)
- suidStr = Long.toHexString(suid).toUpperCase();
- return suidStr;
- }
-
- /**
- * Return the actual (computed) serialVersionUID for this class.
- */
- public static final long getActualSerialVersionUID( java.lang.Class clazz )
- {
- ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
- if( theosc != null )
- {
- return theosc.getActualSerialVersionUID( );
- }
- return 0;
- }
-
- /**
- * Return the actual (computed) serialVersionUID for this class.
- */
- public final long getActualSerialVersionUID() {
- return actualSuid;
- }
-
- /**
- * Return the actual (computed) serialVersionUID for this class.
- */
- public final String getActualSerialVersionUIDStr() {
- if (actualSuidStr == null)
- actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
- return actualSuidStr;
- }
-
- /**
- * Return the class in the local VM that this version is mapped to.
- * Null is returned if there is no corresponding local class.
- */
- public final Class forClass() {
- return ofClass;
- }
-
- /**
- * 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
- */
- public ObjectStreamField[] getFields() {
- // 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;
- }
- }
-
- public boolean hasField(ValueMember field){
-
- for (int i = 0; i < fields.length; i++){
- try{
- if (fields[i].getName().equals(field.name)) {
-
- if (fields[i].getSignature().equals(ValueUtility.getSignature(field)))
- return true;
- }
- }
- catch(Throwable t){}
- }
- return false;
- }
-
- /* Avoid unnecessary allocations. */
- final ObjectStreamField[] getFieldsNoCopy() {
- return fields;
- }
-
- /**
- * 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.
- */
- public final ObjectStreamField getField(String name) {
- /* 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 Serializable writeReplace(Serializable value) {
- if (writeReplaceObjectMethod != null) {
- try {
- return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
- }
- catch(Throwable t) {
- throw new RuntimeException(t.getMessage());
- }
- }
- else return value;
- }
-
- public Object readResolve(Object value) {
- if (readResolveObjectMethod != null) {
- try {
- return readResolveObjectMethod.invoke(value,noArgsList);
- }
- catch(Throwable t) {
- throw new RuntimeException(t.getMessage());
- }
- }
- else return value;
- }
-
- /**
- * Return a string describing this ObjectStreamClass_1_3_1.
- */
- public final String toString() {
- StringBuffer sb = new StringBuffer();
-
- sb.append(name);
- sb.append(": static final long serialVersionUID = ");
- sb.append(Long.toString(suid));
- sb.append("L;");
- return sb.toString();
- }
-
- /*
- * Create a new ObjectStreamClass_1_3_1 from a loaded class.
- * Don't call this directly, call lookup instead.
- */
- private ObjectStreamClass_1_3_1(java.lang.Class cl, ObjectStreamClass_1_3_1 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.
- */
- }
-
- /*
- * Initialize class descriptor. This method is only invoked on class
- * descriptors created via calls to lookupInternal(). This method is kept
- * separate from the ObjectStreamClass_1_3_1 constructor so that lookupInternal
- * does not have to hold onto a global class descriptor table lock while the
- * class descriptor is being initialized (see bug 4165204).
- */
-
-
- private void init() {
- synchronized (lock) {
-
- final Class cl = ofClass;
-
- if (fields != null) // already initialized
- return;
-
-
- 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++) {
- int modifiers = actualfields[i].getModifiers();
- if (!Modifier.isStatic(modifiers) &&
- !Modifier.isTransient(modifiers)) {
- tempFields[numFields++] =
- new ObjectStreamField(actualfields[i]);
- }
- }
- 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_1_3_1 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);
- // get rid of native code
- // suid = getSerialVersionUIDField(cl);
- // SerialBug 2: should be computed after writeObject
- // actualSuid = computeStructuralUID(cl);
- } else {
- suid = ObjectStreamClass.getSerialVersionUID(cl);
- // SerialBug 2: should be computed after writeObject
- // actualSuid = computeStructuralUID(cl);
- }
- } catch (NoSuchFieldException ex) {
- suid = ObjectStreamClass.getSerialVersionUID(cl);
- // SerialBug 2: should be computed after writeObject
- // actualSuid = computeStructuralUID(cl);
- } catch (IllegalAccessException ex) {
- suid = ObjectStreamClass.getSerialVersionUID(cl);
- }
- }
-
-
- try {
- writeReplaceObjectMethod = cl.getDeclaredMethod("writeReplace", noTypesList);
- if (Modifier.isStatic(writeReplaceObjectMethod.getModifiers())) {
- writeReplaceObjectMethod = null;
- } else {
- writeReplaceObjectMethod.setAccessible(true);
- }
-
- } catch (NoSuchMethodException e2) {
-
- }
-
- try {
- readResolveObjectMethod = cl.getDeclaredMethod("readResolve", noTypesList);
- if (Modifier.isStatic(readResolveObjectMethod.getModifiers())) {
- readResolveObjectMethod = null;
- } else {
- readResolveObjectMethod.setAccessible(true);
- }
-
- } catch (NoSuchMethodException e2) {
-
- }
-
- /* Cache lookup of writeObject and readObject for
- * Serializable classes. (Do not lookup for
- * Externalizable)
- */
-
- if (serializable && !forProxyClass) {
-
- /* Look for the writeObject method
- * Set the accessible flag on it here. ObjectOutputStream
- * will call it as necessary.
- */
- try {
- Class[] args = {java.io.ObjectOutputStream.class};
- writeObjectMethod = cl.getDeclaredMethod("writeObject", args);
- hasWriteObjectMethod = true;
- int mods = writeObjectMethod.getModifiers();
-
- // Method must be private and non-static
- if (!Modifier.isPrivate(mods) ||
- Modifier.isStatic(mods)) {
- writeObjectMethod = null;
- hasWriteObjectMethod = false;
- }
-
- } catch (NoSuchMethodException e) {
- }
-
- /* Look for the readObject method
- * set the access override and save the reference for
- * ObjectInputStream so it can all the method directly.
- */
- try {
- Class[] args = {java.io.ObjectInputStream.class};
- readObjectMethod = cl.getDeclaredMethod("readObject", args);
- int mods = readObjectMethod.getModifiers();
-
- // Method must be private and non-static
- if (!Modifier.isPrivate(mods) ||
- Modifier.isStatic(mods)) {
- readObjectMethod = null;
- }
- } catch (NoSuchMethodException e) {
- }
- // Compute the structural UID. This must be done after the
- // calculation for writeObject. Fixed 4/20/2000, eea1
- // SerialBug 2: to have correct value in RepId
- }
- return null;
- }
- });
- }
-
- actualSuid = computeStructuralUID(this, cl);
- }
-
- }
-
- /*
- * Create an empty ObjectStreamClass_1_3_1 for a class about to be read.
- * This is separate from read so ObjectInputStream can assign the
- * wire handle early, before any nested ObjectStreamClass_1_3_1 might
- * be read.
- */
- ObjectStreamClass_1_3_1(String n, long s) {
- name = n;
- suid = s;
- superclass = null;
- }
-
- private static Object[] translateFields(Object objs[])
- throws NoSuchFieldException {
- 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 = com.sun.corba.se.internal.orbutil.ObjectStreamField.class;
-
- 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){
- throw new NoSuchFieldException();
- }
- }
-
- /* Compare the base class names of streamName and localName.
- *
- * @return Return true iff the base class name compare.
- * @parameter streamName Fully qualified class name.
- * @parameter localName Fully qualified class name.
- * @parameter pkgSeparator class names use either '.' or '/'.
- *
- * Only compare base class name to allow package renaming.
- */
- static boolean compareClassNames(String streamName,
- 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);
- }
-
- /*
- * Compare the types of two class descriptors.
- * They match if they have the same class name and suid
- */
- final boolean typeEquals(ObjectStreamClass_1_3_1 other) {
- return (suid == other.suid) &&
- compareClassNames(name, other.name, '.');
- }
-
- /*
- * Return the superclass descriptor of this descriptor.
- */
- final void setSuperclass(ObjectStreamClass_1_3_1 s) {
- superclass = s;
- }
-
- /*
- * Return the superclass descriptor of this descriptor.
- */
- final ObjectStreamClass_1_3_1 getSuperclass() {
- return superclass;
- }
-
- /*
- * Return whether the class has a writeObject method
- */
- final boolean hasWriteObject() {
- return hasWriteObjectMethod;
- }
-
- final boolean isCustomMarshaled() {
- return (hasWriteObject() || isExternalizable());
- }
-
- /*
- * Return true if all instances of 'this' Externalizable class
- * are written in block-data mode from the stream that 'this' was read
- * from. <p>
- *
- * In JDK 1.1, all Externalizable instances are not written
- * in block-data mode.
- * In JDK 1.2, all Externalizable instances, by default, are written
- * in block-data mode and the Externalizable instance is terminated with
- * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
- * instances.
- *
- * IMPLEMENTATION NOTE:
- * This should have been a mode maintained per stream; however,
- * for compatibility reasons, it was only possible to record
- * this change per class. All Externalizable classes within
- * a given stream should either have this mode enabled or
- * disabled. This is enforced by not allowing the PROTOCOL_VERSION
- * of a stream to he changed after any objects have been written.
- *
- * @see ObjectOuputStream#useProtocolVersion
- * @see ObjectStreamConstants#PROTOCOL_VERSION_1
- * @see ObjectStreamConstants#PROTOCOL_VERSION_2
- *
- * @since JDK 1.2
- */
- boolean hasExternalizableBlockDataMode() {
- return hasExternalizableBlockData;
- }
-
- /*
- * Return the ObjectStreamClass_1_3_1 of the local class this one is based on.
- */
- final ObjectStreamClass_1_3_1 localClassDescriptor() {
- return localClassDesc;
- }
-
- /*
- * Get the Serializability of the class.
- */
- boolean isSerializable() {
- return serializable;
- }
-
- /*
- * Get the externalizability of the class.
- */
- boolean isExternalizable() {
- return externalizable;
- }
-
- boolean isNonSerializable() {
- return ! (externalizable || serializable);
- }
-
- /*
- * Calculate the size of the array needed to store primitive data and the
- * number of object references to read when reading from the input
- * stream.
- */
- private void computeFieldInfo() {
- 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 static long computeStructuralUID(ObjectStreamClass_1_3_1 osc, 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);
-
- /* Sort the field names to get a deterministic order */
- // Field[] field = ObjectStreamClass_1_3_1.getDeclaredFields(cl);
-
- ObjectStreamField[] fields = osc.getFields();
-
- // Must make sure that the Field array we allocate
- // below is exactly the right size. Bug fix for
- // 4397133.
- int numNonNullFields = 0;
- for (int i = 0; i < fields.length; i++)
- if (fields[i].getField() != null)
- numNonNullFields++;
-
- Field [] field = new java.lang.reflect.Field[numNonNullFields];
- for (int i = 0, fieldNum = 0; i < fields.length; i++) {
- if (fields[i].getField() != null) {
- field[fieldNum++] = fields[i].getField();
- }
- }
-
- if (field.length > 1)
- 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
- * transient
- */
- int m = f.getModifiers();
- //Serial 6
- //if (Modifier.isTransient(m) || Modifier.isStatic(m))
- // spec reference 00-01-06.pdf, 1.3.5.6, states non-static
- // non-transient, public fields are mapped to Java IDL.
- //
- // Here's the quote from the first paragraph:
- // Java non-static non-transient public fields are mapped to
- // OMG IDL public data members, and other Java fields are
- // not mapped.
-
- // if (Modifier.isTransient(m) || Modifier.isStatic(m))
- // continue;
-
- data.writeUTF(f.getName());
- data.writeUTF(getSignature(f.getType()));
- }
-
- /* 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) {
- throw new SecurityException(complain.getMessage());
- }
- return h;
- }
-
- /**
- * Compute the JVM signature for the class.
- */
- static String getSignature(Class clazz) {
- 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;
- }
-
- /*
- * Compute the JVM method descriptor for the method.
- */
- static String getSignature(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();
- }
-
- /*
- * Compute the JVM constructor descriptor for the constructor.
- */
- static String getSignature(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();
- }
-
- /*
- * Cache of Class -> ClassDescriptor Mappings.
- */
- static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
-
- /*
- * 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.
- */
- private static ObjectStreamClass_1_3_1 findDescriptorFor(Class cl) {
-
- 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_1_3_1 desc = (ObjectStreamClass_1_3_1)(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;
- }
-
- /*
- * insertDescriptorFor a Class -> ObjectStreamClass_1_3_1 mapping.
- */
- private static void insertDescriptorFor(ObjectStreamClass_1_3_1 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;
- }
-
- private static Field[] getDeclaredFields(final Class clz) {
- return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- return clz.getDeclaredFields();
- }
- });
- }
-
-
- /*
- * The name of this descriptor
- */
- private String name;
-
- /*
- * The descriptor of the supertype.
- */
- private ObjectStreamClass_1_3_1 superclass;
-
- /*
- * Flags for Serializable and Externalizable.
- */
- private boolean serializable;
- private boolean externalizable;
-
- /*
- * Array of persistent fields of this class, sorted by
- * type and name.
- */
- private ObjectStreamField[] fields;
-
- /*
- * Class that is a descriptor for in this virtual machine.
- */
- private Class ofClass;
-
- /*
- * True if descriptor for a proxy class.
- */
- boolean forProxyClass;
-
-
- /*
- * SerialVersionUID for this class.
- */
- private long suid = kDefaultUID;
- private String suidStr = null;
-
- /*
- * Actual (computed) SerialVersionUID for this class.
- */
- private long actualSuid = kDefaultUID;
- private String actualSuidStr = null;
-
- /*
- * The total number of bytes of primitive fields.
- * The total number of object fields.
- */
- int primBytes;
- int objFields;
-
- /* Internal lock object. */
- private Object lock = new Object();
-
- /* True if this class has/had a writeObject method */
- private boolean hasWriteObjectMethod;
-
- /* In JDK 1.1, external data was not written in block mode.
- * As of JDK 1.2, external data is written in block data mode. This
- * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
- *
- * @since JDK 1.2
- */
- private boolean hasExternalizableBlockData;
- Method writeObjectMethod;
- Method readObjectMethod;
- private Method writeReplaceObjectMethod;
- private Method readResolveObjectMethod;
-
- /*
- * ObjectStreamClass_1_3_1 that this one was built from.
- */
- private ObjectStreamClass_1_3_1 localClassDesc;
-
- /* Get the private static final field for serial version UID */
- // private static native long getSerialVersionUIDField(Class cl);
-
- /* The Class Object for java.io.Serializable */
- private static Class classSerializable = null;
- private static Class classExternalizable = null;
-
- /*
- * Resolve java.io.Serializable at load time.
- */
- static {
- try {
- classSerializable = Class.forName("java.io.Serializable");
- classExternalizable = Class.forName("java.io.Externalizable");
- } catch (Throwable e) {
- System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
- }
- }
-
- /** use serialVersionUID from JDK 1.1. for interoperability */
- private static final long serialVersionUID = -6120832682080437368L;
-
- /**
- * Set serialPersistentFields of a Serializable class to this value to
- * denote that the class has no Serializable fields.
- */
- public static final ObjectStreamField[] NO_FIELDS =
- new ObjectStreamField[0];
-
- /*
- * Entries held in the Cache of known ObjectStreamClass_1_3_1 objects.
- * Entries are chained together with the same hash value (modulo array size).
- */
- private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
- {
- ObjectStreamClassEntry(ObjectStreamClass_1_3_1 c) {
- //super(c);
- this.c = c;
- }
- ObjectStreamClassEntry next;
-
- public Object get()
- {
- return c;
- }
- private ObjectStreamClass_1_3_1 c;
- }
-
- /*
- * Comparator object for Classes and Interfaces
- */
- private static Comparator compareClassByName =
- new CompareClassByName();
-
- private static class CompareClassByName implements Comparator {
- public int compare(Object o1, Object o2) {
- Class c1 = (Class)o1;
- Class c2 = (Class)o2;
- return (c1.getName()).compareTo(c2.getName());
- }
- }
-
- /*
- * Comparator object for Members, Fields, and Methods
- */
- private static Comparator compareMemberByName =
- new CompareMemberByName();
-
- private static class CompareMemberByName implements Comparator {
- public int compare(Object o1, Object o2) {
- String s1 = ((Member)o1).getName();
- String s2 = ((Member)o2).getName();
-
- if (o1 instanceof Method) {
- s1 += getSignature((Method)o1);
- s2 += getSignature((Method)o2);
- } else if (o1 instanceof Constructor) {
- s1 += getSignature((Constructor)o1);
- s2 += getSignature((Constructor)o2);
- }
- return s1.compareTo(s2);
- }
- }
-
- /* It is expensive to recompute a method or constructor signature
- many times, so compute it only once using this data structure. */
- private static class MethodSignature implements Comparator {
- Member member;
- String signature; // cached parameter signature
-
- /* Given an array of Method or Constructor members,
- return a sorted array of the non-private members.*/
- /* A better implementation would be to implement the returned data
- structure as an insertion sorted link list.*/
- static MethodSignature[] removePrivateAndSort(Member[] m) {
- int numNonPrivate = 0;
- for (int i = 0; i < m.length; i++) {
- if (! Modifier.isPrivate(m[i].getModifiers())) {
- numNonPrivate++;
- }
- }
- MethodSignature[] cm = new MethodSignature[numNonPrivate];
- int cmi = 0;
- for (int i = 0; i < m.length; i++) {
- if (! Modifier.isPrivate(m[i].getModifiers())) {
- cm[cmi] = new MethodSignature(m[i]);
- cmi++;
- }
- }
- if (cmi > 0)
- Arrays.sort(cm, cm[0]);
- return cm;
- }
-
- /* Assumes that o1 and o2 are either both methods
- or both constructors.*/
- public int compare(Object o1, Object o2) {
- /* Arrays.sort calls compare when o1 and o2 are equal.*/
- if (o1 == o2)
- return 0;
-
- MethodSignature c1 = (MethodSignature)o1;
- MethodSignature c2 = (MethodSignature)o2;
-
- int result;
- if (isConstructor()) {
- result = c1.signature.compareTo(c2.signature);
- } else { // is a Method.
- result = c1.member.getName().compareTo(c2.member.getName());
- if (result == 0)
- result = c1.signature.compareTo(c2.signature);
- }
- return result;
- }
-
- final private boolean isConstructor() {
- return member instanceof Constructor;
- }
- private MethodSignature(Member m) {
- member = m;
- if (isConstructor()) {
- signature = ObjectStreamClass_1_3_1.getSignature((Constructor)m);
- } else {
- signature = ObjectStreamClass_1_3_1.getSignature((Method)m);
- }
- }
- }
- }