mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			666 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			666 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* ObjectStreamClass.java -- Class used to write class information
 | |
|    about serialized objects.
 | |
|    Copyright (C) 1998, 1999, 2000, 2001  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., 59 Temple Place, Suite 330, Boston, MA
 | |
| 02111-1307 USA.
 | |
| 
 | |
| As a special exception, if you link this library with other files to
 | |
| produce an executable, this library does not by itself cause the
 | |
| resulting executable to be covered by the GNU General Public License.
 | |
| This exception does not however invalidate any other reasons why the
 | |
| executable file might be covered by the GNU General Public License. */
 | |
| 
 | |
| 
 | |
| package java.io;
 | |
| 
 | |
| 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.security.DigestOutputStream;
 | |
| import java.security.MessageDigest;
 | |
| import java.security.NoSuchAlgorithmException;
 | |
| import java.security.Security;
 | |
| import java.util.Arrays;
 | |
| import java.util.Comparator;
 | |
| import java.util.Hashtable;
 | |
| import java.util.Vector;
 | |
| import gnu.java.io.NullOutputStream;
 | |
| import gnu.java.lang.reflect.TypeSignature;
 | |
| import gnu.java.security.provider.Gnu;
 | |
| 
 | |
| 
 | |
| public class ObjectStreamClass implements Serializable
 | |
| {
 | |
|   /**
 | |
|      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.
 | |
| 
 | |
|      @see java.io.Serializable
 | |
|   */
 | |
|   public static ObjectStreamClass lookup (Class cl)
 | |
|   {
 | |
|     if (cl == null)
 | |
|       return null;
 | |
|     if (! (Serializable.class).isAssignableFrom (cl))
 | |
|       return null;
 | |
| 
 | |
|     ObjectStreamClass osc = (ObjectStreamClass)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.
 | |
|   */
 | |
|   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
 | |
|   */
 | |
|   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.
 | |
|   // XXX doc
 | |
|   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 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 CLAZZ and CLAZZ itself in order from most super to
 | |
|   // CLAZZ.  ObjectStreamClass[0] is the highest superclass of CLAZZ
 | |
|   // that is serializable.
 | |
|   static ObjectStreamClass[] getObjectStreamClasses (Class clazz)
 | |
|   {
 | |
|     ObjectStreamClass osc = ObjectStreamClass.lookup (clazz);
 | |
| 
 | |
|     ObjectStreamClass[] ret_val;
 | |
| 
 | |
|     if (osc == null)
 | |
|       return new ObjectStreamClass[0];
 | |
|     else
 | |
|     {
 | |
|       Vector oscs = new Vector ();
 | |
| 
 | |
|       while (osc != null)
 | |
|       {
 | |
| 	oscs.addElement (osc);
 | |
| 	osc = osc.getSuper ();
 | |
|       }
 | |
| 
 | |
|       int count = oscs.size ();
 | |
|       ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[ count ];
 | |
| 
 | |
|       for (int i = count - 1; i >= 0; i--)
 | |
| 	sorted_oscs[ count - i - 1 ] = (ObjectStreamClass)oscs.elementAt (i);
 | |
| 
 | |
|       return sorted_oscs;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   // 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;
 | |
|   }
 | |
| 
 | |
|   void setClass (Class cl) throws InvalidClassException
 | |
|   {
 | |
|     this.clazz = cl;
 | |
|     long class_uid = getClassUID (cl);
 | |
|     if (uid == 0)
 | |
|       {
 | |
|        uid = class_uid;
 | |
|        return;
 | |
|       }
 | |
|     
 | |
|     // Check that the actual UID of the resolved class matches the UID from 
 | |
|     // the stream.    
 | |
|     if (uid != class_uid)
 | |
|       {
 | |
|        String msg = cl + 
 | |
| 	 ": Local class not compatible: stream serialVersionUID="
 | |
| 	 + uid + ", local serialVersionUID=" + class_uid;
 | |
|        throw new InvalidClassException (msg);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   void setSuperclass (ObjectStreamClass osc)
 | |
|   {
 | |
|     superClass = osc;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   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 ObjectStreamClass (Class cl)
 | |
|   {
 | |
|     uid = 0;
 | |
|     flags = 0;
 | |
| 
 | |
|     clazz = cl;
 | |
|     name = cl.getName ();
 | |
|     setFlags (cl);
 | |
|     setFields (cl);
 | |
|     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;
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       Method writeMethod = cl.getDeclaredMethod ("writeObject",
 | |
| 						 writeMethodArgTypes);
 | |
|       int modifiers = writeMethod.getModifiers ();
 | |
| 
 | |
|       if (writeMethod.getReturnType () == Void.TYPE
 | |
| 	  && Modifier.isPrivate (modifiers)
 | |
| 	  && !Modifier.isStatic (modifiers))
 | |
| 	flags |= ObjectStreamConstants.SC_WRITE_METHOD;
 | |
|     }
 | |
|     catch (NoSuchMethodException oh_well)
 | |
|     {}
 | |
|   }
 | |
| 
 | |
| 
 | |
|   // Sets fields to be a sorted array of the serializable fields of
 | |
|   // clazz.
 | |
|   private void setFields (Class cl)
 | |
|   {
 | |
|     if (! isSerializable () || isExternalizable ())
 | |
|     {
 | |
|       fields = NO_FIELDS;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       Field serialPersistentFields
 | |
| 	= cl.getDeclaredField ("serialPersistentFields");
 | |
|       int modifiers = serialPersistentFields.getModifiers ();
 | |
| 
 | |
|       if (Modifier.isStatic (modifiers)
 | |
| 	  && Modifier.isFinal (modifiers)
 | |
| 	  && Modifier.isPrivate (modifiers))
 | |
|       {
 | |
| 	fields = getSerialPersistentFields (cl);
 | |
| 	Arrays.sort (fields);
 | |
| 	calculateOffsets ();
 | |
| 	return;
 | |
|       }
 | |
|     }
 | |
|     catch (NoSuchFieldException 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)
 | |
|       {
 | |
| 	Field f = all_fields[from];
 | |
| 	fields[to] = new ObjectStreamField (f.getName (), f.getType ());
 | |
| 	to++;
 | |
|       }
 | |
| 
 | |
|     Arrays.sort (fields);
 | |
|     calculateOffsets ();
 | |
|   }
 | |
| 
 | |
|   // 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)
 | |
|   {
 | |
|     try
 | |
|     {
 | |
|       Field suid = cl.getDeclaredField ("serialVersionUID");
 | |
|       int modifiers = suid.getModifiers ();
 | |
| 
 | |
|       if (Modifier.isStatic (modifiers) && Modifier.isFinal (modifiers))
 | |
| 	return suid.getLong (null);	  
 | |
|     }
 | |
|     catch (NoSuchFieldException ignore)
 | |
|     {
 | |
|     }
 | |
|     catch (IllegalAccessException ignore)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     // cl didn't define serialVersionUID, so we have to compute it
 | |
|     try
 | |
|     {
 | |
|       MessageDigest md = null;
 | |
|       DigestOutputStream digest_out = null;
 | |
|       DataOutputStream data_out = null;
 | |
| 
 | |
|       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");
 | |
| 	}
 | |
| 
 | |
|       digest_out = new DigestOutputStream (nullOutputStream, md);
 | |
|       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
 | |
|       boolean has_init;
 | |
|       try
 | |
|       {
 | |
| 	has_init = hasClassInitializer (cl);
 | |
|       }
 | |
|       catch (NoSuchMethodError e)
 | |
|       {
 | |
| 	has_init = false;
 | |
|       }
 | |
| 
 | |
|       if (has_init)
 | |
|       {
 | |
| 	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 ();
 | |
|       long 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;
 | |
|     }
 | |
|     catch (NoSuchAlgorithmException e)
 | |
|     {
 | |
|       throw new RuntimeException ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
 | |
| 				  + cl.getName ());
 | |
|     }
 | |
|     catch (IOException ioe)
 | |
|     {
 | |
|       throw new RuntimeException (ioe.getMessage ());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Returns the value of CLAZZ's private static final field named
 | |
|   // `serialPersistentFields'.
 | |
|   private ObjectStreamField[] getSerialPersistentFields (Class clazz)
 | |
|   {
 | |
|     ObjectStreamField[] o = null;
 | |
|     try
 | |
|       {
 | |
| 	// Use getDeclaredField rather than getField for the same reason
 | |
| 	// as above in getDefinedSUID.
 | |
| 	Field f = clazz.getDeclaredField ("getSerialPersistentFields");
 | |
| 	o = (ObjectStreamField[])f.get (null);
 | |
|       }
 | |
|     catch (java.lang.NoSuchFieldException e)
 | |
|       {
 | |
|       }
 | |
|     catch (java.lang.IllegalAccessException e)
 | |
|       {
 | |
|       }
 | |
| 
 | |
|     return o;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   // Returns true if CLAZZ has a static class initializer
 | |
|   // (a.k.a. <clinit>).
 | |
|   //
 | |
|   // A NoSuchMethodError is raised if CLAZZ has no such method.
 | |
|   private static boolean hasClassInitializer (Class clazz)
 | |
|     throws java.lang.NoSuchMethodError
 | |
|   {
 | |
|     Method m = null;
 | |
| 
 | |
|     try
 | |
|       {
 | |
| 	Class classArgs[] = {};
 | |
| 	m = clazz.getDeclaredMethod ("<clinit>", classArgs);
 | |
|       }
 | |
|     catch (java.lang.NoSuchMethodException e)
 | |
|       {
 | |
| 	throw new java.lang.NoSuchMethodError ();
 | |
|       }
 | |
| 
 | |
|     return m != null;
 | |
|   }
 | |
| 
 | |
|   public static final ObjectStreamField[] NO_FIELDS = {};
 | |
| 
 | |
|   private static Hashtable classLookupTable = new Hashtable ();
 | |
|   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;
 | |
| 
 | |
|   // 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
 | |
| 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
 | |
| 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;
 | |
|   }
 | |
| }
 |