mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1162 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1162 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Java
		
	
	
	
/* ObjectStreamClass.java -- Class used to write class information
 | 
						|
   about serialized objects.
 | 
						|
   Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package java.io;
 | 
						|
 | 
						|
import gnu.java.io.NullOutputStream;
 | 
						|
import gnu.java.lang.reflect.TypeSignature;
 | 
						|
import gnu.java.security.action.SetAccessibleAction;
 | 
						|
import gnu.java.security.provider.Gnu;
 | 
						|
 | 
						|
import java.lang.reflect.Constructor;
 | 
						|
import java.lang.reflect.Field;
 | 
						|
import java.lang.reflect.Member;
 | 
						|
import java.lang.reflect.Method;
 | 
						|
import java.lang.reflect.Modifier;
 | 
						|
import java.lang.reflect.Proxy;
 | 
						|
import java.security.AccessController;
 | 
						|
import java.security.DigestOutputStream;
 | 
						|
import java.security.MessageDigest;
 | 
						|
import java.security.NoSuchAlgorithmException;
 | 
						|
import java.security.PrivilegedAction;
 | 
						|
import java.security.Security;
 | 
						|
import java.util.Arrays;
 | 
						|
import java.util.Comparator;
 | 
						|
import java.util.Hashtable;
 | 
						|
 | 
						|
/**
 | 
						|
 * @author Tom Tromey (tromey@redhat.com)
 | 
						|
 * @author Jeroen Frijters (jeroen@frijters.net)
 | 
						|
 * @author Guilhem Lavaux (guilhem@kaffe.org)
 | 
						|
 * @author Michael Koch (konqueror@gmx.de)
 | 
						|
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 | 
						|
 */
 | 
						|
