1 /* ObjectStreamClass.java -- Class used to write class information
2 about serialized objects.
3 Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
42 import gnu
.java
.io
.NullOutputStream
;
43 import gnu
.java
.lang
.reflect
.TypeSignature
;
44 import gnu
.java
.security
.action
.SetAccessibleAction
;
45 import gnu
.java
.security
.provider
.Gnu
;
47 import java
.lang
.reflect
.Constructor
;
48 import java
.lang
.reflect
.Field
;
49 import java
.lang
.reflect
.Member
;
50 import java
.lang
.reflect
.Method
;
51 import java
.lang
.reflect
.Modifier
;
52 import java
.lang
.reflect
.Proxy
;
53 import java
.security
.AccessController
;
54 import java
.security
.DigestOutputStream
;
55 import java
.security
.MessageDigest
;
56 import java
.security
.NoSuchAlgorithmException
;
57 import java
.security
.PrivilegedAction
;
58 import java
.security
.Security
;
59 import java
.util
.Arrays
;
60 import java
.util
.Comparator
;
61 import java
.util
.Hashtable
;
62 import java
.util
.Vector
;
64 public class ObjectStreamClass
implements Serializable
66 static final ObjectStreamField
[] INVALID_FIELDS
= new ObjectStreamField
[0];
69 * Returns the <code>ObjectStreamClass</code> for <code>cl</code>.
70 * If <code>cl</code> is null, or is not <code>Serializable</code>,
71 * null is returned. <code>ObjectStreamClass</code>'s are memorized;
72 * later calls to this method with the same class will return the
73 * same <code>ObjectStreamClass</code> object and no recalculation
76 * Warning: If this class contains an invalid serialPersistentField arrays
77 * lookup will not throw anything. However {@link #getFields()} will return
78 * an empty array and {@link java.io.ObjectOutputStream#writeObject} will throw an
79 * {@link java.io.InvalidClassException}.
81 * @see java.io.Serializable
83 public static ObjectStreamClass
lookup(Class cl
)
87 if (! (Serializable
.class).isAssignableFrom(cl
))
90 return lookupForClassObject(cl
);
94 * This lookup for internal use by ObjectOutputStream. Suppose
95 * we have a java.lang.Class object C for class A, though A is not
96 * serializable, but it's okay to serialize C.
98 static ObjectStreamClass
lookupForClassObject(Class cl
)
103 ObjectStreamClass osc
= (ObjectStreamClass
) classLookupTable
.get(cl
);
109 osc
= new ObjectStreamClass(cl
);
110 classLookupTable
.put(cl
, osc
);
116 * Returns the name of the class that this
117 * <code>ObjectStreamClass</code> represents.
119 * @return the name of the class.
121 public String
getName()
127 * Returns the class that this <code>ObjectStreamClass</code>
128 * represents. Null could be returned if this
129 * <code>ObjectStreamClass</code> was read from an
130 * <code>ObjectInputStream</code> and the class it represents cannot
131 * be found or loaded.
133 * @see java.io.ObjectInputStream
135 public Class
forClass()
141 * Returns the serial version stream-unique identifier for the class
142 * represented by this <code>ObjectStreamClass</code>. This SUID is
143 * either defined by the class as <code>static final long
144 * serialVersionUID</code> or is calculated as specified in
145 * Javasoft's "Object Serialization Specification" XXX: add reference
147 * @return the serial version UID.
149 public long getSerialVersionUID()
155 * Returns the serializable (non-static and non-transient) Fields
156 * of the class represented by this ObjectStreamClass. The Fields
157 * are sorted by name.
158 * If fields were obtained using serialPersistentFields and this array
159 * is faulty then the returned array of this method will be empty.
161 * @return the fields.
163 public ObjectStreamField
[] getFields()
165 ObjectStreamField
[] copy
= new ObjectStreamField
[ fields
.length
];
166 System
.arraycopy(fields
, 0, copy
, 0, fields
.length
);
171 // Can't do binary search since fields is sorted by name and
173 public ObjectStreamField
getField (String name
)
175 for (int i
= 0; i
< fields
.length
; i
++)
176 if (fields
[i
].getName().equals(name
))
182 * Returns a textual representation of this
183 * <code>ObjectStreamClass</code> object including the name of the
184 * class it represents as well as that class's serial version
185 * stream-unique identifier.
187 * @see #getSerialVersionUID()
190 public String
toString()
192 return "java.io.ObjectStreamClass< " + name
+ ", " + uid
+ " >";
195 // Returns true iff the class that this ObjectStreamClass represents
196 // has the following method:
198 // private void writeObject (ObjectOutputStream)
200 // This method is used by the class to override default
201 // serialization behavior.
202 boolean hasWriteMethod()
204 return (flags
& ObjectStreamConstants
.SC_WRITE_METHOD
) != 0;
207 // Returns true iff the class that this ObjectStreamClass represents
208 // implements Serializable but does *not* implement Externalizable.
209 boolean isSerializable()
211 return (flags
& ObjectStreamConstants
.SC_SERIALIZABLE
) != 0;
215 // Returns true iff the class that this ObjectStreamClass represents
216 // implements Externalizable.
217 boolean isExternalizable()
219 return (flags
& ObjectStreamConstants
.SC_EXTERNALIZABLE
) != 0;
223 // Returns the <code>ObjectStreamClass</code> that represents the
224 // class that is the superclass of the class this
225 // <code>ObjectStreamClass</code> represents. If the superclass is
226 // not Serializable, null is returned.
227 ObjectStreamClass
getSuper()
233 // returns an array of ObjectStreamClasses that represent the super
234 // classes of CLAZZ and CLAZZ itself in order from most super to
235 // CLAZZ. ObjectStreamClass[0] is the highest superclass of CLAZZ
236 // that is serializable.
237 static ObjectStreamClass
[] getObjectStreamClasses(Class clazz
)
239 ObjectStreamClass osc
= ObjectStreamClass
.lookup(clazz
);
242 return new ObjectStreamClass
[0];
245 Vector oscs
= new Vector();
249 oscs
.addElement (osc
);
250 osc
= osc
.getSuper();
253 int count
= oscs
.size();
254 ObjectStreamClass
[] sorted_oscs
= new ObjectStreamClass
[ count
];
256 for (int i
= count
- 1; i
>= 0; i
--)
257 sorted_oscs
[ count
- i
- 1 ] = (ObjectStreamClass
) oscs
.elementAt(i
);
264 // Returns an integer that consists of bit-flags that indicate
265 // properties of the class represented by this ObjectStreamClass.
266 // The bit-flags that could be present are those defined in
267 // ObjectStreamConstants that begin with `SC_'
274 ObjectStreamClass(String name
, long uid
, byte flags
,
275 ObjectStreamField
[] fields
)
280 this.fields
= fields
;
284 * This method builds the internal description corresponding to a Java Class.
285 * As the constructor only assign a name to the current ObjectStreamClass instance,
286 * that method sets the serial UID, chose the fields which will be serialized,
287 * and compute the position of the fields in the serialized stream.
289 * @param cl The Java class which is used as a reference for building the descriptor.
290 * @param superClass The descriptor of the super class for this class descriptor.
291 * @throws InvalidClassException if an incompatibility between computed UID and
292 * already set UID is found.
294 void setClass(Class cl
, ObjectStreamClass superClass
) throws InvalidClassException
300 long class_uid
= getClassUID(cl
);
305 // Check that the actual UID of the resolved class matches the UID from
307 if (uid
!= class_uid
)
310 ": Local class not compatible: stream serialVersionUID="
311 + uid
+ ", local serialVersionUID=" + class_uid
;
312 throw new InvalidClassException (msg
);
316 isProxyClass
= clazz
!= null && Proxy
.isProxyClass(clazz
);
317 this.superClass
= superClass
;
322 ObjectStreamField
[] exportedFields
= getSerialPersistentFields (clazz
);
324 if (exportedFields
== null)
327 ObjectStreamField
[] newFieldList
= new ObjectStreamField
[exportedFields
.length
+ fields
.length
];
330 /* We now check the import fields against the exported fields.
331 * There should not be contradiction (e.g. int x and String x)
332 * but extra virtual fields can be added to the class.
335 Arrays
.sort(exportedFields
);
338 while (i
< fields
.length
&& j
< exportedFields
.length
)
340 int comp
= fields
[i
].compareTo(exportedFields
[j
]);
344 newFieldList
[k
] = fields
[i
];
345 fields
[i
].setPersistent(false);
346 fields
[i
].setToSet(false);
351 /* field not found in imported fields. We add it
352 * in the list of supported fields.
354 newFieldList
[k
] = exportedFields
[j
];
355 newFieldList
[k
].setPersistent(true);
356 newFieldList
[k
].setToSet(false);
359 newFieldList
[k
].lookupField(clazz
);
360 newFieldList
[k
].checkFieldType();
362 catch (NoSuchFieldException _
)
371 exportedFields
[j
].lookupField(clazz
);
372 exportedFields
[j
].checkFieldType();
374 catch (NoSuchFieldException _
)
378 if (!fields
[i
].getType().equals(exportedFields
[j
].getType()))
379 throw new InvalidClassException
380 ("serialPersistentFields must be compatible with" +
381 " imported fields (about " + fields
[i
].getName() + ")");
382 newFieldList
[k
] = fields
[i
];
383 fields
[i
].setPersistent(true);
390 if (i
< fields
.length
)
391 for (;i
<fields
.length
;i
++,k
++)
393 fields
[i
].setPersistent(false);
394 fields
[i
].setToSet(false);
395 newFieldList
[k
] = fields
[i
];
398 if (j
< exportedFields
.length
)
399 for (;j
<exportedFields
.length
;j
++,k
++)
401 exportedFields
[j
].setPersistent(true);
402 exportedFields
[j
].setToSet(false);
403 newFieldList
[k
] = exportedFields
[j
];
406 fields
= new ObjectStreamField
[k
];
407 System
.arraycopy(newFieldList
, 0, fields
, 0, k
);
409 catch (NoSuchFieldException ignore
)
413 catch (IllegalAccessException ignore
)
419 void setSuperclass (ObjectStreamClass osc
)
424 void calculateOffsets()
427 ObjectStreamField field
;
429 int fcount
= fields
.length
;
430 for (i
= 0; i
< fcount
; ++ i
)
434 if (! field
.isPrimitive())
437 field
.setOffset(primFieldSize
);
438 switch (field
.getTypeCode())
459 for (objectFieldCount
= 0; i
< fcount
; ++ i
)
460 fields
[i
].setOffset(objectFieldCount
++);
463 private Method
findMethod(Method
[] methods
, String name
, Class
[] params
,
464 Class returnType
, boolean mustBePrivate
)
467 for (int i
= 0; i
< methods
.length
; i
++)
469 final Method m
= methods
[i
];
470 int mods
= m
.getModifiers();
471 if (Modifier
.isStatic(mods
)
472 || (mustBePrivate
&& !Modifier
.isPrivate(mods
)))
477 if (m
.getName().equals(name
)
478 && m
.getReturnType() == returnType
)
480 Class
[] mp
= m
.getParameterTypes();
481 if (mp
.length
== params
.length
)
483 for (int j
= 0; j
< mp
.length
; j
++)
485 if (mp
[j
] != params
[j
])
490 AccessController
.doPrivileged(new SetAccessibleAction(m
));
498 private static boolean inSamePackage(Class c1
, Class c2
)
500 String name1
= c1
.getName();
501 String name2
= c2
.getName();
503 int id1
= name1
.lastIndexOf('.');
504 int id2
= name2
.lastIndexOf('.');
506 // Handle the default package
507 if (id1
== -1 || id2
== -1)
510 String package1
= name1
.substring(0, id1
);
511 String package2
= name2
.substring(0, id2
);
513 return package1
.equals(package2
);
516 final static Class
[] noArgs
= new Class
[0];
518 private static Method
findAccessibleMethod(String name
, Class from
)
520 for (Class c
= from
; c
!= null; c
= c
.getSuperclass())
524 Method res
= c
.getDeclaredMethod(name
, noArgs
);
525 int mods
= res
.getModifiers();
528 || Modifier
.isProtected(mods
)
529 || Modifier
.isPublic(mods
)
530 || (! Modifier
.isPrivate(mods
) && inSamePackage(c
, from
)))
532 AccessController
.doPrivileged(new SetAccessibleAction(res
));
536 catch (NoSuchMethodException e
)
544 private void cacheMethods()
546 Method
[] methods
= forClass().getDeclaredMethods();
548 readObjectMethod
= findMethod(methods
, "readObject",
549 new Class
[] { ObjectInputStream
.class },
551 writeObjectMethod
= findMethod(methods
, "writeObject",
552 new Class
[] { ObjectOutputStream
.class },
555 // readResolve and writeReplace can be in parent classes, as long as they
556 // are accessible from this class.
557 readResolveMethod
= findAccessibleMethod("readResolve", forClass());
558 writeReplaceMethod
= findAccessibleMethod("writeReplace", forClass());
561 private ObjectStreamClass(Class cl
)
565 isProxyClass
= Proxy
.isProxyClass(cl
);
572 // to those class nonserializable, its uid field is 0
573 if ( (Serializable
.class).isAssignableFrom(cl
) && !isProxyClass
)
574 uid
= getClassUID(cl
);
575 superClass
= lookup(cl
.getSuperclass());
579 // Sets bits in flags according to features of CL.
580 private void setFlags(Class cl
)
582 if ((java
.io
.Externalizable
.class).isAssignableFrom(cl
))
583 flags
|= ObjectStreamConstants
.SC_EXTERNALIZABLE
;
584 else if ((java
.io
.Serializable
.class).isAssignableFrom(cl
))
585 // only set this bit if CL is NOT Externalizable
586 flags
|= ObjectStreamConstants
.SC_SERIALIZABLE
;
588 if (writeObjectMethod
!= null)
589 flags
|= ObjectStreamConstants
.SC_WRITE_METHOD
;
593 // Sets fields to be a sorted array of the serializable fields of
595 private void setFields(Class cl
)
597 SetAccessibleAction setAccessible
= new SetAccessibleAction();
599 if (!isSerializable() || isExternalizable())
608 cl
.getDeclaredField("serialPersistentFields");
609 setAccessible
.setMember(f
);
610 AccessController
.doPrivileged(setAccessible
);
611 int modifiers
= f
.getModifiers();
613 if (Modifier
.isStatic(modifiers
)
614 && Modifier
.isFinal(modifiers
)
615 && Modifier
.isPrivate(modifiers
))
617 fields
= getSerialPersistentFields(cl
);
620 ObjectStreamField
[] fieldsName
= new ObjectStreamField
[fields
.length
];
621 System
.arraycopy(fields
, 0, fieldsName
, 0, fields
.length
);
623 Arrays
.sort (fieldsName
, new Comparator() {
624 public int compare(Object o1
, Object o2
)
626 ObjectStreamField f1
= (ObjectStreamField
)o1
;
627 ObjectStreamField f2
= (ObjectStreamField
)o2
;
629 return f1
.getName().compareTo(f2
.getName());
633 for (int i
=1; i
< fields
.length
; i
++)
635 if (fieldsName
[i
-1].getName().equals(fieldsName
[i
].getName()))
637 fields
= INVALID_FIELDS
;
642 Arrays
.sort (fields
);
643 // Retrieve field reference.
644 for (int i
=0; i
< fields
.length
; i
++)
648 fields
[i
].lookupField(cl
);
650 catch (NoSuchFieldException _
)
652 fields
[i
].setToSet(false);
661 catch (NoSuchFieldException ignore
)
664 catch (IllegalAccessException ignore
)
668 int num_good_fields
= 0;
669 Field
[] all_fields
= cl
.getDeclaredFields();
672 // set non-serializable fields to null in all_fields
673 for (int i
= 0; i
< all_fields
.length
; i
++)
675 modifiers
= all_fields
[i
].getModifiers();
676 if (Modifier
.isTransient(modifiers
)
677 || Modifier
.isStatic(modifiers
))
678 all_fields
[i
] = null;
683 // make a copy of serializable (non-null) fields
684 fields
= new ObjectStreamField
[ num_good_fields
];
685 for (int from
= 0, to
= 0; from
< all_fields
.length
; from
++)
686 if (all_fields
[from
] != null)
688 final Field f
= all_fields
[from
];
689 setAccessible
.setMember(f
);
690 AccessController
.doPrivileged(setAccessible
);
691 fields
[to
] = new ObjectStreamField(all_fields
[from
]);
696 // Make sure we don't have any duplicate field names
697 // (Sun JDK 1.4.1. throws an Internal Error as well)
698 for (int i
= 1; i
< fields
.length
; i
++)
700 if(fields
[i
- 1].getName().equals(fields
[i
].getName()))
701 throw new InternalError("Duplicate field " +
702 fields
[i
].getName() + " in class " + cl
.getName());
707 // Returns the serial version UID defined by class, or if that
708 // isn't present, calculates value of serial version UID.
709 private long getClassUID(Class cl
)
713 // Use getDeclaredField rather than getField, since serialVersionUID
714 // may not be public AND we only want the serialVersionUID of this
715 // class, not a superclass or interface.
716 final Field suid
= cl
.getDeclaredField("serialVersionUID");
717 SetAccessibleAction setAccessible
= new SetAccessibleAction(suid
);
718 AccessController
.doPrivileged(setAccessible
);
719 int modifiers
= suid
.getModifiers();
721 if (Modifier
.isStatic(modifiers
)
722 && Modifier
.isFinal(modifiers
)
723 && suid
.getType() == Long
.TYPE
)
724 return suid
.getLong(null);
726 catch (NoSuchFieldException ignore
)
729 catch (IllegalAccessException ignore
)
733 // cl didn't define serialVersionUID, so we have to compute it
739 md
= MessageDigest
.getInstance("SHA");
741 catch (NoSuchAlgorithmException e
)
743 // If a provider already provides SHA, use it; otherwise, use this.
744 Gnu gnuProvider
= new Gnu();
745 Security
.addProvider(gnuProvider
);
746 md
= MessageDigest
.getInstance("SHA");
749 DigestOutputStream digest_out
=
750 new DigestOutputStream(nullOutputStream
, md
);
751 DataOutputStream data_out
= new DataOutputStream(digest_out
);
753 data_out
.writeUTF(cl
.getName());
755 int modifiers
= cl
.getModifiers();
756 // just look at interesting bits
757 modifiers
= modifiers
& (Modifier
.ABSTRACT
| Modifier
.FINAL
758 | Modifier
.INTERFACE
| Modifier
.PUBLIC
);
759 data_out
.writeInt(modifiers
);
761 // Pretend that an array has no interfaces, because when array
762 // serialization was defined (JDK 1.1), arrays didn't have it.
765 Class
[] interfaces
= cl
.getInterfaces();
766 Arrays
.sort(interfaces
, interfaceComparator
);
767 for (int i
= 0; i
< interfaces
.length
; i
++)
768 data_out
.writeUTF(interfaces
[i
].getName());
772 Field
[] fields
= cl
.getDeclaredFields();
773 Arrays
.sort(fields
, memberComparator
);
774 for (int i
= 0; i
< fields
.length
; i
++)
777 modifiers
= field
.getModifiers();
778 if (Modifier
.isPrivate(modifiers
)
779 && (Modifier
.isStatic(modifiers
)
780 || Modifier
.isTransient(modifiers
)))
783 data_out
.writeUTF(field
.getName());
784 data_out
.writeInt(modifiers
);
785 data_out
.writeUTF(TypeSignature
.getEncodingOfClass (field
.getType()));
788 // write class initializer method if present
789 if (VMObjectStreamClass
.hasClassInitializer(cl
))
791 data_out
.writeUTF("<clinit>");
792 data_out
.writeInt(Modifier
.STATIC
);
793 data_out
.writeUTF("()V");
796 Constructor constructor
;
797 Constructor
[] constructors
= cl
.getDeclaredConstructors();
798 Arrays
.sort (constructors
, memberComparator
);
799 for (int i
= 0; i
< constructors
.length
; i
++)
801 constructor
= constructors
[i
];
802 modifiers
= constructor
.getModifiers();
803 if (Modifier
.isPrivate(modifiers
))
806 data_out
.writeUTF("<init>");
807 data_out
.writeInt(modifiers
);
809 // the replacement of '/' with '.' was needed to make computed
810 // SUID's agree with those computed by JDK
812 (TypeSignature
.getEncodingOfConstructor(constructor
).replace('/','.'));
816 Method
[] methods
= cl
.getDeclaredMethods();
817 Arrays
.sort(methods
, memberComparator
);
818 for (int i
= 0; i
< methods
.length
; i
++)
821 modifiers
= method
.getModifiers();
822 if (Modifier
.isPrivate(modifiers
))
825 data_out
.writeUTF(method
.getName());
826 data_out
.writeInt(modifiers
);
828 // the replacement of '/' with '.' was needed to make computed
829 // SUID's agree with those computed by JDK
831 (TypeSignature
.getEncodingOfMethod(method
).replace('/', '.'));
835 byte[] sha
= md
.digest();
837 int len
= sha
.length
< 8 ? sha
.length
: 8;
838 for (int i
= 0; i
< len
; i
++)
839 result
+= (long) (sha
[i
] & 0xFF) << (8 * i
);
843 catch (NoSuchAlgorithmException e
)
845 throw new RuntimeException
846 ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
849 catch (IOException ioe
)
851 throw new RuntimeException(ioe
);
856 * Returns the value of CLAZZ's private static final field named
857 * `serialPersistentFields'. It performs some sanity checks before
858 * returning the real array. Besides, the returned array is a clean
859 * copy of the original. So it can be modified.
861 * @param clazz Class to retrieve 'serialPersistentFields' from.
862 * @return The content of 'serialPersistentFields'.
864 private ObjectStreamField
[] getSerialPersistentFields(Class clazz
)
865 throws NoSuchFieldException
, IllegalAccessException
867 ObjectStreamField
[] fieldsArray
= null;
868 ObjectStreamField
[] o
;
870 // Use getDeclaredField rather than getField for the same reason
871 // as above in getDefinedSUID.
872 Field f
= clazz
.getDeclaredField("serialPersistentFields");
873 f
.setAccessible(true);
875 int modifiers
= f
.getModifiers();
876 if (!(Modifier
.isStatic(modifiers
) &&
877 Modifier
.isFinal(modifiers
) &&
878 Modifier
.isPrivate(modifiers
)))
881 o
= (ObjectStreamField
[]) f
.get(null);
886 fieldsArray
= new ObjectStreamField
[ o
.length
];
887 System
.arraycopy(o
, 0, fieldsArray
, 0, o
.length
);
893 * Returns a new instance of the Class this ObjectStreamClass corresponds
895 * Note that this should only be used for Externalizable classes.
897 * @return A new instance.
899 Externalizable
newInstance() throws InvalidClassException
903 if (constructor
== null)
907 final Constructor c
= clazz
.getConstructor(new Class
[0]);
909 AccessController
.doPrivileged(new PrivilegedAction()
913 c
.setAccessible(true);
920 catch(NoSuchMethodException x
)
922 throw new InvalidClassException(clazz
.getName(),
923 "No public zero-argument constructor");
930 return (Externalizable
)constructor
.newInstance(null);
934 throw (InvalidClassException
)
935 new InvalidClassException(clazz
.getName(),
936 "Unable to instantiate").initCause(x
);
940 public static final ObjectStreamField
[] NO_FIELDS
= {};
942 private static Hashtable classLookupTable
= new Hashtable();
943 private static final NullOutputStream nullOutputStream
= new NullOutputStream();
944 private static final Comparator interfaceComparator
= new InterfaceComparator();
945 private static final Comparator memberComparator
= new MemberComparator();
947 Class
[] writeMethodArgTypes
= { java
.io
.ObjectOutputStream
.class };
949 private ObjectStreamClass superClass
;
955 // this field is package protected so that ObjectInputStream and
956 // ObjectOutputStream can access it directly
957 ObjectStreamField
[] fields
;
959 // these are accessed by ObjectIn/OutputStream
960 int primFieldSize
= -1; // -1 if not yet calculated
961 int objectFieldCount
;
963 Method readObjectMethod
;
964 Method readResolveMethod
;
965 Method writeReplaceMethod
;
966 Method writeObjectMethod
;
967 boolean realClassIsSerializable
;
968 boolean realClassIsExternalizable
;
969 ObjectStreamField
[] fieldMapping
;
970 Constructor firstNonSerializableParentConstructor
;
971 private Constructor constructor
; // default constructor for Externalizable
973 boolean isProxyClass
= false;
975 // This is probably not necessary because this class is special cased already
976 // but it will avoid showing up as a discrepancy when comparing SUIDs.
977 private static final long serialVersionUID
= -6120832682080437368L;
980 // interfaces are compared only by name
981 private static final class InterfaceComparator
implements Comparator
983 public int compare(Object o1
, Object o2
)
985 return ((Class
) o1
).getName().compareTo(((Class
) o2
).getName());
990 // Members (Methods and Constructors) are compared first by name,
991 // conflicts are resolved by comparing type signatures
992 private static final class MemberComparator
implements Comparator
994 public int compare(Object o1
, Object o2
)
996 Member m1
= (Member
) o1
;
997 Member m2
= (Member
) o2
;
999 int comp
= m1
.getName().compareTo(m2
.getName());
1002 return TypeSignature
.getEncodingOfMember(m1
).
1003 compareTo(TypeSignature
.getEncodingOfMember(m2
));