1 /* ObjectStreamClass.java -- Class used to write class information
2 about serialized objects.
3 Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 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
;
64 * @author Tom Tromey (tromey@redhat.com)
65 * @author Jeroen Frijters (jeroen@frijters.net)
66 * @author Guilhem Lavaux (guilhem@kaffe.org)
67 * @author Michael Koch (konqueror@gmx.de)
68 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
70 public class ObjectStreamClass
implements Serializable
72 static final ObjectStreamField
[] INVALID_FIELDS
= new ObjectStreamField
[0];
75 * Returns the <code>ObjectStreamClass</code> for <code>cl</code>.
76 * If <code>cl</code> is null, or is not <code>Serializable</code>,
77 * null is returned. <code>ObjectStreamClass</code>'s are memorized;
78 * later calls to this method with the same class will return the
79 * same <code>ObjectStreamClass</code> object and no recalculation
82 * Warning: If this class contains an invalid serialPersistentField arrays
83 * lookup will not throw anything. However {@link #getFields()} will return
84 * an empty array and {@link java.io.ObjectOutputStream#writeObject} will throw an
85 * {@link java.io.InvalidClassException}.
87 * @see java.io.Serializable
89 public static ObjectStreamClass
lookup(Class
<?
> cl
)
93 if (! (Serializable
.class).isAssignableFrom(cl
))
96 return lookupForClassObject(cl
);
100 * This lookup for internal use by ObjectOutputStream. Suppose
101 * we have a java.lang.Class object C for class A, though A is not
102 * serializable, but it's okay to serialize C.
104 static ObjectStreamClass
lookupForClassObject(Class cl
)
109 ObjectStreamClass osc
= (ObjectStreamClass
) classLookupTable
.get(cl
);
115 osc
= new ObjectStreamClass(cl
);
116 classLookupTable
.put(cl
, osc
);
122 * Returns the name of the class that this
123 * <code>ObjectStreamClass</code> represents.
125 * @return the name of the class.
127 public String
getName()
133 * Returns the class that this <code>ObjectStreamClass</code>
134 * represents. Null could be returned if this
135 * <code>ObjectStreamClass</code> was read from an
136 * <code>ObjectInputStream</code> and the class it represents cannot
137 * be found or loaded.
139 * @see java.io.ObjectInputStream
141 public Class
<?
> forClass()
147 * Returns the serial version stream-unique identifier for the class
148 * represented by this <code>ObjectStreamClass</code>. This SUID is
149 * either defined by the class as <code>static final long
150 * serialVersionUID</code> or is calculated as specified in
151 * Javasoft's "Object Serialization Specification" XXX: add reference
153 * @return the serial version UID.
155 public long getSerialVersionUID()
161 * Returns the serializable (non-static and non-transient) Fields
162 * of the class represented by this ObjectStreamClass. The Fields
163 * are sorted by name.
164 * If fields were obtained using serialPersistentFields and this array
165 * is faulty then the returned array of this method will be empty.
167 * @return the fields.
169 public ObjectStreamField
[] getFields()
171 ObjectStreamField
[] copy
= new ObjectStreamField
[ fields
.length
];
172 System
.arraycopy(fields
, 0, copy
, 0, fields
.length
);
177 // Can't do binary search since fields is sorted by name and
179 public ObjectStreamField
getField (String name
)
181 for (int i
= 0; i
< fields
.length
; i
++)
182 if (fields
[i
].getName().equals(name
))
188 * Returns a textual representation of this
189 * <code>ObjectStreamClass</code> object including the name of the
190 * class it represents as well as that class's serial version
191 * stream-unique identifier.
193 * @see #getSerialVersionUID()
196 public String
toString()
198 return "java.io.ObjectStreamClass< " + name
+ ", " + uid
+ " >";
201 // Returns true iff the class that this ObjectStreamClass represents
202 // has the following method:
204 // private void writeObject (ObjectOutputStream)
206 // This method is used by the class to override default
207 // serialization behavior.
208 boolean hasWriteMethod()
210 return (flags
& ObjectStreamConstants
.SC_WRITE_METHOD
) != 0;
213 // Returns true iff the class that this ObjectStreamClass represents
214 // implements Serializable but does *not* implement Externalizable.
215 boolean isSerializable()
217 return (flags
& ObjectStreamConstants
.SC_SERIALIZABLE
) != 0;
221 // Returns true iff the class that this ObjectStreamClass represents
222 // implements Externalizable.
223 boolean isExternalizable()
225 return (flags
& ObjectStreamConstants
.SC_EXTERNALIZABLE
) != 0;
228 // Returns true iff the class that this ObjectStreamClass represents
229 // implements Externalizable.
232 return (flags
& ObjectStreamConstants
.SC_ENUM
) != 0;
235 // Returns the <code>ObjectStreamClass</code> that represents the
236 // class that is the superclass of the class this
237 // <code>ObjectStreamClass</code> represents. If the superclass is
238 // not Serializable, null is returned.
239 ObjectStreamClass
getSuper()
245 * returns an array of ObjectStreamClasses that represent the super
246 * classes of the class represented by this and the class
247 * represented by this itself in order from most super to this.
248 * ObjectStreamClass[0] is the highest superclass of this that is
251 * The result of consecutive calls this hierarchy() will be the same
254 * @return an array of ObjectStreamClass representing the
255 * super-class hierarchy of serializable classes.
257 ObjectStreamClass
[] hierarchy()
259 ObjectStreamClass
[] result
= hierarchy
;
264 for(ObjectStreamClass osc
= this; osc
!= null; osc
= osc
.getSuper())
267 result
= new ObjectStreamClass
[d
];
269 for (ObjectStreamClass osc
= this; osc
!= null; osc
= osc
.getSuper())
280 * Cache for hierarchy() result.
282 private ObjectStreamClass
[] hierarchy
= null;
284 // Returns an integer that consists of bit-flags that indicate
285 // properties of the class represented by this ObjectStreamClass.
286 // The bit-flags that could be present are those defined in
287 // ObjectStreamConstants that begin with `SC_'
294 ObjectStreamClass(String name
, long uid
, byte flags
,
295 ObjectStreamField
[] fields
)
300 this.fields
= fields
;
304 * This method builds the internal description corresponding to a Java Class.
305 * As the constructor only assign a name to the current ObjectStreamClass instance,
306 * that method sets the serial UID, chose the fields which will be serialized,
307 * and compute the position of the fields in the serialized stream.
309 * @param cl The Java class which is used as a reference for building the descriptor.
310 * @param superClass The descriptor of the super class for this class descriptor.
311 * @throws InvalidClassException if an incompatibility between computed UID and
312 * already set UID is found.
314 void setClass(Class cl
, ObjectStreamClass superClass
) throws InvalidClassException
320 long class_uid
= getClassUID(cl
);
325 // Check that the actual UID of the resolved class matches the UID from
326 // the stream. Mismatches for array classes are ignored.
327 if (!cl
.isArray() && uid
!= class_uid
)
330 ": Local class not compatible: stream serialVersionUID="
331 + uid
+ ", local serialVersionUID=" + class_uid
;
332 throw new InvalidClassException (msg
);
336 isProxyClass
= clazz
!= null && Proxy
.isProxyClass(clazz
);
337 this.superClass
= superClass
;
342 ObjectStreamField
[] exportedFields
= getSerialPersistentFields (clazz
);
344 if (exportedFields
== null)
347 ObjectStreamField
[] newFieldList
= new ObjectStreamField
[exportedFields
.length
+ fields
.length
];
350 /* We now check the import fields against the exported fields.
351 * There should not be contradiction (e.g. int x and String x)
352 * but extra virtual fields can be added to the class.
355 Arrays
.sort(exportedFields
);
358 while (i
< fields
.length
&& j
< exportedFields
.length
)
360 int comp
= fields
[i
].compareTo(exportedFields
[j
]);
364 newFieldList
[k
] = fields
[i
];
365 fields
[i
].setPersistent(false);
366 fields
[i
].setToSet(false);
371 /* field not found in imported fields. We add it
372 * in the list of supported fields.
374 newFieldList
[k
] = exportedFields
[j
];
375 newFieldList
[k
].setPersistent(true);
376 newFieldList
[k
].setToSet(false);
379 newFieldList
[k
].lookupField(clazz
);
380 newFieldList
[k
].checkFieldType();
382 catch (NoSuchFieldException _
)
391 exportedFields
[j
].lookupField(clazz
);
392 exportedFields
[j
].checkFieldType();
394 catch (NoSuchFieldException _
)
398 if (!fields
[i
].getType().equals(exportedFields
[j
].getType()))
399 throw new InvalidClassException
400 ("serialPersistentFields must be compatible with" +
401 " imported fields (about " + fields
[i
].getName() + ")");
402 newFieldList
[k
] = fields
[i
];
403 fields
[i
].setPersistent(true);
410 if (i
< fields
.length
)
411 for (;i
<fields
.length
;i
++,k
++)
413 fields
[i
].setPersistent(false);
414 fields
[i
].setToSet(false);
415 newFieldList
[k
] = fields
[i
];
418 if (j
< exportedFields
.length
)
419 for (;j
<exportedFields
.length
;j
++,k
++)
421 exportedFields
[j
].setPersistent(true);
422 exportedFields
[j
].setToSet(false);
423 newFieldList
[k
] = exportedFields
[j
];
426 fields
= new ObjectStreamField
[k
];
427 System
.arraycopy(newFieldList
, 0, fields
, 0, k
);
429 catch (NoSuchFieldException ignore
)
433 catch (IllegalAccessException ignore
)
439 void setSuperclass (ObjectStreamClass osc
)
445 void calculateOffsets()
448 ObjectStreamField field
;
450 int fcount
= fields
.length
;
451 for (i
= 0; i
< fcount
; ++ i
)
455 if (! field
.isPrimitive())
458 field
.setOffset(primFieldSize
);
459 switch (field
.getTypeCode())
480 for (objectFieldCount
= 0; i
< fcount
; ++ i
)
481 fields
[i
].setOffset(objectFieldCount
++);
484 private Method
findMethod(Method
[] methods
, String name
, Class
[] params
,
485 Class returnType
, boolean mustBePrivate
)
488 for (int i
= 0; i
< methods
.length
; i
++)
490 final Method m
= methods
[i
];
491 int mods
= m
.getModifiers();
492 if (Modifier
.isStatic(mods
)
493 || (mustBePrivate
&& !Modifier
.isPrivate(mods
)))
498 if (m
.getName().equals(name
)
499 && m
.getReturnType() == returnType
)
501 Class
[] mp
= m
.getParameterTypes();
502 if (mp
.length
== params
.length
)
504 for (int j
= 0; j
< mp
.length
; j
++)
506 if (mp
[j
] != params
[j
])
511 AccessController
.doPrivileged(new SetAccessibleAction(m
));
519 private static boolean inSamePackage(Class c1
, Class c2
)
521 String name1
= c1
.getName();
522 String name2
= c2
.getName();
524 int id1
= name1
.lastIndexOf('.');
525 int id2
= name2
.lastIndexOf('.');
527 // Handle the default package
528 if (id1
== -1 || id2
== -1)
531 String package1
= name1
.substring(0, id1
);
532 String package2
= name2
.substring(0, id2
);
534 return package1
.equals(package2
);
537 final static Class
[] noArgs
= new Class
[0];
539 private static Method
findAccessibleMethod(String name
, Class from
)
541 for (Class c
= from
; c
!= null; c
= c
.getSuperclass())
545 Method res
= c
.getDeclaredMethod(name
, noArgs
);
546 int mods
= res
.getModifiers();
549 || Modifier
.isProtected(mods
)
550 || Modifier
.isPublic(mods
)
551 || (! Modifier
.isPrivate(mods
) && inSamePackage(c
, from
)))
553 AccessController
.doPrivileged(new SetAccessibleAction(res
));
557 catch (NoSuchMethodException e
)
566 * Helper routine to check if a class was loaded by boot or
567 * application class loader. Classes for which this is not the case
568 * should not be cached since caching prevent class file garbage
573 * @return true if cl was loaded by boot or application class loader,
574 * false if cl was loaded by a user class loader.
576 private static boolean loadedByBootOrApplicationClassLoader(Class cl
)
578 ClassLoader l
= cl
.getClassLoader();
580 ( l
== null /* boot loader */ )
581 || (l
== ClassLoader
.getSystemClassLoader() /* application loader */);
584 static Hashtable methodCache
= new Hashtable();
586 static final Class
[] readObjectSignature
= { ObjectInputStream
.class };
587 static final Class
[] writeObjectSignature
= { ObjectOutputStream
.class };
589 private void cacheMethods()
591 Class cl
= forClass();
592 Method
[] cached
= (Method
[]) methodCache
.get(cl
);
595 cached
= new Method
[4];
596 Method
[] methods
= cl
.getDeclaredMethods();
598 cached
[0] = findMethod(methods
, "readObject",
601 cached
[1] = findMethod(methods
, "writeObject",
602 writeObjectSignature
,
605 // readResolve and writeReplace can be in parent classes, as long as they
606 // are accessible from this class.
607 cached
[2] = findAccessibleMethod("readResolve", cl
);
608 cached
[3] = findAccessibleMethod("writeReplace", cl
);
610 /* put in cache if classes not loaded by user class loader.
611 * For a user class loader, the cache may otherwise grow
614 if (loadedByBootOrApplicationClassLoader(cl
))
615 methodCache
.put(cl
,cached
);
617 readObjectMethod
= cached
[0];
618 writeObjectMethod
= cached
[1];
619 readResolveMethod
= cached
[2];
620 writeReplaceMethod
= cached
[3];
623 private ObjectStreamClass(Class cl
)
627 isProxyClass
= Proxy
.isProxyClass(cl
);
634 // to those class nonserializable, its uid field is 0
635 if ( (Serializable
.class).isAssignableFrom(cl
) && !isProxyClass
)
636 uid
= getClassUID(cl
);
637 superClass
= lookup(cl
.getSuperclass());
641 // Sets bits in flags according to features of CL.
642 private void setFlags(Class cl
)
644 if ((java
.io
.Externalizable
.class).isAssignableFrom(cl
))
645 flags
|= ObjectStreamConstants
.SC_EXTERNALIZABLE
;
646 else if ((java
.io
.Serializable
.class).isAssignableFrom(cl
))
647 // only set this bit if CL is NOT Externalizable
648 flags
|= ObjectStreamConstants
.SC_SERIALIZABLE
;
650 if (writeObjectMethod
!= null)
651 flags
|= ObjectStreamConstants
.SC_WRITE_METHOD
;
653 if (cl
.isEnum() || cl
== Enum
.class)
654 flags
|= ObjectStreamConstants
.SC_ENUM
;
658 // FIXME: This is a workaround for a fairly obscure bug that happens
659 // when reading a Proxy and then writing it back out again. The
660 // result is that the ObjectStreamClass doesn't have its fields set,
661 // generating a NullPointerException. Rather than this kludge we
662 // should probably fix the real bug, but it would require a fairly
663 // radical reorganization to do so.
664 final void ensureFieldsSet(Class cl
)
672 // Sets fields to be a sorted array of the serializable fields of
674 private void setFields(Class cl
)
680 SetAccessibleAction setAccessible
= new SetAccessibleAction();
682 if (!isSerializable() || isExternalizable() || isEnum())
691 cl
.getDeclaredField("serialPersistentFields");
692 setAccessible
.setMember(f
);
693 AccessController
.doPrivileged(setAccessible
);
694 int modifiers
= f
.getModifiers();
696 if (Modifier
.isStatic(modifiers
)
697 && Modifier
.isFinal(modifiers
)
698 && Modifier
.isPrivate(modifiers
))
700 fields
= getSerialPersistentFields(cl
);
703 ObjectStreamField
[] fieldsName
= new ObjectStreamField
[fields
.length
];
704 System
.arraycopy(fields
, 0, fieldsName
, 0, fields
.length
);
706 Arrays
.sort (fieldsName
, new Comparator() {
707 public int compare(Object o1
, Object o2
)
709 ObjectStreamField f1
= (ObjectStreamField
)o1
;
710 ObjectStreamField f2
= (ObjectStreamField
)o2
;
712 return f1
.getName().compareTo(f2
.getName());
716 for (int i
=1; i
< fields
.length
; i
++)
718 if (fieldsName
[i
-1].getName().equals(fieldsName
[i
].getName()))
720 fields
= INVALID_FIELDS
;
725 Arrays
.sort (fields
);
726 // Retrieve field reference.
727 for (int i
=0; i
< fields
.length
; i
++)
731 fields
[i
].lookupField(cl
);
733 catch (NoSuchFieldException _
)
735 fields
[i
].setToSet(false);
744 catch (NoSuchFieldException ignore
)
747 catch (IllegalAccessException ignore
)
751 int num_good_fields
= 0;
752 Field
[] all_fields
= cl
.getDeclaredFields();
755 // set non-serializable fields to null in all_fields
756 for (int i
= 0; i
< all_fields
.length
; i
++)
758 modifiers
= all_fields
[i
].getModifiers();
759 if (Modifier
.isTransient(modifiers
)
760 || Modifier
.isStatic(modifiers
))
761 all_fields
[i
] = null;
766 // make a copy of serializable (non-null) fields
767 fields
= new ObjectStreamField
[ num_good_fields
];
768 for (int from
= 0, to
= 0; from
< all_fields
.length
; from
++)
769 if (all_fields
[from
] != null)
771 final Field f
= all_fields
[from
];
772 setAccessible
.setMember(f
);
773 AccessController
.doPrivileged(setAccessible
);
774 fields
[to
] = new ObjectStreamField(all_fields
[from
]);
779 // Make sure we don't have any duplicate field names
780 // (Sun JDK 1.4.1. throws an Internal Error as well)
781 for (int i
= 1; i
< fields
.length
; i
++)
783 if(fields
[i
- 1].getName().equals(fields
[i
].getName()))
784 throw new InternalError("Duplicate field " +
785 fields
[i
].getName() + " in class " + cl
.getName());
790 static Hashtable uidCache
= new Hashtable();
792 // Returns the serial version UID defined by class, or if that
793 // isn't present, calculates value of serial version UID.
794 private long getClassUID(Class cl
)
797 Long cache
= (Long
) uidCache
.get(cl
);
799 result
= cache
.longValue();
802 // Note that we can't use Class.isEnum() here, because that returns
803 // false for java.lang.Enum and enum value sub classes.
804 if (Enum
.class.isAssignableFrom(cl
) || Proxy
.isProxyClass(cl
))
806 // Spec says that enums and dynamic proxies have
807 // a serialVersionUID of 0L.
812 result
= getClassUIDFromField(cl
);
814 catch (NoSuchFieldException ignore
)
818 result
= calculateClassUID(cl
);
820 catch (NoSuchAlgorithmException e
)
822 throw new RuntimeException
823 ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
826 catch (IOException ioe
)
828 throw new RuntimeException(ioe
);
832 if (loadedByBootOrApplicationClassLoader(cl
))
833 uidCache
.put(cl
,new Long(result
));
839 * Search for a serialVersionUID field in the given class and read
842 * @return the contents of the serialVersionUID field
844 * @throws NoSuchFieldException if such a field does not exist or is
845 * not static, not final, not of type Long or not accessible.
847 long getClassUIDFromField(Class cl
)
848 throws NoSuchFieldException
854 // Use getDeclaredField rather than getField, since serialVersionUID
855 // may not be public AND we only want the serialVersionUID of this
856 // class, not a superclass or interface.
857 final Field suid
= cl
.getDeclaredField("serialVersionUID");
858 SetAccessibleAction setAccessible
= new SetAccessibleAction(suid
);
859 AccessController
.doPrivileged(setAccessible
);
860 int modifiers
= suid
.getModifiers();
862 if (Modifier
.isStatic(modifiers
)
863 && Modifier
.isFinal(modifiers
)
864 && suid
.getType() == Long
.TYPE
)
865 result
= suid
.getLong(null);
867 throw new NoSuchFieldException();
869 catch (IllegalAccessException ignore
)
871 throw new NoSuchFieldException();
878 * Calculate class serial version UID for a class that does not
879 * define serialVersionUID:
883 * @return the calculated serial varsion UID.
885 * @throws NoSuchAlgorithmException if SHA algorithm not found
887 * @throws IOException if writing to the DigestOutputStream causes
890 long calculateClassUID(Class cl
)
891 throws NoSuchAlgorithmException
, IOException
897 md
= MessageDigest
.getInstance("SHA");
899 catch (NoSuchAlgorithmException e
)
901 // If a provider already provides SHA, use it; otherwise, use this.
902 Gnu gnuProvider
= new Gnu();
903 Security
.addProvider(gnuProvider
);
904 md
= MessageDigest
.getInstance("SHA");
907 DigestOutputStream digest_out
=
908 new DigestOutputStream(nullOutputStream
, md
);
909 DataOutputStream data_out
= new DataOutputStream(digest_out
);
911 data_out
.writeUTF(cl
.getName());
913 int modifiers
= cl
.getModifiers();
914 // just look at interesting bits
915 modifiers
= modifiers
& (Modifier
.ABSTRACT
| Modifier
.FINAL
916 | Modifier
.INTERFACE
| Modifier
.PUBLIC
);
917 data_out
.writeInt(modifiers
);
919 // Pretend that an array has no interfaces, because when array
920 // serialization was defined (JDK 1.1), arrays didn't have it.
923 Class
[] interfaces
= cl
.getInterfaces();
924 Arrays
.sort(interfaces
, interfaceComparator
);
925 for (int i
= 0; i
< interfaces
.length
; i
++)
926 data_out
.writeUTF(interfaces
[i
].getName());
930 Field
[] fields
= cl
.getDeclaredFields();
931 Arrays
.sort(fields
, memberComparator
);
932 for (int i
= 0; i
< fields
.length
; i
++)
935 modifiers
= field
.getModifiers();
936 if (Modifier
.isPrivate(modifiers
)
937 && (Modifier
.isStatic(modifiers
)
938 || Modifier
.isTransient(modifiers
)))
941 data_out
.writeUTF(field
.getName());
942 data_out
.writeInt(modifiers
);
943 data_out
.writeUTF(TypeSignature
.getEncodingOfClass (field
.getType()));
946 // write class initializer method if present
947 if (VMObjectStreamClass
.hasClassInitializer(cl
))
949 data_out
.writeUTF("<clinit>");
950 data_out
.writeInt(Modifier
.STATIC
);
951 data_out
.writeUTF("()V");
954 Constructor constructor
;
955 Constructor
[] constructors
= cl
.getDeclaredConstructors();
956 Arrays
.sort (constructors
, memberComparator
);
957 for (int i
= 0; i
< constructors
.length
; i
++)
959 constructor
= constructors
[i
];
960 modifiers
= constructor
.getModifiers();
961 if (Modifier
.isPrivate(modifiers
))
964 data_out
.writeUTF("<init>");
965 data_out
.writeInt(modifiers
);
967 // the replacement of '/' with '.' was needed to make computed
968 // SUID's agree with those computed by JDK
970 (TypeSignature
.getEncodingOfConstructor(constructor
).replace('/','.'));
974 Method
[] methods
= cl
.getDeclaredMethods();
975 Arrays
.sort(methods
, memberComparator
);
976 for (int i
= 0; i
< methods
.length
; i
++)
979 modifiers
= method
.getModifiers();
980 if (Modifier
.isPrivate(modifiers
))
983 data_out
.writeUTF(method
.getName());
984 data_out
.writeInt(modifiers
);
986 // the replacement of '/' with '.' was needed to make computed
987 // SUID's agree with those computed by JDK
989 (TypeSignature
.getEncodingOfMethod(method
).replace('/', '.'));
993 byte[] sha
= md
.digest();
995 int len
= sha
.length
< 8 ? sha
.length
: 8;
996 for (int i
= 0; i
< len
; i
++)
997 result
+= (long) (sha
[i
] & 0xFF) << (8 * i
);
1003 * Returns the value of CLAZZ's private static final field named
1004 * `serialPersistentFields'. It performs some sanity checks before
1005 * returning the real array. Besides, the returned array is a clean
1006 * copy of the original. So it can be modified.
1008 * @param clazz Class to retrieve 'serialPersistentFields' from.
1009 * @return The content of 'serialPersistentFields'.
1011 private ObjectStreamField
[] getSerialPersistentFields(Class clazz
)
1012 throws NoSuchFieldException
, IllegalAccessException
1014 ObjectStreamField
[] fieldsArray
= null;
1015 ObjectStreamField
[] o
;
1017 // Use getDeclaredField rather than getField for the same reason
1018 // as above in getDefinedSUID.
1019 Field f
= clazz
.getDeclaredField("serialPersistentFields");
1020 f
.setAccessible(true);
1022 int modifiers
= f
.getModifiers();
1023 if (!(Modifier
.isStatic(modifiers
) &&
1024 Modifier
.isFinal(modifiers
) &&
1025 Modifier
.isPrivate(modifiers
)))
1028 o
= (ObjectStreamField
[]) f
.get(null);
1033 fieldsArray
= new ObjectStreamField
[ o
.length
];
1034 System
.arraycopy(o
, 0, fieldsArray
, 0, o
.length
);
1040 * Returns a new instance of the Class this ObjectStreamClass corresponds
1042 * Note that this should only be used for Externalizable classes.
1044 * @return A new instance.
1046 Externalizable
newInstance() throws InvalidClassException
1050 if (constructor
== null)
1054 final Constructor c
= clazz
.getConstructor(new Class
[0]);
1056 AccessController
.doPrivileged(new PrivilegedAction()
1060 c
.setAccessible(true);
1067 catch(NoSuchMethodException x
)
1069 throw new InvalidClassException(clazz
.getName(),
1070 "No public zero-argument constructor");
1077 return (Externalizable
)constructor
.newInstance(null);
1081 throw (InvalidClassException
)
1082 new InvalidClassException(clazz
.getName(),
1083 "Unable to instantiate").initCause(x
);
1087 public static final ObjectStreamField
[] NO_FIELDS
= {};
1089 private static Hashtable
<Class
,ObjectStreamClass
> classLookupTable
1090 = new Hashtable
<Class
,ObjectStreamClass
>();
1091 private static final NullOutputStream nullOutputStream
= new NullOutputStream();
1092 private static final Comparator interfaceComparator
= new InterfaceComparator();
1093 private static final Comparator memberComparator
= new MemberComparator();
1094 private static final
1095 Class
[] writeMethodArgTypes
= { java
.io
.ObjectOutputStream
.class };
1097 private ObjectStreamClass superClass
;
1098 private Class
<?
> clazz
;
1099 private String name
;
1103 // this field is package protected so that ObjectInputStream and
1104 // ObjectOutputStream can access it directly
1105 ObjectStreamField
[] fields
;
1107 // these are accessed by ObjectIn/OutputStream
1108 int primFieldSize
= -1; // -1 if not yet calculated
1109 int objectFieldCount
;
1111 Method readObjectMethod
;
1112 Method readResolveMethod
;
1113 Method writeReplaceMethod
;
1114 Method writeObjectMethod
;
1115 boolean realClassIsSerializable
;
1116 boolean realClassIsExternalizable
;
1117 ObjectStreamField
[] fieldMapping
;
1118 Constructor firstNonSerializableParentConstructor
;
1119 private Constructor constructor
; // default constructor for Externalizable
1121 boolean isProxyClass
= false;
1124 // True after setFields() has been called
1125 private boolean fieldsSet
= false;
1128 // This is probably not necessary because this class is special cased already
1129 // but it will avoid showing up as a discrepancy when comparing SUIDs.
1130 private static final long serialVersionUID
= -6120832682080437368L;
1133 // interfaces are compared only by name
1134 private static final class InterfaceComparator
implements Comparator
1136 public int compare(Object o1
, Object o2
)
1138 return ((Class
) o1
).getName().compareTo(((Class
) o2
).getName());
1143 // Members (Methods and Constructors) are compared first by name,
1144 // conflicts are resolved by comparing type signatures
1145 private static final class MemberComparator
implements Comparator
1147 public int compare(Object o1
, Object o2
)
1149 Member m1
= (Member
) o1
;
1150 Member m2
= (Member
) o2
;
1152 int comp
= m1
.getName().compareTo(m2
.getName());
1155 return TypeSignature
.getEncodingOfMember(m1
).
1156 compareTo(TypeSignature
.getEncodingOfMember(m2
));