public class ObjectStreamClass implements Serializable
 | 
						|
{
 | 
						|
  static final ObjectStreamField[] INVALID_FIELDS = new ObjectStreamField[0];
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the <code>ObjectStreamClass</code> for <code>cl</code>.
 | 
						|
   * If <code>cl</code> is null, or is not <code>Serializable</code>,
 | 
						|
   * null is returned.  <code>ObjectStreamClass</code>'s are memorized;
 | 
						|
   * later calls to this method with the same class will return the
 | 
						|
   * same <code>ObjectStreamClass</code> object and no recalculation
 | 
						|
   * will be done.
 | 
						|
   *
 | 
						|
   * Warning: If this class contains an invalid serialPersistentField arrays
 | 
						|
   * lookup will not throw anything. However {@link #getFields()} will return
 | 
						|
   * an empty array and {@link java.io.ObjectOutputStream#writeObject} will throw an
 | 
						|
   * {@link java.io.InvalidClassException}.
 | 
						|
   *
 | 
						|
   * @see java.io.Serializable
 | 
						|
   */
 | 
						|
  public static ObjectStreamClass lookup(Class<?> cl)
 | 
						|
  {
 | 
						|
    if (cl == null)
 | 
						|
      return null;
 | 
						|
    if (! (Serializable.class).isAssignableFrom(cl))
 | 
						|
      return null;
 | 
						|
 | 
						|
    return lookupForClassObject(cl);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This lookup for internal use by ObjectOutputStream.  Suppose
 | 
						|
   * we have a java.lang.Class object C for class A, though A is not
 | 
						|
   * serializable, but it's okay to serialize C.
 | 
						|
   */
 | 
						|
  static ObjectStreamClass lookupForClassObject(Class cl)
 | 
						|
  {
 | 
						|
    if (cl == null)
 | 
						|
      return null;
 | 
						|
 | 
						|
    ObjectStreamClass osc = classLookupTable.get(cl);
 | 
						|
 | 
						|
    if (osc != null)
 | 
						|
      return osc;
 | 
						|
    else
 | 
						|
      {
 | 
						|
        osc = new ObjectStreamClass(cl);
 | 
						|
        classLookupTable.put(cl, osc);
 | 
						|
        return osc;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the name of the class that this
 | 
						|
   * <code>ObjectStreamClass</code> represents.
 | 
						|
   *
 | 
						|
   * @return the name of the class.
 | 
						|
   */
 | 
						|
  public String getName()
 | 
						|
  {
 | 
						|
    return name;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the class that this <code>ObjectStreamClass</code>
 | 
						|
   * represents.  Null could be returned if this
 | 
						|
   * <code>ObjectStreamClass</code> was read from an
 | 
						|
   * <code>ObjectInputStream</code> and the class it represents cannot
 | 
						|
   * be found or loaded.
 | 
						|
   *
 | 
						|
   * @see java.io.ObjectInputStream
 | 
						|
   */
 | 
						|
  public Class<?> forClass()
 | 
						|
  {
 | 
						|
    return clazz;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the serial version stream-unique identifier for the class
 | 
						|
   * represented by this <code>ObjectStreamClass</code>.  This SUID is
 | 
						|
   * either defined by the class as <code>static final long
 | 
						|
   * serialVersionUID</code> or is calculated as specified in
 | 
						|
   * Javasoft's "Object Serialization Specification" XXX: add reference
 | 
						|
   *
 | 
						|
   * @return the serial version UID.
 | 
						|
   */
 | 
						|
  public long getSerialVersionUID()
 | 
						|
  {
 | 
						|
    return uid;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the serializable (non-static and non-transient) Fields
 | 
						|
   * of the class represented by this ObjectStreamClass.  The Fields
 | 
						|
   * are sorted by name.
 | 
						|
   * If fields were obtained using serialPersistentFields and this array
 | 
						|
   * is faulty then the returned array of this method will be empty.
 | 
						|
   *
 | 
						|
   * @return the fields.
 | 
						|
   */
 | 
						|
  public ObjectStreamField[] getFields()
 | 
						|
  {
 | 
						|
    ObjectStreamField[] copy = new ObjectStreamField[ fields.length ];
 | 
						|
    System.arraycopy(fields, 0, copy, 0, fields.length);
 | 
						|
    return copy;
 | 
						|
  }
 | 
						|
 | 
						|
  // XXX doc
 | 
						|
  // Can't do binary search since fields is sorted by name and
 | 
						|
  // primitiveness.
 | 
						|
  public ObjectStreamField getField (String name)
 | 
						|
  {
 | 
						|
    for (int i = 0; i < fields.length; i++)
 | 
						|
      if (fields[i].getName().equals(name))
 | 
						|
        return fields[i];
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a textual representation of this
 | 
						|
   * <code>ObjectStreamClass</code> object including the name of the
 | 
						|
   * class it represents as well as that class's serial version
 | 
						|
   * stream-unique identifier.
 | 
						|
   *
 | 
						|
   * @see #getSerialVersionUID()
 | 
						|
   * @see #getName()
 | 
						|
   */
 | 
						|
  public String toString()
 | 
						|
  {
 | 
						|
    return "java.io.ObjectStreamClass< " + name + ", " + uid + " >";
 | 
						|
  }
 | 
						|
 | 
						|
  // Returns true iff the class that this ObjectStreamClass represents
 | 
						|
  // has the following method:
 | 
						|
  //
 | 
						|
  // private void writeObject (ObjectOutputStream)
 | 
						|
  //
 | 
						|
  // This method is used by the class to override default
 | 
						|
  // serialization behavior.
 | 
						|
  boolean hasWriteMethod()
 | 
						|
  {
 | 
						|
    return (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0;
 | 
						|
  }
 | 
						|
 | 
						|
  // Returns true iff the class that this ObjectStreamClass represents
 | 
						|
  // implements Serializable but does *not* implement Externalizable.
 | 
						|
  boolean isSerializable()
 | 
						|
  {
 | 
						|
    return (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  // Returns true iff the class that this ObjectStreamClass represents
 | 
						|
  // implements Externalizable.
 | 
						|
  boolean isExternalizable()
 | 
						|
  {
 | 
						|
    return (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
 | 
						|
  }
 | 
						|
 | 
						|
  // Returns true iff the class that this ObjectStreamClass represents
 | 
						|
  // implements Externalizable.
 | 
						|
  boolean isEnum()
 | 
						|
  {
 | 
						|
    return (flags & ObjectStreamConstants.SC_ENUM) != 0;
 | 
						|
  }
 | 
						|
 | 
						|
  // Returns the <code>ObjectStreamClass</code> that represents the
 | 
						|
  // class that is the superclass of the class this
 | 
						|
  // <code>ObjectStreamClass</code> represents.  If the superclass is
 | 
						|
  // not Serializable, null is returned.
 | 
						|
  ObjectStreamClass getSuper()
 | 
						|
  {
 | 
						|
    return superClass;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * returns an array of ObjectStreamClasses that represent the super
 | 
						|
   * classes of the class represented by this and the class
 | 
						|
   * represented by this itself in order from most super to this.
 | 
						|
   * ObjectStreamClass[0] is the highest superclass of this that is
 | 
						|
   * serializable.
 | 
						|
   *
 | 
						|
   * The result of consecutive calls this hierarchy() will be the same
 | 
						|
   * array instance.
 | 
						|
   *
 | 
						|
   * @return an array of ObjectStreamClass representing the
 | 
						|
   * super-class hierarchy of serializable classes.
 | 
						|
   */
 | 
						|
  ObjectStreamClass[] hierarchy()
 | 
						|
  {
 | 
						|
    ObjectStreamClass[] result = hierarchy;
 | 
						|
    if (result == null)
 | 
						|
        {
 | 
						|
        int d = 0;
 | 
						|
 | 
						|
        for(ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
 | 
						|
          d++;
 | 
						|
 | 
						|
        result = new ObjectStreamClass[d];
 | 
						|
 | 
						|
        for (ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
 | 
						|
          {
 | 
						|
            result[--d] = osc;
 | 
						|
          }
 | 
						|
 | 
						|
        hierarchy = result;
 | 
						|
      }
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Cache for hierarchy() result.
 | 
						|
   */
 | 
						|
  private ObjectStreamClass[] hierarchy = null;
 | 
						|
 | 
						|
  // Returns an integer that consists of bit-flags that indicate
 | 
						|
  // properties of the class represented by this ObjectStreamClass.
 | 
						|
  // The bit-flags that could be present are those defined in
 | 
						|
  // ObjectStreamConstants that begin with `SC_'
 | 
						|
  int getFlags()
 | 
						|
  {
 | 
						|
    return flags;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  ObjectStreamClass(String name, long uid, byte flags,
 | 
						|
                    ObjectStreamField[] fields)
 | 
						|
  {
 | 
						|
    this.name = name;
 | 
						|
    this.uid = uid;
 | 
						|
    this.flags = flags;
 | 
						|
    this.fields = fields;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method builds the internal description corresponding to a Java Class.
 | 
						|
   * As the constructor only assign a name to the current ObjectStreamClass instance,
 | 
						|
   * that method sets the serial UID, chose the fields which will be serialized,
 | 
						|
   * and compute the position of the fields in the serialized stream.
 | 
						|
   *
 | 
						|
   * @param cl The Java class which is used as a reference for building the descriptor.
 | 
						|
   * @param superClass The descriptor of the super class for this class descriptor.
 | 
						|
   * @throws InvalidClassException if an incompatibility between computed UID and
 | 
						|
   * already set UID is found.
 | 
						|
   */
 | 
						|
  void setClass(Class cl, ObjectStreamClass superClass) throws InvalidClassException
 | 
						|
  {hierarchy = null;
 | 
						|
    this.clazz = cl;
 | 
						|
 | 
						|
    cacheMethods();
 | 
						|
 | 
						|
    long class_uid = getClassUID(cl);
 | 
						|
    if (uid == 0)
 | 
						|
      uid = class_uid;
 | 
						|
    else
 | 
						|
      {
 | 
						|
        // Check that the actual UID of the resolved class matches the UID from
 | 
						|
        // the stream. Mismatches for array classes are ignored.
 | 
						|
        if (!cl.isArray() && uid != class_uid)
 | 
						|
          {
 | 
						|
            String msg = cl +
 | 
						|
              ": Local class not compatible: stream serialVersionUID="
 | 
						|
              + uid + ", local serialVersionUID=" + class_uid;
 | 
						|
            throw new InvalidClassException (msg);
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    isProxyClass = clazz != null && Proxy.isProxyClass(clazz);
 | 
						|
    this.superClass = superClass;
 | 
						|
    calculateOffsets();
 | 
						|
 | 
						|
    try
 | 
						|
      {
 | 
						|
        ObjectStreamField[] exportedFields = getSerialPersistentFields (clazz);
 | 
						|
 | 
						|
        if (exportedFields == null)
 | 
						|
          return;
 | 
						|
 | 
						|
        ObjectStreamField[] newFieldList = new ObjectStreamField[exportedFields.length + fields.length];
 | 
						|
        int i, j, k;
 | 
						|
 | 
						|
        /* We now check the import fields against the exported fields.
 | 
						|
         * There should not be contradiction (e.g. int x and String x)
 | 
						|
         * but extra virtual fields can be added to the class.
 | 
						|
         */
 | 
						|
 | 
						|
        Arrays.sort(exportedFields);
 | 
						|
 | 
						|
        i = 0; j = 0; k = 0;
 | 
						|
        while (i < fields.length && j < exportedFields.length)
 | 
						|
          {
 | 
						|
            int comp = fields[i].compareTo(exportedFields[j]);
 | 
						|
 | 
						|
            if (comp < 0)
 | 
						|
              {
 | 
						|
                newFieldList[k] = fields[i];
 | 
						|
                fields[i].setPersistent(false);
 | 
						|
                fields[i].setToSet(false);
 | 
						|
                i++;
 | 
						|
              }
 | 
						|
            else if (comp > 0)
 | 
						|
              {
 | 
						|
                /* field not found in imported fields. We add it
 | 
						|
                 * in the list of supported fields.
 | 
						|
                 */
 | 
						|
                newFieldList[k] = exportedFields[j];
 | 
						|
                newFieldList[k].setPersistent(true);
 | 
						|
                newFieldList[k].setToSet(false);
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    newFieldList[k].lookupField(clazz);
 | 
						|
                    newFieldList[k].checkFieldType();
 | 
						|
                  }
 | 
						|
                catch (NoSuchFieldException _)
 | 
						|
                  {
 | 
						|
                  }
 | 
						|
                j++;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    exportedFields[j].lookupField(clazz);
 | 
						|
                    exportedFields[j].checkFieldType();
 | 
						|
                  }
 | 
						|
                catch (NoSuchFieldException _)
 | 
						|
                  {
 | 
						|
                  }
 | 
						|
 | 
						|
                if (!fields[i].getType().equals(exportedFields[j].getType()))
 | 
						|
                  throw new InvalidClassException
 | 
						|
                    ("serialPersistentFields must be compatible with" +
 | 
						|
                     " imported fields (about " + fields[i].getName() + ")");
 | 
						|
                newFieldList[k] = fields[i];
 | 
						|
                fields[i].setPersistent(true);
 | 
						|
                i++;
 | 
						|
                j++;
 | 
						|
              }
 | 
						|
            k++;
 | 
						|
          }
 | 
						|
 | 
						|
        if (i < fields.length)
 | 
						|
          for (;i<fields.length;i++,k++)
 | 
						|
            {
 | 
						|
              fields[i].setPersistent(false);
 | 
						|
              fields[i].setToSet(false);
 | 
						|
              newFieldList[k] = fields[i];
 | 
						|
            }
 | 
						|
        else
 | 
						|
          if (j < exportedFields.length)
 | 
						|
            for (;j<exportedFields.length;j++,k++)
 | 
						|
              {
 | 
						|
                exportedFields[j].setPersistent(true);
 | 
						|
                exportedFields[j].setToSet(false);
 | 
						|
                newFieldList[k] = exportedFields[j];
 | 
						|
              }
 | 
						|
 | 
						|
        fields = new ObjectStreamField[k];
 | 
						|
        System.arraycopy(newFieldList, 0, fields, 0, k);
 | 
						|
      }
 | 
						|
    catch (NoSuchFieldException ignore)
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    catch (IllegalAccessException ignore)
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  void setSuperclass (ObjectStreamClass osc)
 | 
						|
  {
 | 
						|
    superClass = osc;
 | 
						|
    hierarchy = null;
 | 
						|
  }
 | 
						|
 | 
						|
  void calculateOffsets()
 | 
						|
  {
 | 
						|
    int i;
 | 
						|
    ObjectStreamField field;
 | 
						|
    primFieldSize = 0;
 | 
						|
    int fcount = fields.length;
 | 
						|
    for (i = 0; i < fcount; ++ i)
 | 
						|
      {
 | 
						|
        field = fields[i];
 | 
						|
 | 
						|
        if (! field.isPrimitive())
 | 
						|
          break;
 | 
						|
 | 
						|
        field.setOffset(primFieldSize);
 | 
						|
        switch (field.getTypeCode())
 | 
						|
          {
 | 
						|
          case 'B':
 | 
						|
          case 'Z':
 | 
						|
            ++ primFieldSize;
 | 
						|
            break;
 | 
						|
          case 'C':
 | 
						|
          case 'S':
 | 
						|
            primFieldSize += 2;
 | 
						|
            break;
 | 
						|
          case 'I':
 | 
						|
          case 'F':
 | 
						|
            primFieldSize += 4;
 | 
						|
            break;
 | 
						|
          case 'D':
 | 
						|
          case 'J':
 | 
						|
            primFieldSize += 8;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    for (objectFieldCount = 0; i < fcount; ++ i)
 | 
						|
      fields[i].setOffset(objectFieldCount++);
 | 
						|
  }
 | 
						|
 | 
						|
  private Method findMethod(Method[] methods, String name, Class[] params,
 | 
						|
                            Class returnType, boolean mustBePrivate)
 | 
						|
  {
 | 
						|
outer:
 | 
						|
    for (int i = 0; i < methods.length; i++)
 | 
						|
    {
 | 
						|
        final Method m = methods[i];
 | 
						|
        int mods = m.getModifiers();
 | 
						|
        if (Modifier.isStatic(mods)
 | 
						|
            || (mustBePrivate && !Modifier.isPrivate(mods)))
 | 
						|
        {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        if (m.getName().equals(name)
 | 
						|
           && m.getReturnType() == returnType)
 | 
						|
        {
 | 
						|
            Class[] mp = m.getParameterTypes();
 | 
						|
            if (mp.length == params.length)
 | 
						|
            {
 | 
						|
                for (int j = 0; j < mp.length; j++)
 | 
						|
                {
 | 
						|
                    if (mp[j] != params[j])
 | 
						|
                    {
 | 
						|
                        continue outer;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                AccessController.doPrivileged(new SetAccessibleAction(m));
 | 
						|
                return m;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  private static boolean inSamePackage(Class c1, Class c2)
 | 
						|
  {
 | 
						|
    String name1 = c1.getName();
 | 
						|
    String name2 = c2.getName();
 | 
						|
 | 
						|
    int id1 = name1.lastIndexOf('.');
 | 
						|
    int id2 = name2.lastIndexOf('.');
 | 
						|
 | 
						|
    // Handle the default package
 | 
						|
    if (id1 == -1 || id2 == -1)
 | 
						|
      return id1 == id2;
 | 
						|
 | 
						|
    String package1 = name1.substring(0, id1);
 | 
						|
    String package2 = name2.substring(0, id2);
 | 
						|
 | 
						|
    return package1.equals(package2);
 | 
						|
  }
 | 
						|
 | 
						|
  final static Class[] noArgs = new Class[0];
 | 
						|
 | 
						|
  private static Method findAccessibleMethod(String name, Class from)
 | 
						|
  {
 | 
						|
    for (Class c = from; c != null; c = c.getSuperclass())
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            Method res = c.getDeclaredMethod(name, noArgs);
 | 
						|
            int mods = res.getModifiers();
 | 
						|
 | 
						|
            if (c == from
 | 
						|
                || Modifier.isProtected(mods)
 | 
						|
                || Modifier.isPublic(mods)
 | 
						|
                || (! Modifier.isPrivate(mods) && inSamePackage(c, from)))
 | 
						|
              {
 | 
						|
                AccessController.doPrivileged(new SetAccessibleAction(res));
 | 
						|
                return res;
 | 
						|
              }
 | 
						|
          }
 | 
						|
        catch (NoSuchMethodException e)
 | 
						|
          {
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Helper routine to check if a class was loaded by boot or
 | 
						|
   * application class loader.  Classes for which this is not the case
 | 
						|
   * should not be cached since caching prevent class file garbage
 | 
						|
   * collection.
 | 
						|
   *
 | 
						|
   * @param cl a class
 | 
						|
   *
 | 
						|
   * @return true if cl was loaded by boot or application class loader,
 | 
						|
   *         false if cl was loaded by a user class loader.
 | 
						|
   */
 | 
						|
  private static boolean loadedByBootOrApplicationClassLoader(Class cl)
 | 
						|
  {
 | 
						|
    ClassLoader l = cl.getClassLoader();
 | 
						|
    return
 | 
						|
      (   l == null                             /* boot loader */       )
 | 
						|
      || (l == ClassLoader.getSystemClassLoader() /* application loader */);
 | 
						|
  }
 | 
						|
 | 
						|
  static Hashtable methodCache = new Hashtable();
 | 
						|
 | 
						|
  static final Class[] readObjectSignature  = { ObjectInputStream.class };
 | 
						|
  static final Class[] writeObjectSignature = { ObjectOutputStream.class };
 | 
						|
 | 
						|
  private void cacheMethods()
 | 
						|
  {
 | 
						|
    Class cl = forClass();
 | 
						|
    Method[] cached = (Method[]) methodCache.get(cl);
 | 
						|
    if (cached == null)
 | 
						|
      {
 | 
						|
        cached = new Method[4];
 | 
						|
        Method[] methods = cl.getDeclaredMethods();
 | 
						|
 | 
						|
        cached[0] = findMethod(methods, "readObject",
 | 
						|
                               readObjectSignature,
 | 
						|
                               Void.TYPE, true);
 | 
						|
        cached[1] = findMethod(methods, "writeObject",
 | 
						|
                               writeObjectSignature,
 | 
						|
                               Void.TYPE, true);
 | 
						|
 | 
						|
        // readResolve and writeReplace can be in parent classes, as long as they
 | 
						|
        // are accessible from this class.
 | 
						|
        cached[2] = findAccessibleMethod("readResolve", cl);
 | 
						|
        cached[3] = findAccessibleMethod("writeReplace", cl);
 | 
						|
 | 
						|
        /* put in cache if classes not loaded by user class loader.
 | 
						|
         * For a user class loader, the cache may otherwise grow
 | 
						|
         * without limit.
 | 
						|
         */
 | 
						|
        if (loadedByBootOrApplicationClassLoader(cl))
 | 
						|
          methodCache.put(cl,cached);
 | 
						|
      }
 | 
						|
    readObjectMethod   = cached[0];
 | 
						|
    writeObjectMethod  = cached[1];
 | 
						|
    readResolveMethod  = cached[2];
 | 
						|
    writeReplaceMethod = cached[3];
 | 
						|
  }
 | 
						|
 | 
						|
  private ObjectStreamClass(Class cl)
 | 
						|
  {
 | 
						|
    uid = 0;
 | 
						|
    flags = 0;
 | 
						|
    isProxyClass = Proxy.isProxyClass(cl);
 | 
						|
 | 
						|
    clazz = cl;
 | 
						|
    cacheMethods();
 | 
						|
    name = cl.getName();
 | 
						|
    setFlags(cl);
 | 
						|
    setFields(cl);
 | 
						|
    // to those class nonserializable, its uid field is 0
 | 
						|
    if ( (Serializable.class).isAssignableFrom(cl) && !isProxyClass)
 | 
						|
      uid = getClassUID(cl);
 | 
						|
    superClass = lookup(cl.getSuperclass());
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  // Sets bits in flags according to features of CL.
 | 
						|
  private void setFlags(Class cl)
 | 
						|
  {
 | 
						|
    if ((java.io.Externalizable.class).isAssignableFrom(cl))
 | 
						|
      flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
 | 
						|
    else if ((java.io.Serializable.class).isAssignableFrom(cl))
 | 
						|
      // only set this bit if CL is NOT Externalizable
 | 
						|
      flags |= ObjectStreamConstants.SC_SERIALIZABLE;
 | 
						|
 | 
						|
    if (writeObjectMethod != null)
 | 
						|
      flags |= ObjectStreamConstants.SC_WRITE_METHOD;
 | 
						|
 | 
						|
    if (cl.isEnum() || cl == Enum.class)
 | 
						|
      flags |= ObjectStreamConstants.SC_ENUM;
 | 
						|
  }
 | 
						|
 | 
						|
/* GCJ LOCAL */
 | 
						|
  // FIXME: This is a workaround for a fairly obscure bug that happens
 | 
						|
  // when reading a Proxy and then writing it back out again.  The
 | 
						|
  // result is that the ObjectStreamClass doesn't have its fields set,
 | 
						|
  // generating a NullPointerException.  Rather than this kludge we
 | 
						|
  // should probably fix the real bug, but it would require a fairly
 | 
						|
  // radical reorganization to do so.
 | 
						|
  final void ensureFieldsSet(Class cl)
 | 
						|
  {
 | 
						|
    if (! fieldsSet)
 | 
						|
      setFields(cl);
 | 
						|
  }
 | 
						|
/* END GCJ LOCAL */
 | 
						|
 | 
						|
 | 
						|
  // Sets fields to be a sorted array of the serializable fields of
 | 
						|
  // clazz.
 | 
						|
  private void setFields(Class cl)
 | 
						|
  {
 | 
						|
/* GCJ LOCAL */
 | 
						|
    fieldsSet = true;
 | 
						|
/* END GCJ LOCAL */
 | 
						|
 | 
						|
    SetAccessibleAction setAccessible = new SetAccessibleAction();
 | 
						|
 | 
						|
    if (!isSerializable() || isExternalizable() || isEnum())
 | 
						|
      {
 | 
						|
        fields = NO_FIELDS;
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
    try
 | 
						|
      {
 | 
						|
        final Field f =
 | 
						|
          cl.getDeclaredField("serialPersistentFields");
 | 
						|
        setAccessible.setMember(f);
 | 
						|
        AccessController.doPrivileged(setAccessible);
 | 
						|
        int modifiers = f.getModifiers();
 | 
						|
 | 
						|
        if (Modifier.isStatic(modifiers)
 | 
						|
            && Modifier.isFinal(modifiers)
 | 
						|
            && Modifier.isPrivate(modifiers))
 | 
						|
          {
 | 
						|
            fields = getSerialPersistentFields(cl);
 | 
						|
            if (fields != null)
 | 
						|
              {
 | 
						|
                ObjectStreamField[] fieldsName = new ObjectStreamField[fields.length];
 | 
						|
                System.arraycopy(fields, 0, fieldsName, 0, fields.length);
 | 
						|
 | 
						|
                Arrays.sort (fieldsName, new Comparator() {
 | 
						|
                        public int compare(Object o1, Object o2)
 | 
						|
                        {
 | 
						|
                          ObjectStreamField f1 = (ObjectStreamField)o1;
 | 
						|
                          ObjectStreamField f2 = (ObjectStreamField)o2;
 | 
						|
 | 
						|
                          return f1.getName().compareTo(f2.getName());
 | 
						|
                        }
 | 
						|
                    });
 | 
						|
 | 
						|
                for (int i=1; i < fields.length; i++)
 | 
						|
                  {
 | 
						|
                    if (fieldsName[i-1].getName().equals(fieldsName[i].getName()))
 | 
						|
                        {
 | 
						|
                            fields = INVALID_FIELDS;
 | 
						|
                            return;
 | 
						|
                        }
 | 
						|
                  }
 | 
						|
 | 
						|
                Arrays.sort (fields);
 | 
						|
                // Retrieve field reference.
 | 
						|
                for (int i=0; i < fields.length; i++)
 | 
						|
                  {
 | 
						|
                    try
 | 
						|
                      {
 | 
						|
                        fields[i].lookupField(cl);
 | 
						|
                      }
 | 
						|
                    catch (NoSuchFieldException _)
 | 
						|
                      {
 | 
						|
                        fields[i].setToSet(false);
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
 | 
						|
                calculateOffsets();
 | 
						|
                return;
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    catch (NoSuchFieldException ignore)
 | 
						|
      {
 | 
						|
      }
 | 
						|
    catch (IllegalAccessException ignore)
 | 
						|
      {
 | 
						|
      }
 | 
						|
 | 
						|
    int num_good_fields = 0;
 | 
						|
    Field[] all_fields = cl.getDeclaredFields();
 | 
						|
 | 
						|
    int modifiers;
 | 
						|
    // set non-serializable fields to null in all_fields
 | 
						|
    for (int i = 0; i < all_fields.length; i++)
 | 
						|
      {
 | 
						|
        modifiers = all_fields[i].getModifiers();
 | 
						|
        if (Modifier.isTransient(modifiers)
 | 
						|
            || Modifier.isStatic(modifiers))
 | 
						|
          all_fields[i] = null;
 | 
						|
        else
 | 
						|
          num_good_fields++;
 | 
						|
      }
 | 
						|
 | 
						|
    // make a copy of serializable (non-null) fields
 | 
						|
    fields = new ObjectStreamField[ num_good_fields ];
 | 
						|
    for (int from = 0, to = 0; from < all_fields.length; from++)
 | 
						|
      if (all_fields[from] != null)
 | 
						|
        {
 | 
						|
          final Field f = all_fields[from];
 | 
						|
          setAccessible.setMember(f);
 | 
						|
          AccessController.doPrivileged(setAccessible);
 | 
						|
          fields[to] = new ObjectStreamField(all_fields[from]);
 | 
						|
          to++;
 | 
						|
        }
 | 
						|
 | 
						|
    Arrays.sort(fields);
 | 
						|
    // Make sure we don't have any duplicate field names
 | 
						|
    // (Sun JDK 1.4.1. throws an Internal Error as well)
 | 
						|
    for (int i = 1; i < fields.length; i++)
 | 
						|
      {
 | 
						|
        if(fields[i - 1].getName().equals(fields[i].getName()))
 | 
						|
            throw new InternalError("Duplicate field " +
 | 
						|
                        fields[i].getName() + " in class " + cl.getName());
 | 
						|
      }
 | 
						|
    calculateOffsets();
 | 
						|
  }
 | 
						|
 | 
						|
  static Hashtable uidCache = new Hashtable();
 | 
						|
 | 
						|
  // Returns the serial version UID defined by class, or if that
 | 
						|
  // isn't present, calculates value of serial version UID.
 | 
						|
  private long getClassUID(Class cl)
 | 
						|
  {
 | 
						|
    long result = 0;
 | 
						|
    Long cache = (Long) uidCache.get(cl);
 | 
						|
    if (cache != null)
 | 
						|
      result = cache.longValue();
 | 
						|
    else
 | 
						|
      {
 | 
						|
        // Note that we can't use Class.isEnum() here, because that returns
 | 
						|
        // false for java.lang.Enum and enum value sub classes.
 | 
						|
        if (Enum.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
 | 
						|
          {
 | 
						|
            // Spec says that enums and dynamic proxies have
 | 
						|
            // a serialVersionUID of 0L.
 | 
						|
            return 0L;
 | 
						|
          }
 | 
						|
        try
 | 
						|
          {
 | 
						|
            result = getClassUIDFromField(cl);
 | 
						|
          }
 | 
						|
        catch (NoSuchFieldException ignore)
 | 
						|
          {
 | 
						|
            try
 | 
						|
              {
 | 
						|
                result = calculateClassUID(cl);
 | 
						|
              }
 | 
						|
            catch (NoSuchAlgorithmException e)
 | 
						|
              {
 | 
						|
                throw new RuntimeException
 | 
						|
                  ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
 | 
						|
                   + cl.getName(), e);
 | 
						|
              }
 | 
						|
            catch (IOException ioe)
 | 
						|
              {
 | 
						|
                throw new RuntimeException(ioe);
 | 
						|
              }
 | 
						|
          }
 | 
						|
 | 
						|
        if (loadedByBootOrApplicationClassLoader(cl))
 | 
						|
          uidCache.put(cl,Long.valueOf(result));
 | 
						|
      }
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Search for a serialVersionUID field in the given class and read
 | 
						|
   * its value.
 | 
						|
   *
 | 
						|
   * @return the contents of the serialVersionUID field
 | 
						|
   *
 | 
						|
   * @throws NoSuchFieldException if such a field does not exist or is
 | 
						|
   * not static, not final, not of type Long or not accessible.
 | 
						|
   */
 | 
						|
  long getClassUIDFromField(Class cl)
 | 
						|
    throws NoSuchFieldException
 | 
						|
  {
 | 
						|
    long result;
 | 
						|
 | 
						|
    try
 | 
						|
      {
 | 
						|
        // Use getDeclaredField rather than getField, since serialVersionUID
 | 
						|
        // may not be public AND we only want the serialVersionUID of this
 | 
						|
        // class, not a superclass or interface.
 | 
						|
        final Field suid = cl.getDeclaredField("serialVersionUID");
 | 
						|
        SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
 | 
						|
        AccessController.doPrivileged(setAccessible);
 | 
						|
        int modifiers = suid.getModifiers();
 | 
						|
 | 
						|
        if (Modifier.isStatic(modifiers)
 | 
						|
            && Modifier.isFinal(modifiers)
 | 
						|
            && suid.getType() == Long.TYPE)
 | 
						|
          result = suid.getLong(null);
 | 
						|
        else
 | 
						|
          throw new NoSuchFieldException();
 | 
						|
      }
 | 
						|
    catch (IllegalAccessException ignore)
 | 
						|
      {
 | 
						|
        throw new NoSuchFieldException();
 | 
						|
      }
 | 
						|
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Calculate class serial version UID for a class that does not
 | 
						|
   * define serialVersionUID:
 | 
						|
   *
 | 
						|
   * @param cl a class
 | 
						|
   *
 | 
						|
   * @return the calculated serial varsion UID.
 | 
						|
   *
 | 
						|
   * @throws NoSuchAlgorithmException if SHA algorithm not found
 | 
						|
   *
 | 
						|
   * @throws IOException if writing to the DigestOutputStream causes
 | 
						|
   * an IOException.
 | 
						|
   */
 | 
						|
  long calculateClassUID(Class cl)
 | 
						|
    throws NoSuchAlgorithmException, IOException
 | 
						|
  {
 | 
						|
    long result;
 | 
						|
    MessageDigest md;
 | 
						|
    try
 | 
						|
      {
 | 
						|
        md = MessageDigest.getInstance("SHA");
 | 
						|
      }
 | 
						|
    catch (NoSuchAlgorithmException e)
 | 
						|
      {
 | 
						|
        // If a provider already provides SHA, use it; otherwise, use this.
 | 
						|
        Gnu gnuProvider = new Gnu();
 | 
						|
        Security.addProvider(gnuProvider);
 | 
						|
        md = MessageDigest.getInstance("SHA");
 | 
						|
      }
 | 
						|
 | 
						|
    DigestOutputStream digest_out =
 | 
						|
      new DigestOutputStream(nullOutputStream, md);
 | 
						|
    DataOutputStream data_out = new DataOutputStream(digest_out);
 | 
						|
 | 
						|
    data_out.writeUTF(cl.getName());
 | 
						|
 | 
						|
    int modifiers = cl.getModifiers();
 | 
						|
    // just look at interesting bits
 | 
						|
    modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
 | 
						|
                             | Modifier.INTERFACE | Modifier.PUBLIC);
 | 
						|
    data_out.writeInt(modifiers);
 | 
						|
 | 
						|
    // Pretend that an array has no interfaces, because when array
 | 
						|
    // serialization was defined (JDK 1.1), arrays didn't have it.
 | 
						|
    if (! cl.isArray())
 | 
						|
      {
 | 
						|
        Class[] interfaces = cl.getInterfaces();
 | 
						|
        Arrays.sort(interfaces, interfaceComparator);
 | 
						|
        for (int i = 0; i < interfaces.length; i++)
 | 
						|
          data_out.writeUTF(interfaces[i].getName());
 | 
						|
      }
 | 
						|
 | 
						|
    Field field;
 | 
						|
    Field[] fields = cl.getDeclaredFields();
 | 
						|
    Arrays.sort(fields, memberComparator);
 | 
						|
    for (int i = 0; i < fields.length; i++)
 | 
						|
      {
 | 
						|
        field = fields[i];
 | 
						|
        modifiers = field.getModifiers();
 | 
						|
        if (Modifier.isPrivate(modifiers)
 | 
						|
            && (Modifier.isStatic(modifiers)
 | 
						|
                || Modifier.isTransient(modifiers)))
 | 
						|
          continue;
 | 
						|
 | 
						|
        data_out.writeUTF(field.getName());
 | 
						|
        data_out.writeInt(modifiers);
 | 
						|
        data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
 | 
						|
      }
 | 
						|
 | 
						|
    // write class initializer method if present
 | 
						|
    if (VMObjectStreamClass.hasClassInitializer(cl))
 | 
						|
      {
 | 
						|
        data_out.writeUTF("<clinit>");
 | 
						|
        data_out.writeInt(Modifier.STATIC);
 | 
						|
        data_out.writeUTF("()V");
 | 
						|
      }
 | 
						|
 | 
						|
    Constructor constructor;
 | 
						|
    Constructor[] constructors = cl.getDeclaredConstructors();
 | 
						|
    Arrays.sort (constructors, memberComparator);
 | 
						|
    for (int i = 0; i < constructors.length; i++)
 | 
						|
      {
 | 
						|
        constructor = constructors[i];
 | 
						|
        modifiers = constructor.getModifiers();
 | 
						|
        if (Modifier.isPrivate(modifiers))
 | 
						|
          continue;
 | 
						|
 | 
						|
        data_out.writeUTF("<init>");
 | 
						|
        data_out.writeInt(modifiers);
 | 
						|
 | 
						|
        // the replacement of '/' with '.' was needed to make computed
 | 
						|
        // SUID's agree with those computed by JDK
 | 
						|
        data_out.writeUTF
 | 
						|
          (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
 | 
						|
      }
 | 
						|
 | 
						|
    Method method;
 | 
						|
    Method[] methods = cl.getDeclaredMethods();
 | 
						|
    Arrays.sort(methods, memberComparator);
 | 
						|
    for (int i = 0; i < methods.length; i++)
 | 
						|
      {
 | 
						|
        method = methods[i];
 | 
						|
        modifiers = method.getModifiers();
 | 
						|
        if (Modifier.isPrivate(modifiers))
 | 
						|
          continue;
 | 
						|
 | 
						|
        data_out.writeUTF(method.getName());
 | 
						|
        data_out.writeInt(modifiers);
 | 
						|
 | 
						|
        // the replacement of '/' with '.' was needed to make computed
 | 
						|
        // SUID's agree with those computed by JDK
 | 
						|
        data_out.writeUTF
 | 
						|
          (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
 | 
						|
      }
 | 
						|
 | 
						|
    data_out.close();
 | 
						|
    byte[] sha = md.digest();
 | 
						|
    result = 0;
 | 
						|
    int len = sha.length < 8 ? sha.length : 8;
 | 
						|
    for (int i = 0; i < len; i++)
 | 
						|
      result += (long) (sha[i] & 0xFF) << (8 * i);
 | 
						|
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the value of CLAZZ's private static final field named
 | 
						|
   * `serialPersistentFields'. It performs some sanity checks before
 | 
						|
   * returning the real array. Besides, the returned array is a clean
 | 
						|
   * copy of the original. So it can be modified.
 | 
						|
   *
 | 
						|
   * @param clazz Class to retrieve 'serialPersistentFields' from.
 | 
						|
   * @return The content of 'serialPersistentFields'.
 | 
						|
   */
 | 
						|
  private ObjectStreamField[] getSerialPersistentFields(Class clazz)
 | 
						|
    throws NoSuchFieldException, IllegalAccessException
 | 
						|
  {
 | 
						|
    ObjectStreamField[] fieldsArray = null;
 | 
						|
    ObjectStreamField[] o;
 | 
						|
 | 
						|
    // Use getDeclaredField rather than getField for the same reason
 | 
						|
    // as above in getDefinedSUID.
 | 
						|
    Field f = clazz.getDeclaredField("serialPersistentFields");
 | 
						|
    f.setAccessible(true);
 | 
						|
 | 
						|
    int modifiers = f.getModifiers();
 | 
						|
    if (!(Modifier.isStatic(modifiers) &&
 | 
						|
          Modifier.isFinal(modifiers) &&
 | 
						|
          Modifier.isPrivate(modifiers)))
 | 
						|
      return null;
 | 
						|
 | 
						|
    o = (ObjectStreamField[]) f.get(null);
 | 
						|
 | 
						|
    if (o == null)
 | 
						|
      return null;
 | 
						|
 | 
						|
    fieldsArray = new ObjectStreamField[ o.length ];
 | 
						|
    System.arraycopy(o, 0, fieldsArray, 0, o.length);
 | 
						|
 | 
						|
    return fieldsArray;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a new instance of the Class this ObjectStreamClass corresponds
 | 
						|
   * to.
 | 
						|
   * Note that this should only be used for Externalizable classes.
 | 
						|
   *
 | 
						|
   * @return A new instance.
 | 
						|
   */
 | 
						|
  Externalizable newInstance() throws InvalidClassException
 | 
						|
  {
 | 
						|
    synchronized(this)
 | 
						|
    {
 | 
						|
        if (constructor == null)
 | 
						|
        {
 | 
						|
            try
 | 
						|
            {
 | 
						|
                final Constructor c = clazz.getConstructor(new Class[0]);
 | 
						|
 | 
						|
                AccessController.doPrivileged(new PrivilegedAction()
 | 
						|
                {
 | 
						|
                    public Object run()
 | 
						|
                    {
 | 
						|
                        c.setAccessible(true);
 | 
						|
                        return null;
 | 
						|
                    }
 | 
						|
                });
 | 
						|
 | 
						|
                constructor = c;
 | 
						|
            }
 | 
						|
            catch(NoSuchMethodException x)
 | 
						|
            {
 | 
						|
                throw new InvalidClassException(clazz.getName(),
 | 
						|
                    "No public zero-argument constructor");
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    try
 | 
						|
    {
 | 
						|
        return (Externalizable)constructor.newInstance();
 | 
						|
    }
 | 
						|
    catch(Exception x)
 | 
						|
    {
 | 
						|
        throw (InvalidClassException)
 | 
						|
            new InvalidClassException(clazz.getName(),
 | 
						|
                     "Unable to instantiate").initCause(x);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public static final ObjectStreamField[] NO_FIELDS = {};
 | 
						|
 | 
						|
  private static Hashtable<Class,ObjectStreamClass> classLookupTable
 | 
						|
    = new Hashtable<Class,ObjectStreamClass>();
 | 
						|
  private static final NullOutputStream nullOutputStream = new NullOutputStream();
 | 
						|
  private static final Comparator interfaceComparator = new InterfaceComparator();
 | 
						|
  private static final Comparator memberComparator = new MemberComparator();
 | 
						|
  private static final
 | 
						|
    Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
 | 
						|
 | 
						|
  private ObjectStreamClass superClass;
 | 
						|
  private Class<?> clazz;
 | 
						|
  private String name;
 | 
						|
  private long uid;
 | 
						|
  private byte flags;
 | 
						|
 | 
						|
  // this field is package protected so that ObjectInputStream and
 | 
						|
  // ObjectOutputStream can access it directly
 | 
						|
  ObjectStreamField[] fields;
 | 
						|
 | 
						|
  // these are accessed by ObjectIn/OutputStream
 | 
						|
  int primFieldSize = -1;  // -1 if not yet calculated
 | 
						|
  int objectFieldCount;
 | 
						|
 | 
						|
  Method readObjectMethod;
 | 
						|
  Method readResolveMethod;
 | 
						|
  Method writeReplaceMethod;
 | 
						|
  Method writeObjectMethod;
 | 
						|
  boolean realClassIsSerializable;
 | 
						|
  boolean realClassIsExternalizable;
 | 
						|
  ObjectStreamField[] fieldMapping;
 | 
						|
  Constructor firstNonSerializableParentConstructor;
 | 
						|
  private Constructor constructor;  // default constructor for Externalizable
 | 
						|
 | 
						|
  boolean isProxyClass = false;
 | 
						|
 | 
						|
/* GCJ LOCAL */
 | 
						|
  // True after setFields() has been called
 | 
						|
  private boolean fieldsSet = false;
 | 
						|
/* END GCJ LOCAL */
 | 
						|
 | 
						|
  // This is probably not necessary because this class is special cased already
 | 
						|
  // but it will avoid showing up as a discrepancy when comparing SUIDs.
 | 
						|
  private static final long serialVersionUID = -6120832682080437368L;
 | 
						|
 | 
						|
 | 
						|
  // interfaces are compared only by name
 | 
						|
  private static final class InterfaceComparator implements Comparator
 | 
						|
  {
 | 
						|
    public int compare(Object o1, Object o2)
 | 
						|
    {
 | 
						|
      return ((Class) o1).getName().compareTo(((Class) o2).getName());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  // Members (Methods and Constructors) are compared first by name,
 | 
						|
  // conflicts are resolved by comparing type signatures
 | 
						|
  private static final class MemberComparator implements Comparator
 | 
						|
  {
 | 
						|
    public int compare(Object o1, Object o2)
 | 
						|
    {
 | 
						|
      Member m1 = (Member) o1;
 | 
						|
      Member m2 = (Member) o2;
 | 
						|
 | 
						|
      int comp = m1.getName().compareTo(m2.getName());
 | 
						|
 | 
						|
      if (comp == 0)
 | 
						|
        return TypeSignature.getEncodingOfMember(m1).
 | 
						|
          compareTo(TypeSignature.getEncodingOfMember(m2));
 | 
						|
      else
 | 
						|
        return comp;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |