Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
28 import java.lang.ref.Reference;
29 import java.lang.ref.ReferenceQueue;
30 import java.lang.ref.SoftReference;
31 import java.lang.ref.WeakReference;
32 import java.lang.reflect.Constructor;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.InvocationTargetException;
35 import java.lang.reflect.Member;
36 import java.lang.reflect.Method;
37 import java.lang.reflect.Modifier;
38 import java.lang.reflect.Proxy;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Collections;
42 import java.util.Comparator;
43 import java.util.HashSet;
47 * Serialization's descriptor for classes. It contains the name and
48 * serialVersionUID of the class. The ObjectStreamClass for a specific class
49 * loaded in this Java VM can be found/created using the lookup method.
51 * <p>The algorithm to compute the SerialVersionUID is described in
52 * <a href="../../../platform/serialization/spec/class.html#4100">Object
53 * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
57 * @see ObjectStreamField
58 * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
61 public class ObjectStreamClass implements Serializable {
63 /** serialPersistentFields value indicating no serializable fields */
64 public static final ObjectStreamField[] NO_FIELDS =
65 new ObjectStreamField[0];
67 private static final long serialVersionUID = -6120832682080437368L;
68 private static final ObjectStreamField[] serialPersistentFields =
72 /** class associated with this descriptor (if any) */
74 /** name of class represented by this descriptor */
76 /** serialVersionUID of represented class (null if not computed yet) */
77 private volatile Long suid;
79 /** true if represents dynamic proxy class */
80 private boolean isProxy;
81 /** true if represents enum type */
82 private boolean isEnum;
83 /** true if represented class implements Serializable */
84 private boolean serializable;
85 /** true if represented class implements Externalizable */
86 private boolean externalizable;
87 /** true if desc has data written by class-defined writeObject method */
88 private boolean hasWriteObjectData;
90 * true if desc has externalizable data written in block data format; this
91 * must be true by default to accommodate ObjectInputStream subclasses which
92 * override readClassDescriptor() to return class descriptors obtained from
93 * ObjectStreamClass.lookup() (see 4461737)
95 private boolean hasBlockExternalData = true;
97 /** exception (if any) thrown while attempting to resolve class */
98 private ClassNotFoundException resolveEx;
99 /** exception (if any) to throw if non-enum deserialization attempted */
100 private InvalidClassException deserializeEx;
101 /** exception (if any) to throw if non-enum serialization attempted */
102 private InvalidClassException serializeEx;
103 /** exception (if any) to throw if default serialization attempted */
104 private InvalidClassException defaultSerializeEx;
106 /** serializable fields */
107 private ObjectStreamField[] fields;
108 /** aggregate marshalled size of primitive fields */
109 private int primDataSize;
110 /** number of non-primitive fields */
111 private int numObjFields;
112 /** reflector for setting/getting serializable field values */
113 // private FieldReflector fieldRefl;
114 /** data layout of serialized objects described by this class desc */
115 private volatile ClassDataSlot[] dataLayout;
117 /** serialization-appropriate constructor, or null if none */
118 private Constructor cons;
119 /** class-defined writeObject method, or null if none */
120 private Method writeObjectMethod;
121 /** class-defined readObject method, or null if none */
122 private Method readObjectMethod;
123 /** class-defined readObjectNoData method, or null if none */
124 private Method readObjectNoDataMethod;
125 /** class-defined writeReplace method, or null if none */
126 private Method writeReplaceMethod;
127 /** class-defined readResolve method, or null if none */
128 private Method readResolveMethod;
130 /** local class descriptor for represented class (may point to self) */
131 private ObjectStreamClass localDesc;
132 /** superclass descriptor appearing in stream */
133 private ObjectStreamClass superDesc;
136 * Initializes native code.
138 private static native void initNative();
144 * Find the descriptor for a class that can be serialized. Creates an
145 * ObjectStreamClass instance if one does not exist yet for class. Null is
146 * returned if the specified class does not implement java.io.Serializable
147 * or java.io.Externalizable.
149 * @param cl class for which to get the descriptor
150 * @return the class descriptor for the specified class
152 public static ObjectStreamClass lookup(Class<?> cl) {
153 return lookup(cl, false);
157 * Returns the descriptor for any class, regardless of whether it
158 * implements {@link Serializable}.
160 * @param cl class for which to get the descriptor
161 * @return the class descriptor for the specified class
164 public static ObjectStreamClass lookupAny(Class<?> cl) {
165 return lookup(cl, true);
169 * Returns the name of the class described by this descriptor.
170 * This method returns the name of the class in the format that
171 * is used by the {@link Class#getName} method.
173 * @return a string representing the name of the class
175 public String getName() {
180 * Return the serialVersionUID for this class. The serialVersionUID
181 * defines a set of classes all with the same name that have evolved from a
182 * common root class and agree to be serialized and deserialized using a
183 * common format. NonSerializable classes have a serialVersionUID of 0L.
185 * @return the SUID of the class described by this descriptor
187 public long getSerialVersionUID() {
188 // REMIND: synchronize instead of relying on volatile?
190 return computeDefaultSUID(cl);
192 return suid.longValue();
196 * Return the class in the local VM that this version is mapped to. Null
197 * is returned if there is no corresponding local class.
199 * @return the <code>Class</code> instance that this descriptor represents
201 public Class<?> forClass() {
206 * Return an array of the fields of this serializable class.
208 * @return an array containing an element for each persistent field of
209 * this class. Returns an array of length zero if there are no
213 public ObjectStreamField[] getFields() {
214 return getFields(true);
218 * Get the field of this class by name.
220 * @param name the name of the data field to look for
221 * @return The ObjectStreamField object of the named field or null if
222 * there is no such named field.
224 public ObjectStreamField getField(String name) {
225 return getField(name, null);
229 * Return a string describing this ObjectStreamClass.
231 public String toString() {
232 return name + ": static final long serialVersionUID = " +
233 getSerialVersionUID() + "L;";
237 * Looks up and returns class descriptor for given class, or null if class
238 * is non-serializable and "all" is set to false.
240 * @param cl class to look up
241 * @param all if true, return descriptors for all classes; if false, only
242 * return descriptors for serializable classes
244 static ObjectStreamClass lookup(Class<?> cl, boolean all) {
245 if (!(all || Serializable.class.isAssignableFrom(cl))) {
249 EntryFuture future = null;
251 EntryFuture newEntry = new EntryFuture();
252 Reference<?> newRef = new SoftReference<>(newEntry);
258 if (entry instanceof ObjectStreamClass) { // check common case first
259 return (ObjectStreamClass) entry;
261 if (entry instanceof EntryFuture) {
262 future = (EntryFuture) entry;
265 * Handle nested call situation described by 4803747: waiting
266 * for future value to be set by a lookup() call further up the
267 * stack will result in deadlock, so calculate and set the
268 * future value here instead.
272 entry = future.get();
277 entry = new ObjectStreamClass(cl);
278 } catch (Throwable th) {
281 // nested lookup call already set future
282 entry = future.get();
285 if (entry instanceof ObjectStreamClass) {
286 return (ObjectStreamClass) entry;
287 } else if (entry instanceof RuntimeException) {
288 throw (RuntimeException) entry;
289 } else if (entry instanceof Error) {
292 throw new InternalError("unexpected entry: " + entry);
297 * Placeholder used in class descriptor and field reflector lookup tables
298 * for an entry in the process of being initialized. (Internal) callers
299 * which receive an EntryFuture belonging to another thread as the result
300 * of a lookup should call the get() method of the EntryFuture; this will
301 * return the actual entry once it is ready for use and has been set(). To
302 * conserve objects, EntryFutures synchronize on themselves.
304 private static class EntryFuture {
306 private static final Object unset = new Object();
307 private Object entry = unset;
310 * Attempts to set the value contained by this EntryFuture. If the
311 * EntryFuture's value has not been set already, then the value is
312 * saved, any callers blocked in the get() method are notified, and
313 * true is returned. If the value has already been set, then no saving
314 * or notification occurs, and false is returned.
316 synchronized boolean set(Object entry) {
317 if (this.entry != unset) {
326 * Returns the value contained by this EntryFuture, blocking if
327 * necessary until a value is set.
329 synchronized Object get() {
330 boolean interrupted = false;
331 while (entry == unset) {
334 } catch (InterruptedException ex) {
343 * Creates local class descriptor representing given class.
345 private ObjectStreamClass(final Class<?> cl) {
348 isProxy = Proxy.isProxyClass(cl);
349 isEnum = Enum.class.isAssignableFrom(cl);
350 serializable = Serializable.class.isAssignableFrom(cl);
351 externalizable = Externalizable.class.isAssignableFrom(cl);
353 Class<?> superCl = cl.getSuperclass();
354 superDesc = (superCl != null) ? lookup(superCl, false) : null;
357 suid = Long.valueOf(0);
361 if (deserializeEx == null) {
363 deserializeEx = new InvalidClassException(name, "enum type");
364 } else if (cons == null) {
365 deserializeEx = new InvalidClassException(
366 name, "no valid constructor");
369 for (int i = 0; i < fields.length; i++) {
370 if (fields[i].getField() == null) {
371 defaultSerializeEx = new InvalidClassException(
372 name, "unmatched serializable field(s) declared");
378 * Creates blank class descriptor which should be initialized via a
379 * subsequent call to initProxy(), initNonProxy() or readNonProxy().
381 ObjectStreamClass() {
385 * Initializes class descriptor representing a proxy class.
387 void initProxy(Class<?> cl,
388 ClassNotFoundException resolveEx,
389 ObjectStreamClass superDesc)
390 throws InvalidClassException
393 this.resolveEx = resolveEx;
394 this.superDesc = superDesc;
397 suid = Long.valueOf(0);
401 localDesc = lookup(cl, true);
402 if (!localDesc.isProxy) {
403 throw new InvalidClassException(
404 "cannot bind proxy descriptor to a non-proxy class");
406 name = localDesc.name;
407 externalizable = localDesc.externalizable;
408 cons = localDesc.cons;
409 writeReplaceMethod = localDesc.writeReplaceMethod;
410 readResolveMethod = localDesc.readResolveMethod;
411 deserializeEx = localDesc.deserializeEx;
416 * Initializes class descriptor representing a non-proxy class.
418 void initNonProxy(ObjectStreamClass model,
420 ClassNotFoundException resolveEx,
421 ObjectStreamClass superDesc)
422 throws InvalidClassException
425 this.resolveEx = resolveEx;
426 this.superDesc = superDesc;
428 suid = Long.valueOf(model.getSerialVersionUID());
430 isEnum = model.isEnum;
431 serializable = model.serializable;
432 externalizable = model.externalizable;
433 hasBlockExternalData = model.hasBlockExternalData;
434 hasWriteObjectData = model.hasWriteObjectData;
435 fields = model.fields;
436 primDataSize = model.primDataSize;
437 numObjFields = model.numObjFields;
440 localDesc = lookup(cl, true);
441 if (localDesc.isProxy) {
442 throw new InvalidClassException(
443 "cannot bind non-proxy descriptor to a proxy class");
445 if (isEnum != localDesc.isEnum) {
446 throw new InvalidClassException(isEnum ?
447 "cannot bind enum descriptor to a non-enum class" :
448 "cannot bind non-enum descriptor to an enum class");
451 if (serializable == localDesc.serializable &&
453 suid.longValue() != localDesc.getSerialVersionUID())
455 throw new InvalidClassException(localDesc.name,
456 "local class incompatible: " +
457 "stream classdesc serialVersionUID = " + suid +
458 ", local class serialVersionUID = " +
459 localDesc.getSerialVersionUID());
462 if (!classNamesEqual(name, localDesc.name)) {
463 throw new InvalidClassException(localDesc.name,
464 "local class name incompatible with stream class " +
465 "name \"" + name + "\"");
469 if ((serializable == localDesc.serializable) &&
470 (externalizable != localDesc.externalizable))
472 throw new InvalidClassException(localDesc.name,
473 "Serializable incompatible with Externalizable");
476 if ((serializable != localDesc.serializable) ||
477 (externalizable != localDesc.externalizable) ||
478 !(serializable || externalizable))
480 deserializeEx = new InvalidClassException(localDesc.name,
481 "class invalid for deserialization");
485 cons = localDesc.cons;
486 writeObjectMethod = localDesc.writeObjectMethod;
487 readObjectMethod = localDesc.readObjectMethod;
488 readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
489 writeReplaceMethod = localDesc.writeReplaceMethod;
490 readResolveMethod = localDesc.readResolveMethod;
491 if (deserializeEx == null) {
492 deserializeEx = localDesc.deserializeEx;
495 // reassign to matched fields so as to reflect local unshared settings
500 * Reads non-proxy class descriptor information from given input stream.
501 * The resulting class descriptor is not fully functional; it can only be
502 * used as input to the ObjectInputStream.resolveClass() and
503 * ObjectStreamClass.initNonProxy() methods.
505 void readNonProxy(ObjectInputStream in)
506 throws IOException, ClassNotFoundException
509 suid = Long.valueOf(in.readLong());
512 byte flags = in.readByte();
514 ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
515 hasBlockExternalData =
516 ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
518 ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
520 ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
521 if (externalizable && sflag) {
522 throw new InvalidClassException(
523 name, "serializable and externalizable flags conflict");
525 serializable = externalizable || sflag;
526 isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
527 if (isEnum && suid.longValue() != 0L) {
528 throw new InvalidClassException(name,
529 "enum descriptor has non-zero serialVersionUID: " + suid);
532 int numFields = in.readShort();
533 if (isEnum && numFields != 0) {
534 throw new InvalidClassException(name,
535 "enum descriptor has non-zero field count: " + numFields);
537 fields = (numFields > 0) ?
538 new ObjectStreamField[numFields] : NO_FIELDS;
539 for (int i = 0; i < numFields; i++) {
540 char tcode = (char) in.readByte();
541 String fname = in.readUTF();
542 String signature = ((tcode == 'L') || (tcode == '[')) ?
543 in.readTypeString() : new String(new char[] { tcode });
545 fields[i] = new ObjectStreamField(fname, signature, false);
546 } catch (RuntimeException e) {
547 throw (IOException) new InvalidClassException(name,
548 "invalid descriptor for field " + fname).initCause(e);
551 computeFieldOffsets();
555 * Writes non-proxy class descriptor information to given output stream.
557 void writeNonProxy(ObjectOutputStream out) throws IOException {
559 out.writeLong(getSerialVersionUID());
562 if (externalizable) {
563 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
564 int protocol = out.getProtocolVersion();
565 if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
566 flags |= ObjectStreamConstants.SC_BLOCK_DATA;
568 } else if (serializable) {
569 flags |= ObjectStreamConstants.SC_SERIALIZABLE;
571 if (hasWriteObjectData) {
572 flags |= ObjectStreamConstants.SC_WRITE_METHOD;
575 flags |= ObjectStreamConstants.SC_ENUM;
577 out.writeByte(flags);
579 out.writeShort(fields.length);
580 for (int i = 0; i < fields.length; i++) {
581 ObjectStreamField f = fields[i];
582 out.writeByte(f.getTypeCode());
583 out.writeUTF(f.getName());
584 if (!f.isPrimitive()) {
585 out.writeTypeString(f.getTypeString());
591 * Returns ClassNotFoundException (if any) thrown while attempting to
592 * resolve local class corresponding to this class descriptor.
594 ClassNotFoundException getResolveException() {
599 * Throws an InvalidClassException if object instances referencing this
600 * class descriptor should not be allowed to deserialize. This method does
601 * not apply to deserialization of enum constants.
603 void checkDeserialize() throws InvalidClassException {
604 if (deserializeEx != null) {
605 InvalidClassException ice =
606 new InvalidClassException(deserializeEx.classname,
607 deserializeEx.getMessage());
608 ice.initCause(deserializeEx);
614 * Throws an InvalidClassException if objects whose class is represented by
615 * this descriptor should not be allowed to serialize. This method does
616 * not apply to serialization of enum constants.
618 void checkSerialize() throws InvalidClassException {
619 if (serializeEx != null) {
620 InvalidClassException ice =
621 new InvalidClassException(serializeEx.classname,
622 serializeEx.getMessage());
623 ice.initCause(serializeEx);
629 * Throws an InvalidClassException if objects whose class is represented by
630 * this descriptor should not be permitted to use default serialization
631 * (e.g., if the class declares serializable fields that do not correspond
632 * to actual fields, and hence must use the GetField API). This method
633 * does not apply to deserialization of enum constants.
635 void checkDefaultSerialize() throws InvalidClassException {
636 if (defaultSerializeEx != null) {
637 InvalidClassException ice =
638 new InvalidClassException(defaultSerializeEx.classname,
639 defaultSerializeEx.getMessage());
640 ice.initCause(defaultSerializeEx);
646 * Returns superclass descriptor. Note that on the receiving side, the
647 * superclass descriptor may be bound to a class that is not a superclass
648 * of the subclass descriptor's bound class.
650 ObjectStreamClass getSuperDesc() {
655 * Returns the "local" class descriptor for the class associated with this
656 * class descriptor (i.e., the result of
657 * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
658 * associated with this descriptor.
660 ObjectStreamClass getLocalDesc() {
665 * Returns arrays of ObjectStreamFields representing the serializable
666 * fields of the represented class. If copy is true, a clone of this class
667 * descriptor's field array is returned, otherwise the array itself is
670 ObjectStreamField[] getFields(boolean copy) {
671 return copy ? fields.clone() : fields;
675 * Looks up a serializable field of the represented class by name and type.
676 * A specified type of null matches all types, Object.class matches all
677 * non-primitive types, and any other non-null type matches assignable
678 * types only. Returns matching field, or null if no match found.
680 ObjectStreamField getField(String name, Class<?> type) {
681 for (int i = 0; i < fields.length; i++) {
682 ObjectStreamField f = fields[i];
683 if (f.getName().equals(name)) {
685 (type == Object.class && !f.isPrimitive()))
689 Class<?> ftype = f.getType();
690 if (ftype != null && type.isAssignableFrom(ftype)) {
699 * Returns true if class descriptor represents a dynamic proxy class, false
707 * Returns true if class descriptor represents an enum type, false
715 * Returns true if represented class implements Externalizable, false
718 boolean isExternalizable() {
719 return externalizable;
723 * Returns true if represented class implements Serializable, false
726 boolean isSerializable() {
731 * Returns true if class descriptor represents externalizable class that
732 * has written its data in 1.2 (block data) format, false otherwise.
734 boolean hasBlockExternalData() {
735 return hasBlockExternalData;
739 * Returns true if class descriptor represents serializable (but not
740 * externalizable) class which has written its data via a custom
741 * writeObject() method, false otherwise.
743 boolean hasWriteObjectData() {
744 return hasWriteObjectData;
748 * Returns true if represented class is serializable/externalizable and can
749 * be instantiated by the serialization runtime--i.e., if it is
750 * externalizable and defines a public no-arg constructor, or if it is
751 * non-externalizable and its first non-serializable superclass defines an
752 * accessible no-arg constructor. Otherwise, returns false.
754 boolean isInstantiable() {
755 return (cons != null);
759 * Returns true if represented class is serializable (but not
760 * externalizable) and defines a conformant writeObject method. Otherwise,
763 boolean hasWriteObjectMethod() {
764 return (writeObjectMethod != null);
768 * Returns true if represented class is serializable (but not
769 * externalizable) and defines a conformant readObject method. Otherwise,
772 boolean hasReadObjectMethod() {
773 return (readObjectMethod != null);
777 * Returns true if represented class is serializable (but not
778 * externalizable) and defines a conformant readObjectNoData method.
779 * Otherwise, returns false.
781 boolean hasReadObjectNoDataMethod() {
782 return (readObjectNoDataMethod != null);
786 * Returns true if represented class is serializable or externalizable and
787 * defines a conformant writeReplace method. Otherwise, returns false.
789 boolean hasWriteReplaceMethod() {
790 return (writeReplaceMethod != null);
794 * Returns true if represented class is serializable or externalizable and
795 * defines a conformant readResolve method. Otherwise, returns false.
797 boolean hasReadResolveMethod() {
798 return (readResolveMethod != null);
802 * Creates a new instance of the represented class. If the class is
803 * externalizable, invokes its public no-arg constructor; otherwise, if the
804 * class is serializable, invokes the no-arg constructor of the first
805 * non-serializable superclass. Throws UnsupportedOperationException if
806 * this class descriptor is not associated with a class, if the associated
807 * class is non-serializable or if the appropriate no-arg constructor is
808 * inaccessible/unavailable.
811 throws InstantiationException, InvocationTargetException,
812 UnsupportedOperationException
816 return cons.newInstance();
817 } catch (IllegalAccessException ex) {
818 // should not occur, as access checks have been suppressed
819 throw new InternalError();
822 throw new UnsupportedOperationException();
827 * Invokes the writeObject method of the represented serializable class.
828 * Throws UnsupportedOperationException if this class descriptor is not
829 * associated with a class, or if the class is externalizable,
830 * non-serializable or does not define writeObject.
832 void invokeWriteObject(Object obj, ObjectOutputStream out)
833 throws IOException, UnsupportedOperationException
835 if (writeObjectMethod != null) {
837 writeObjectMethod.invoke(obj, new Object[]{ out });
838 } catch (InvocationTargetException ex) {
839 Throwable th = ex.getTargetException();
840 if (th instanceof IOException) {
841 throw (IOException) th;
843 throwMiscException(th);
845 } catch (IllegalAccessException ex) {
846 // should not occur, as access checks have been suppressed
847 throw new InternalError();
850 throw new UnsupportedOperationException();
855 * Invokes the readObject method of the represented serializable class.
856 * Throws UnsupportedOperationException if this class descriptor is not
857 * associated with a class, or if the class is externalizable,
858 * non-serializable or does not define readObject.
860 void invokeReadObject(Object obj, ObjectInputStream in)
861 throws ClassNotFoundException, IOException,
862 UnsupportedOperationException
864 if (readObjectMethod != null) {
866 readObjectMethod.invoke(obj, new Object[]{ in });
867 } catch (InvocationTargetException ex) {
868 Throwable th = ex.getTargetException();
869 if (th instanceof ClassNotFoundException) {
870 throw (ClassNotFoundException) th;
871 } else if (th instanceof IOException) {
872 throw (IOException) th;
874 throwMiscException(th);
876 } catch (IllegalAccessException ex) {
877 // should not occur, as access checks have been suppressed
878 throw new InternalError();
881 throw new UnsupportedOperationException();
886 * Invokes the readObjectNoData method of the represented serializable
887 * class. Throws UnsupportedOperationException if this class descriptor is
888 * not associated with a class, or if the class is externalizable,
889 * non-serializable or does not define readObjectNoData.
891 void invokeReadObjectNoData(Object obj)
892 throws IOException, UnsupportedOperationException
894 if (readObjectNoDataMethod != null) {
896 readObjectNoDataMethod.invoke(obj, (Object[]) null);
897 } catch (InvocationTargetException ex) {
898 Throwable th = ex.getTargetException();
899 if (th instanceof ObjectStreamException) {
900 throw (ObjectStreamException) th;
902 throwMiscException(th);
904 } catch (IllegalAccessException ex) {
905 // should not occur, as access checks have been suppressed
906 throw new InternalError();
909 throw new UnsupportedOperationException();
914 * Invokes the writeReplace method of the represented serializable class and
915 * returns the result. Throws UnsupportedOperationException if this class
916 * descriptor is not associated with a class, or if the class is
917 * non-serializable or does not define writeReplace.
919 Object invokeWriteReplace(Object obj)
920 throws IOException, UnsupportedOperationException
922 if (writeReplaceMethod != null) {
924 return writeReplaceMethod.invoke(obj, (Object[]) null);
925 } catch (InvocationTargetException ex) {
926 Throwable th = ex.getTargetException();
927 if (th instanceof ObjectStreamException) {
928 throw (ObjectStreamException) th;
930 throwMiscException(th);
931 throw new InternalError(); // never reached
933 } catch (IllegalAccessException ex) {
934 // should not occur, as access checks have been suppressed
935 throw new InternalError();
938 throw new UnsupportedOperationException();
943 * Invokes the readResolve method of the represented serializable class and
944 * returns the result. Throws UnsupportedOperationException if this class
945 * descriptor is not associated with a class, or if the class is
946 * non-serializable or does not define readResolve.
948 Object invokeReadResolve(Object obj)
949 throws IOException, UnsupportedOperationException
951 if (readResolveMethod != null) {
953 return readResolveMethod.invoke(obj, (Object[]) null);
954 } catch (InvocationTargetException ex) {
955 Throwable th = ex.getTargetException();
956 if (th instanceof ObjectStreamException) {
957 throw (ObjectStreamException) th;
959 throwMiscException(th);
960 throw new InternalError(); // never reached
962 } catch (IllegalAccessException ex) {
963 // should not occur, as access checks have been suppressed
964 throw new InternalError();
967 throw new UnsupportedOperationException();
972 * Class representing the portion of an object's serialized form allotted
973 * to data described by a given class descriptor. If "hasData" is false,
974 * the object's serialized form does not contain data associated with the
977 static class ClassDataSlot {
979 /** class descriptor "occupying" this slot */
980 final ObjectStreamClass desc;
981 /** true if serialized form includes data for this slot's descriptor */
982 final boolean hasData;
984 ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
986 this.hasData = hasData;
991 * Returns array of ClassDataSlot instances representing the data layout
992 * (including superclass data) for serialized objects described by this
993 * class descriptor. ClassDataSlots are ordered by inheritance with those
994 * containing "higher" superclasses appearing first. The final
995 * ClassDataSlot contains a reference to this descriptor.
997 ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
998 // REMIND: synchronize instead of relying on volatile?
999 if (dataLayout == null) {
1000 dataLayout = getClassDataLayout0();
1005 private ClassDataSlot[] getClassDataLayout0()
1006 throws InvalidClassException
1008 ArrayList<ClassDataSlot> slots = new ArrayList<>();
1009 Class<?> start = cl, end = cl;
1011 // locate closest non-serializable superclass
1012 while (end != null && Serializable.class.isAssignableFrom(end)) {
1013 end = end.getSuperclass();
1016 for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
1018 // search up inheritance hierarchy for class with matching name
1019 String searchName = (d.cl != null) ? d.cl.getName() : d.name;
1020 Class<?> match = null;
1021 for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1022 if (searchName.equals(c.getName())) {
1028 // add "no data" slot for each unmatched class below match
1029 if (match != null) {
1030 for (Class<?> c = start; c != match; c = c.getSuperclass()) {
1031 slots.add(new ClassDataSlot(
1032 ObjectStreamClass.lookup(c, true), false));
1034 start = match.getSuperclass();
1037 // record descriptor/class pairing
1038 slots.add(new ClassDataSlot(d.getVariantFor(match), true));
1041 // add "no data" slot for any leftover unmatched classes
1042 for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1043 slots.add(new ClassDataSlot(
1044 ObjectStreamClass.lookup(c, true), false));
1047 // order slots from superclass -> subclass
1048 Collections.reverse(slots);
1049 return slots.toArray(new ClassDataSlot[slots.size()]);
1053 * Returns aggregate size (in bytes) of marshalled primitive field values
1054 * for represented class.
1056 int getPrimDataSize() {
1057 return primDataSize;
1061 * Returns number of non-primitive serializable fields of represented
1064 int getNumObjFields() {
1065 return numObjFields;
1069 * Fetches the serializable primitive field values of object obj and
1070 * marshals them into byte array buf starting at offset 0. It is the
1071 * responsibility of the caller to ensure that obj is of the proper type if
1074 void getPrimFieldValues(Object obj, byte[] buf) {
1078 * Sets the serializable primitive fields of object obj using values
1079 * unmarshalled from byte array buf starting at offset 0. It is the
1080 * responsibility of the caller to ensure that obj is of the proper type if
1083 void setPrimFieldValues(Object obj, byte[] buf) {
1087 * Fetches the serializable object field values of object obj and stores
1088 * them in array vals starting at offset 0. It is the responsibility of
1089 * the caller to ensure that obj is of the proper type if non-null.
1091 void getObjFieldValues(Object obj, Object[] vals) {
1095 * Sets the serializable object fields of object obj using values from
1096 * array vals starting at offset 0. It is the responsibility of the caller
1097 * to ensure that obj is of the proper type if non-null.
1099 void setObjFieldValues(Object obj, Object[] vals) {
1103 * Calculates and sets serializable field offsets, as well as primitive
1104 * data size and object field count totals. Throws InvalidClassException
1105 * if fields are illegally ordered.
1107 private void computeFieldOffsets() throws InvalidClassException {
1110 int firstObjIndex = -1;
1112 for (int i = 0; i < fields.length; i++) {
1113 ObjectStreamField f = fields[i];
1114 switch (f.getTypeCode()) {
1117 f.setOffset(primDataSize++);
1122 f.setOffset(primDataSize);
1128 f.setOffset(primDataSize);
1134 f.setOffset(primDataSize);
1140 f.setOffset(numObjFields++);
1141 if (firstObjIndex == -1) {
1147 throw new InternalError();
1150 if (firstObjIndex != -1 &&
1151 firstObjIndex + numObjFields != fields.length)
1153 throw new InvalidClassException(name, "illegal field order");
1158 * If given class is the same as the class associated with this class
1159 * descriptor, returns reference to this class descriptor. Otherwise,
1160 * returns variant of this class descriptor bound to given class.
1162 private ObjectStreamClass getVariantFor(Class<?> cl)
1163 throws InvalidClassException
1165 if (this.cl == cl) {
1168 ObjectStreamClass desc = new ObjectStreamClass();
1170 desc.initProxy(cl, null, superDesc);
1172 desc.initNonProxy(this, cl, null, superDesc);
1178 * Returns public no-arg constructor of given class, or null if none found.
1179 * Access checks are disabled on the returned constructor (if any), since
1180 * the defining class may still be non-public.
1182 private static Constructor getExternalizableConstructor(Class<?> cl) {
1183 throw new SecurityException();
1187 * Returns subclass-accessible no-arg constructor of first non-serializable
1188 * superclass, or null if none found. Access checks are disabled on the
1189 * returned constructor (if any).
1191 private static Constructor getSerializableConstructor(Class<?> cl) {
1192 Class<?> initCl = cl;
1193 while (Serializable.class.isAssignableFrom(initCl)) {
1194 if ((initCl = initCl.getSuperclass()) == null) {
1198 throw new SecurityException();
1202 * Returns non-static, non-abstract method with given signature provided it
1203 * is defined by or accessible (via inheritance) by the given class, or
1204 * null if no match found. Access checks are disabled on the returned
1207 private static Method getInheritableMethod(Class<?> cl, String name,
1208 Class<?>[] argTypes,
1209 Class<?> returnType)
1211 throw new SecurityException();
1215 * Returns non-static private method with given signature defined by given
1216 * class, or null if none found. Access checks are disabled on the
1217 * returned method (if any).
1219 private static Method getPrivateMethod(Class<?> cl, String name,
1220 Class<?>[] argTypes,
1221 Class<?> returnType)
1223 throw new SecurityException();
1227 * Returns true if classes are defined in the same runtime package, false
1230 private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
1231 return (cl1.getClassLoader() == cl2.getClassLoader() &&
1232 getPackageName(cl1).equals(getPackageName(cl2)));
1236 * Returns package name of given class.
1238 private static String getPackageName(Class<?> cl) {
1239 String s = cl.getName();
1240 int i = s.lastIndexOf('[');
1242 s = s.substring(i + 2);
1244 i = s.lastIndexOf('.');
1245 return (i >= 0) ? s.substring(0, i) : "";
1249 * Compares class names for equality, ignoring package names. Returns true
1250 * if class names equal, false otherwise.
1252 private static boolean classNamesEqual(String name1, String name2) {
1253 name1 = name1.substring(name1.lastIndexOf('.') + 1);
1254 name2 = name2.substring(name2.lastIndexOf('.') + 1);
1255 return name1.equals(name2);
1259 * Returns JVM type signature for given class.
1261 private static String getClassSignature(Class<?> cl) {
1262 StringBuilder sbuf = new StringBuilder();
1263 while (cl.isArray()) {
1265 cl = cl.getComponentType();
1267 if (cl.isPrimitive()) {
1268 if (cl == Integer.TYPE) {
1270 } else if (cl == Byte.TYPE) {
1272 } else if (cl == Long.TYPE) {
1274 } else if (cl == Float.TYPE) {
1276 } else if (cl == Double.TYPE) {
1278 } else if (cl == Short.TYPE) {
1280 } else if (cl == Character.TYPE) {
1282 } else if (cl == Boolean.TYPE) {
1284 } else if (cl == Void.TYPE) {
1287 throw new InternalError();
1290 sbuf.append('L' + cl.getName().replace('.', '/') + ';');
1292 return sbuf.toString();
1296 * Returns JVM type signature for given list of parameters and return type.
1298 private static String getMethodSignature(Class<?>[] paramTypes,
1301 StringBuilder sbuf = new StringBuilder();
1303 for (int i = 0; i < paramTypes.length; i++) {
1304 sbuf.append(getClassSignature(paramTypes[i]));
1307 sbuf.append(getClassSignature(retType));
1308 return sbuf.toString();
1312 * Convenience method for throwing an exception that is either a
1313 * RuntimeException, Error, or of some unexpected type (in which case it is
1314 * wrapped inside an IOException).
1316 private static void throwMiscException(Throwable th) throws IOException {
1317 if (th instanceof RuntimeException) {
1318 throw (RuntimeException) th;
1319 } else if (th instanceof Error) {
1322 IOException ex = new IOException("unexpected exception type");
1329 * Returns ObjectStreamField array describing the serializable fields of
1330 * the given class. Serializable fields backed by an actual field of the
1331 * class are represented by ObjectStreamFields with corresponding non-null
1332 * Field objects. Throws InvalidClassException if the (explicitly
1333 * declared) serializable fields are invalid.
1335 private static ObjectStreamField[] getSerialFields(Class<?> cl)
1336 throws InvalidClassException
1338 ObjectStreamField[] fields;
1339 if (Serializable.class.isAssignableFrom(cl) &&
1340 !Externalizable.class.isAssignableFrom(cl) &&
1341 !Proxy.isProxyClass(cl) &&
1344 if ((fields = getDeclaredSerialFields(cl)) == null) {
1345 fields = getDefaultSerialFields(cl);
1347 Arrays.sort(fields);
1355 * Returns serializable fields of given class as defined explicitly by a
1356 * "serialPersistentFields" field, or null if no appropriate
1357 * "serialPersistentFields" field is defined. Serializable fields backed
1358 * by an actual field of the class are represented by ObjectStreamFields
1359 * with corresponding non-null Field objects. For compatibility with past
1360 * releases, a "serialPersistentFields" field with a null value is
1361 * considered equivalent to not declaring "serialPersistentFields". Throws
1362 * InvalidClassException if the declared serializable fields are
1363 * invalid--e.g., if multiple fields share the same name.
1365 private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
1366 throws InvalidClassException
1368 throw new SecurityException();
1372 * Returns array of ObjectStreamFields corresponding to all non-static
1373 * non-transient fields declared by given class. Each ObjectStreamField
1374 * contains a Field object for the field it represents. If no default
1375 * serializable fields exist, NO_FIELDS is returned.
1377 private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
1378 throw new SecurityException();
1382 * Returns explicit serial version UID value declared by given class, or
1385 private static Long getDeclaredSUID(Class<?> cl) {
1390 * Computes the default serial version UID value for the given class.
1392 private static long computeDefaultSUID(Class<?> cl) {
1393 throw new SecurityException();