Merge from mainline
[official-gcc.git] / libjava / classpath / java / io / ObjectStreamClass.java
blob203e4a5abaaa2c3d4d0838df36881eacd4125a47
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)
10 any later version.
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
20 02110-1301 USA.
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
25 combination.
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. */
40 package java.io;
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];
68 /**
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
74 * will be done.
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)
85 if (cl == null)
86 return null;
87 if (! (Serializable.class).isAssignableFrom(cl))
88 return null;
90 return lookupForClassObject(cl);
93 /**
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)
100 if (cl == null)
101 return null;
103 ObjectStreamClass osc = (ObjectStreamClass) classLookupTable.get(cl);
105 if (osc != null)
106 return osc;
107 else
109 osc = new ObjectStreamClass(cl);
110 classLookupTable.put(cl, osc);
111 return 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()
123 return name;
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()
137 return clazz;
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()
151 return uid;
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);
167 return copy;
170 // XXX doc
171 // Can't do binary search since fields is sorted by name and
172 // primitiveness.
173 public ObjectStreamField getField (String name)
175 for (int i = 0; i < fields.length; i++)
176 if (fields[i].getName().equals(name))
177 return fields[i];
178 return null;
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()
188 * @see #getName()
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()
229 return superClass;
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);
241 if (osc == null)
242 return new ObjectStreamClass[0];
243 else
245 Vector oscs = new Vector();
247 while (osc != null)
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);
259 return sorted_oscs;
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_'
268 int getFlags()
270 return flags;
274 ObjectStreamClass(String name, long uid, byte flags,
275 ObjectStreamField[] fields)
277 this.name = name;
278 this.uid = uid;
279 this.flags = flags;
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
296 this.clazz = cl;
298 cacheMethods();
300 long class_uid = getClassUID(cl);
301 if (uid == 0)
302 uid = class_uid;
303 else
305 // Check that the actual UID of the resolved class matches the UID from
306 // the stream.
307 if (uid != class_uid)
309 String msg = cl +
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;
318 calculateOffsets();
322 ObjectStreamField[] exportedFields = getSerialPersistentFields (clazz);
324 if (exportedFields == null)
325 return;
327 ObjectStreamField[] newFieldList = new ObjectStreamField[exportedFields.length + fields.length];
328 int i, j, k;
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);
337 i = 0; j = 0; k = 0;
338 while (i < fields.length && j < exportedFields.length)
340 int comp = fields[i].compareTo(exportedFields[j]);
342 if (comp < 0)
344 newFieldList[k] = fields[i];
345 fields[i].setPersistent(false);
346 fields[i].setToSet(false);
347 i++;
349 else if (comp > 0)
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 _)
365 j++;
367 else
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);
384 i++;
385 j++;
387 k++;
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];
397 else
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)
411 return;
413 catch (IllegalAccessException ignore)
415 return;
419 void setSuperclass (ObjectStreamClass osc)
421 superClass = osc;
424 void calculateOffsets()
426 int i;
427 ObjectStreamField field;
428 primFieldSize = 0;
429 int fcount = fields.length;
430 for (i = 0; i < fcount; ++ i)
432 field = fields[i];
434 if (! field.isPrimitive())
435 break;
437 field.setOffset(primFieldSize);
438 switch (field.getTypeCode())
440 case 'B':
441 case 'Z':
442 ++ primFieldSize;
443 break;
444 case 'C':
445 case 'S':
446 primFieldSize += 2;
447 break;
448 case 'I':
449 case 'F':
450 primFieldSize += 4;
451 break;
452 case 'D':
453 case 'J':
454 primFieldSize += 8;
455 break;
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)
466 outer:
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)))
474 continue;
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])
487 continue outer;
490 AccessController.doPrivileged(new SetAccessibleAction(m));
491 return m;
495 return null;
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)
508 return id1 == id2;
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();
527 if (c == from
528 || Modifier.isProtected(mods)
529 || Modifier.isPublic(mods)
530 || (! Modifier.isPrivate(mods) && inSamePackage(c, from)))
532 AccessController.doPrivileged(new SetAccessibleAction(res));
533 return res;
536 catch (NoSuchMethodException e)
541 return null;
544 private void cacheMethods()
546 Method[] methods = forClass().getDeclaredMethods();
548 readObjectMethod = findMethod(methods, "readObject",
549 new Class[] { ObjectInputStream.class },
550 Void.TYPE, true);
551 writeObjectMethod = findMethod(methods, "writeObject",
552 new Class[] { ObjectOutputStream.class },
553 Void.TYPE, true);
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)
563 uid = 0;
564 flags = 0;
565 isProxyClass = Proxy.isProxyClass(cl);
567 clazz = cl;
568 cacheMethods();
569 name = cl.getName();
570 setFlags(cl);
571 setFields(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
594 // clazz.
595 private void setFields(Class cl)
597 SetAccessibleAction setAccessible = new SetAccessibleAction();
599 if (!isSerializable() || isExternalizable())
601 fields = NO_FIELDS;
602 return;
607 final Field f =
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);
618 if (fields != null)
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;
638 return;
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);
656 calculateOffsets();
657 return;
661 catch (NoSuchFieldException ignore)
664 catch (IllegalAccessException ignore)
668 int num_good_fields = 0;
669 Field[] all_fields = cl.getDeclaredFields();
671 int modifiers;
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;
679 else
680 num_good_fields++;
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]);
692 to++;
695 Arrays.sort(fields);
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());
704 calculateOffsets();
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
736 MessageDigest md;
737 try
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.
763 if (! cl.isArray())
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());
771 Field field;
772 Field[] fields = cl.getDeclaredFields();
773 Arrays.sort(fields, memberComparator);
774 for (int i = 0; i < fields.length; i++)
776 field = fields[i];
777 modifiers = field.getModifiers();
778 if (Modifier.isPrivate(modifiers)
779 && (Modifier.isStatic(modifiers)
780 || Modifier.isTransient(modifiers)))
781 continue;
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))
804 continue;
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
811 data_out.writeUTF
812 (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
815 Method method;
816 Method[] methods = cl.getDeclaredMethods();
817 Arrays.sort(methods, memberComparator);
818 for (int i = 0; i < methods.length; i++)
820 method = methods[i];
821 modifiers = method.getModifiers();
822 if (Modifier.isPrivate(modifiers))
823 continue;
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
830 data_out.writeUTF
831 (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
834 data_out.close();
835 byte[] sha = md.digest();
836 long result = 0;
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);
841 return result;
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 "
847 + cl.getName(), e);
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)))
879 return null;
881 o = (ObjectStreamField[]) f.get(null);
883 if (o == null)
884 return null;
886 fieldsArray = new ObjectStreamField[ o.length ];
887 System.arraycopy(o, 0, fieldsArray, 0, o.length);
889 return fieldsArray;
893 * Returns a new instance of the Class this ObjectStreamClass corresponds
894 * to.
895 * Note that this should only be used for Externalizable classes.
897 * @return A new instance.
899 Externalizable newInstance() throws InvalidClassException
901 synchronized(this)
903 if (constructor == null)
907 final Constructor c = clazz.getConstructor(new Class[0]);
909 AccessController.doPrivileged(new PrivilegedAction()
911 public Object run()
913 c.setAccessible(true);
914 return null;
918 constructor = c;
920 catch(NoSuchMethodException x)
922 throw new InvalidClassException(clazz.getName(),
923 "No public zero-argument constructor");
930 return (Externalizable)constructor.newInstance(null);
932 catch(Exception x)
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();
946 private static final
947 Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
949 private ObjectStreamClass superClass;
950 private Class clazz;
951 private String name;
952 private long uid;
953 private byte flags;
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());
1001 if (comp == 0)
1002 return TypeSignature.getEncodingOfMember(m1).
1003 compareTo(TypeSignature.getEncodingOfMember(m2));
1004 else
1005 return comp;