1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/io/ObjectStreamClass.java Tue Feb 26 16:54:16 2013 +0100
1.3 @@ -0,0 +1,1396 @@
1.4 +/*
1.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package java.io;
1.30 +
1.31 +import java.lang.ref.Reference;
1.32 +import java.lang.ref.ReferenceQueue;
1.33 +import java.lang.ref.SoftReference;
1.34 +import java.lang.ref.WeakReference;
1.35 +import java.lang.reflect.Constructor;
1.36 +import java.lang.reflect.Field;
1.37 +import java.lang.reflect.InvocationTargetException;
1.38 +import java.lang.reflect.Member;
1.39 +import java.lang.reflect.Method;
1.40 +import java.lang.reflect.Modifier;
1.41 +import java.lang.reflect.Proxy;
1.42 +import java.util.ArrayList;
1.43 +import java.util.Arrays;
1.44 +import java.util.Collections;
1.45 +import java.util.Comparator;
1.46 +import java.util.HashSet;
1.47 +import java.util.Set;
1.48 +
1.49 +/**
1.50 + * Serialization's descriptor for classes. It contains the name and
1.51 + * serialVersionUID of the class. The ObjectStreamClass for a specific class
1.52 + * loaded in this Java VM can be found/created using the lookup method.
1.53 + *
1.54 + * <p>The algorithm to compute the SerialVersionUID is described in
1.55 + * <a href="../../../platform/serialization/spec/class.html#4100">Object
1.56 + * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
1.57 + *
1.58 + * @author Mike Warres
1.59 + * @author Roger Riggs
1.60 + * @see ObjectStreamField
1.61 + * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
1.62 + * @since JDK1.1
1.63 + */
1.64 +public class ObjectStreamClass implements Serializable {
1.65 +
1.66 + /** serialPersistentFields value indicating no serializable fields */
1.67 + public static final ObjectStreamField[] NO_FIELDS =
1.68 + new ObjectStreamField[0];
1.69 +
1.70 + private static final long serialVersionUID = -6120832682080437368L;
1.71 + private static final ObjectStreamField[] serialPersistentFields =
1.72 + NO_FIELDS;
1.73 +
1.74 +
1.75 + /** class associated with this descriptor (if any) */
1.76 + private Class<?> cl;
1.77 + /** name of class represented by this descriptor */
1.78 + private String name;
1.79 + /** serialVersionUID of represented class (null if not computed yet) */
1.80 + private volatile Long suid;
1.81 +
1.82 + /** true if represents dynamic proxy class */
1.83 + private boolean isProxy;
1.84 + /** true if represents enum type */
1.85 + private boolean isEnum;
1.86 + /** true if represented class implements Serializable */
1.87 + private boolean serializable;
1.88 + /** true if represented class implements Externalizable */
1.89 + private boolean externalizable;
1.90 + /** true if desc has data written by class-defined writeObject method */
1.91 + private boolean hasWriteObjectData;
1.92 + /**
1.93 + * true if desc has externalizable data written in block data format; this
1.94 + * must be true by default to accommodate ObjectInputStream subclasses which
1.95 + * override readClassDescriptor() to return class descriptors obtained from
1.96 + * ObjectStreamClass.lookup() (see 4461737)
1.97 + */
1.98 + private boolean hasBlockExternalData = true;
1.99 +
1.100 + /** exception (if any) thrown while attempting to resolve class */
1.101 + private ClassNotFoundException resolveEx;
1.102 + /** exception (if any) to throw if non-enum deserialization attempted */
1.103 + private InvalidClassException deserializeEx;
1.104 + /** exception (if any) to throw if non-enum serialization attempted */
1.105 + private InvalidClassException serializeEx;
1.106 + /** exception (if any) to throw if default serialization attempted */
1.107 + private InvalidClassException defaultSerializeEx;
1.108 +
1.109 + /** serializable fields */
1.110 + private ObjectStreamField[] fields;
1.111 + /** aggregate marshalled size of primitive fields */
1.112 + private int primDataSize;
1.113 + /** number of non-primitive fields */
1.114 + private int numObjFields;
1.115 + /** reflector for setting/getting serializable field values */
1.116 +// private FieldReflector fieldRefl;
1.117 + /** data layout of serialized objects described by this class desc */
1.118 + private volatile ClassDataSlot[] dataLayout;
1.119 +
1.120 + /** serialization-appropriate constructor, or null if none */
1.121 + private Constructor cons;
1.122 + /** class-defined writeObject method, or null if none */
1.123 + private Method writeObjectMethod;
1.124 + /** class-defined readObject method, or null if none */
1.125 + private Method readObjectMethod;
1.126 + /** class-defined readObjectNoData method, or null if none */
1.127 + private Method readObjectNoDataMethod;
1.128 + /** class-defined writeReplace method, or null if none */
1.129 + private Method writeReplaceMethod;
1.130 + /** class-defined readResolve method, or null if none */
1.131 + private Method readResolveMethod;
1.132 +
1.133 + /** local class descriptor for represented class (may point to self) */
1.134 + private ObjectStreamClass localDesc;
1.135 + /** superclass descriptor appearing in stream */
1.136 + private ObjectStreamClass superDesc;
1.137 +
1.138 + /**
1.139 + * Initializes native code.
1.140 + */
1.141 + private static native void initNative();
1.142 + static {
1.143 + initNative();
1.144 + }
1.145 +
1.146 + /**
1.147 + * Find the descriptor for a class that can be serialized. Creates an
1.148 + * ObjectStreamClass instance if one does not exist yet for class. Null is
1.149 + * returned if the specified class does not implement java.io.Serializable
1.150 + * or java.io.Externalizable.
1.151 + *
1.152 + * @param cl class for which to get the descriptor
1.153 + * @return the class descriptor for the specified class
1.154 + */
1.155 + public static ObjectStreamClass lookup(Class<?> cl) {
1.156 + return lookup(cl, false);
1.157 + }
1.158 +
1.159 + /**
1.160 + * Returns the descriptor for any class, regardless of whether it
1.161 + * implements {@link Serializable}.
1.162 + *
1.163 + * @param cl class for which to get the descriptor
1.164 + * @return the class descriptor for the specified class
1.165 + * @since 1.6
1.166 + */
1.167 + public static ObjectStreamClass lookupAny(Class<?> cl) {
1.168 + return lookup(cl, true);
1.169 + }
1.170 +
1.171 + /**
1.172 + * Returns the name of the class described by this descriptor.
1.173 + * This method returns the name of the class in the format that
1.174 + * is used by the {@link Class#getName} method.
1.175 + *
1.176 + * @return a string representing the name of the class
1.177 + */
1.178 + public String getName() {
1.179 + return name;
1.180 + }
1.181 +
1.182 + /**
1.183 + * Return the serialVersionUID for this class. The serialVersionUID
1.184 + * defines a set of classes all with the same name that have evolved from a
1.185 + * common root class and agree to be serialized and deserialized using a
1.186 + * common format. NonSerializable classes have a serialVersionUID of 0L.
1.187 + *
1.188 + * @return the SUID of the class described by this descriptor
1.189 + */
1.190 + public long getSerialVersionUID() {
1.191 + // REMIND: synchronize instead of relying on volatile?
1.192 + if (suid == null) {
1.193 + return computeDefaultSUID(cl);
1.194 + }
1.195 + return suid.longValue();
1.196 + }
1.197 +
1.198 + /**
1.199 + * Return the class in the local VM that this version is mapped to. Null
1.200 + * is returned if there is no corresponding local class.
1.201 + *
1.202 + * @return the <code>Class</code> instance that this descriptor represents
1.203 + */
1.204 + public Class<?> forClass() {
1.205 + return cl;
1.206 + }
1.207 +
1.208 + /**
1.209 + * Return an array of the fields of this serializable class.
1.210 + *
1.211 + * @return an array containing an element for each persistent field of
1.212 + * this class. Returns an array of length zero if there are no
1.213 + * fields.
1.214 + * @since 1.2
1.215 + */
1.216 + public ObjectStreamField[] getFields() {
1.217 + return getFields(true);
1.218 + }
1.219 +
1.220 + /**
1.221 + * Get the field of this class by name.
1.222 + *
1.223 + * @param name the name of the data field to look for
1.224 + * @return The ObjectStreamField object of the named field or null if
1.225 + * there is no such named field.
1.226 + */
1.227 + public ObjectStreamField getField(String name) {
1.228 + return getField(name, null);
1.229 + }
1.230 +
1.231 + /**
1.232 + * Return a string describing this ObjectStreamClass.
1.233 + */
1.234 + public String toString() {
1.235 + return name + ": static final long serialVersionUID = " +
1.236 + getSerialVersionUID() + "L;";
1.237 + }
1.238 +
1.239 + /**
1.240 + * Looks up and returns class descriptor for given class, or null if class
1.241 + * is non-serializable and "all" is set to false.
1.242 + *
1.243 + * @param cl class to look up
1.244 + * @param all if true, return descriptors for all classes; if false, only
1.245 + * return descriptors for serializable classes
1.246 + */
1.247 + static ObjectStreamClass lookup(Class<?> cl, boolean all) {
1.248 + if (!(all || Serializable.class.isAssignableFrom(cl))) {
1.249 + return null;
1.250 + }
1.251 + Object entry = null;
1.252 + EntryFuture future = null;
1.253 + if (entry == null) {
1.254 + EntryFuture newEntry = new EntryFuture();
1.255 + Reference<?> newRef = new SoftReference<>(newEntry);
1.256 + if (entry == null) {
1.257 + future = newEntry;
1.258 + }
1.259 + }
1.260 +
1.261 + if (entry instanceof ObjectStreamClass) { // check common case first
1.262 + return (ObjectStreamClass) entry;
1.263 + }
1.264 + if (entry instanceof EntryFuture) {
1.265 + future = (EntryFuture) entry;
1.266 + if (true) {
1.267 + /*
1.268 + * Handle nested call situation described by 4803747: waiting
1.269 + * for future value to be set by a lookup() call further up the
1.270 + * stack will result in deadlock, so calculate and set the
1.271 + * future value here instead.
1.272 + */
1.273 + entry = null;
1.274 + } else {
1.275 + entry = future.get();
1.276 + }
1.277 + }
1.278 + if (entry == null) {
1.279 + try {
1.280 + entry = new ObjectStreamClass(cl);
1.281 + } catch (Throwable th) {
1.282 + entry = th;
1.283 + }
1.284 + // nested lookup call already set future
1.285 + entry = future.get();
1.286 + }
1.287 +
1.288 + if (entry instanceof ObjectStreamClass) {
1.289 + return (ObjectStreamClass) entry;
1.290 + } else if (entry instanceof RuntimeException) {
1.291 + throw (RuntimeException) entry;
1.292 + } else if (entry instanceof Error) {
1.293 + throw (Error) entry;
1.294 + } else {
1.295 + throw new InternalError("unexpected entry: " + entry);
1.296 + }
1.297 + }
1.298 +
1.299 + /**
1.300 + * Placeholder used in class descriptor and field reflector lookup tables
1.301 + * for an entry in the process of being initialized. (Internal) callers
1.302 + * which receive an EntryFuture belonging to another thread as the result
1.303 + * of a lookup should call the get() method of the EntryFuture; this will
1.304 + * return the actual entry once it is ready for use and has been set(). To
1.305 + * conserve objects, EntryFutures synchronize on themselves.
1.306 + */
1.307 + private static class EntryFuture {
1.308 +
1.309 + private static final Object unset = new Object();
1.310 + private Object entry = unset;
1.311 +
1.312 + /**
1.313 + * Attempts to set the value contained by this EntryFuture. If the
1.314 + * EntryFuture's value has not been set already, then the value is
1.315 + * saved, any callers blocked in the get() method are notified, and
1.316 + * true is returned. If the value has already been set, then no saving
1.317 + * or notification occurs, and false is returned.
1.318 + */
1.319 + synchronized boolean set(Object entry) {
1.320 + if (this.entry != unset) {
1.321 + return false;
1.322 + }
1.323 + this.entry = entry;
1.324 + notifyAll();
1.325 + return true;
1.326 + }
1.327 +
1.328 + /**
1.329 + * Returns the value contained by this EntryFuture, blocking if
1.330 + * necessary until a value is set.
1.331 + */
1.332 + synchronized Object get() {
1.333 + boolean interrupted = false;
1.334 + while (entry == unset) {
1.335 + try {
1.336 + wait();
1.337 + } catch (InterruptedException ex) {
1.338 + interrupted = true;
1.339 + }
1.340 + }
1.341 + return entry;
1.342 + }
1.343 + }
1.344 +
1.345 + /**
1.346 + * Creates local class descriptor representing given class.
1.347 + */
1.348 + private ObjectStreamClass(final Class<?> cl) {
1.349 + this.cl = cl;
1.350 + name = cl.getName();
1.351 + isProxy = Proxy.isProxyClass(cl);
1.352 + isEnum = Enum.class.isAssignableFrom(cl);
1.353 + serializable = Serializable.class.isAssignableFrom(cl);
1.354 + externalizable = Externalizable.class.isAssignableFrom(cl);
1.355 +
1.356 + Class<?> superCl = cl.getSuperclass();
1.357 + superDesc = (superCl != null) ? lookup(superCl, false) : null;
1.358 + localDesc = this;
1.359 +
1.360 + suid = Long.valueOf(0);
1.361 + fields = NO_FIELDS;
1.362 +
1.363 +
1.364 + if (deserializeEx == null) {
1.365 + if (isEnum) {
1.366 + deserializeEx = new InvalidClassException(name, "enum type");
1.367 + } else if (cons == null) {
1.368 + deserializeEx = new InvalidClassException(
1.369 + name, "no valid constructor");
1.370 + }
1.371 + }
1.372 + for (int i = 0; i < fields.length; i++) {
1.373 + if (fields[i].getField() == null) {
1.374 + defaultSerializeEx = new InvalidClassException(
1.375 + name, "unmatched serializable field(s) declared");
1.376 + }
1.377 + }
1.378 + }
1.379 +
1.380 + /**
1.381 + * Creates blank class descriptor which should be initialized via a
1.382 + * subsequent call to initProxy(), initNonProxy() or readNonProxy().
1.383 + */
1.384 + ObjectStreamClass() {
1.385 + }
1.386 +
1.387 + /**
1.388 + * Initializes class descriptor representing a proxy class.
1.389 + */
1.390 + void initProxy(Class<?> cl,
1.391 + ClassNotFoundException resolveEx,
1.392 + ObjectStreamClass superDesc)
1.393 + throws InvalidClassException
1.394 + {
1.395 + this.cl = cl;
1.396 + this.resolveEx = resolveEx;
1.397 + this.superDesc = superDesc;
1.398 + isProxy = true;
1.399 + serializable = true;
1.400 + suid = Long.valueOf(0);
1.401 + fields = NO_FIELDS;
1.402 +
1.403 + if (cl != null) {
1.404 + localDesc = lookup(cl, true);
1.405 + if (!localDesc.isProxy) {
1.406 + throw new InvalidClassException(
1.407 + "cannot bind proxy descriptor to a non-proxy class");
1.408 + }
1.409 + name = localDesc.name;
1.410 + externalizable = localDesc.externalizable;
1.411 + cons = localDesc.cons;
1.412 + writeReplaceMethod = localDesc.writeReplaceMethod;
1.413 + readResolveMethod = localDesc.readResolveMethod;
1.414 + deserializeEx = localDesc.deserializeEx;
1.415 + }
1.416 + }
1.417 +
1.418 + /**
1.419 + * Initializes class descriptor representing a non-proxy class.
1.420 + */
1.421 + void initNonProxy(ObjectStreamClass model,
1.422 + Class<?> cl,
1.423 + ClassNotFoundException resolveEx,
1.424 + ObjectStreamClass superDesc)
1.425 + throws InvalidClassException
1.426 + {
1.427 + this.cl = cl;
1.428 + this.resolveEx = resolveEx;
1.429 + this.superDesc = superDesc;
1.430 + name = model.name;
1.431 + suid = Long.valueOf(model.getSerialVersionUID());
1.432 + isProxy = false;
1.433 + isEnum = model.isEnum;
1.434 + serializable = model.serializable;
1.435 + externalizable = model.externalizable;
1.436 + hasBlockExternalData = model.hasBlockExternalData;
1.437 + hasWriteObjectData = model.hasWriteObjectData;
1.438 + fields = model.fields;
1.439 + primDataSize = model.primDataSize;
1.440 + numObjFields = model.numObjFields;
1.441 +
1.442 + if (cl != null) {
1.443 + localDesc = lookup(cl, true);
1.444 + if (localDesc.isProxy) {
1.445 + throw new InvalidClassException(
1.446 + "cannot bind non-proxy descriptor to a proxy class");
1.447 + }
1.448 + if (isEnum != localDesc.isEnum) {
1.449 + throw new InvalidClassException(isEnum ?
1.450 + "cannot bind enum descriptor to a non-enum class" :
1.451 + "cannot bind non-enum descriptor to an enum class");
1.452 + }
1.453 +
1.454 + if (serializable == localDesc.serializable &&
1.455 + !cl.isArray() &&
1.456 + suid.longValue() != localDesc.getSerialVersionUID())
1.457 + {
1.458 + throw new InvalidClassException(localDesc.name,
1.459 + "local class incompatible: " +
1.460 + "stream classdesc serialVersionUID = " + suid +
1.461 + ", local class serialVersionUID = " +
1.462 + localDesc.getSerialVersionUID());
1.463 + }
1.464 +
1.465 + if (!classNamesEqual(name, localDesc.name)) {
1.466 + throw new InvalidClassException(localDesc.name,
1.467 + "local class name incompatible with stream class " +
1.468 + "name \"" + name + "\"");
1.469 + }
1.470 +
1.471 + if (!isEnum) {
1.472 + if ((serializable == localDesc.serializable) &&
1.473 + (externalizable != localDesc.externalizable))
1.474 + {
1.475 + throw new InvalidClassException(localDesc.name,
1.476 + "Serializable incompatible with Externalizable");
1.477 + }
1.478 +
1.479 + if ((serializable != localDesc.serializable) ||
1.480 + (externalizable != localDesc.externalizable) ||
1.481 + !(serializable || externalizable))
1.482 + {
1.483 + deserializeEx = new InvalidClassException(localDesc.name,
1.484 + "class invalid for deserialization");
1.485 + }
1.486 + }
1.487 +
1.488 + cons = localDesc.cons;
1.489 + writeObjectMethod = localDesc.writeObjectMethod;
1.490 + readObjectMethod = localDesc.readObjectMethod;
1.491 + readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
1.492 + writeReplaceMethod = localDesc.writeReplaceMethod;
1.493 + readResolveMethod = localDesc.readResolveMethod;
1.494 + if (deserializeEx == null) {
1.495 + deserializeEx = localDesc.deserializeEx;
1.496 + }
1.497 + }
1.498 + // reassign to matched fields so as to reflect local unshared settings
1.499 + fields = null;
1.500 + }
1.501 +
1.502 + /**
1.503 + * Reads non-proxy class descriptor information from given input stream.
1.504 + * The resulting class descriptor is not fully functional; it can only be
1.505 + * used as input to the ObjectInputStream.resolveClass() and
1.506 + * ObjectStreamClass.initNonProxy() methods.
1.507 + */
1.508 + void readNonProxy(ObjectInputStream in)
1.509 + throws IOException, ClassNotFoundException
1.510 + {
1.511 + name = in.readUTF();
1.512 + suid = Long.valueOf(in.readLong());
1.513 + isProxy = false;
1.514 +
1.515 + byte flags = in.readByte();
1.516 + hasWriteObjectData =
1.517 + ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
1.518 + hasBlockExternalData =
1.519 + ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
1.520 + externalizable =
1.521 + ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
1.522 + boolean sflag =
1.523 + ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
1.524 + if (externalizable && sflag) {
1.525 + throw new InvalidClassException(
1.526 + name, "serializable and externalizable flags conflict");
1.527 + }
1.528 + serializable = externalizable || sflag;
1.529 + isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
1.530 + if (isEnum && suid.longValue() != 0L) {
1.531 + throw new InvalidClassException(name,
1.532 + "enum descriptor has non-zero serialVersionUID: " + suid);
1.533 + }
1.534 +
1.535 + int numFields = in.readShort();
1.536 + if (isEnum && numFields != 0) {
1.537 + throw new InvalidClassException(name,
1.538 + "enum descriptor has non-zero field count: " + numFields);
1.539 + }
1.540 + fields = (numFields > 0) ?
1.541 + new ObjectStreamField[numFields] : NO_FIELDS;
1.542 + for (int i = 0; i < numFields; i++) {
1.543 + char tcode = (char) in.readByte();
1.544 + String fname = in.readUTF();
1.545 + String signature = ((tcode == 'L') || (tcode == '[')) ?
1.546 + in.readTypeString() : new String(new char[] { tcode });
1.547 + try {
1.548 + fields[i] = new ObjectStreamField(fname, signature, false);
1.549 + } catch (RuntimeException e) {
1.550 + throw (IOException) new InvalidClassException(name,
1.551 + "invalid descriptor for field " + fname).initCause(e);
1.552 + }
1.553 + }
1.554 + computeFieldOffsets();
1.555 + }
1.556 +
1.557 + /**
1.558 + * Writes non-proxy class descriptor information to given output stream.
1.559 + */
1.560 + void writeNonProxy(ObjectOutputStream out) throws IOException {
1.561 + out.writeUTF(name);
1.562 + out.writeLong(getSerialVersionUID());
1.563 +
1.564 + byte flags = 0;
1.565 + if (externalizable) {
1.566 + flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
1.567 + int protocol = out.getProtocolVersion();
1.568 + if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
1.569 + flags |= ObjectStreamConstants.SC_BLOCK_DATA;
1.570 + }
1.571 + } else if (serializable) {
1.572 + flags |= ObjectStreamConstants.SC_SERIALIZABLE;
1.573 + }
1.574 + if (hasWriteObjectData) {
1.575 + flags |= ObjectStreamConstants.SC_WRITE_METHOD;
1.576 + }
1.577 + if (isEnum) {
1.578 + flags |= ObjectStreamConstants.SC_ENUM;
1.579 + }
1.580 + out.writeByte(flags);
1.581 +
1.582 + out.writeShort(fields.length);
1.583 + for (int i = 0; i < fields.length; i++) {
1.584 + ObjectStreamField f = fields[i];
1.585 + out.writeByte(f.getTypeCode());
1.586 + out.writeUTF(f.getName());
1.587 + if (!f.isPrimitive()) {
1.588 + out.writeTypeString(f.getTypeString());
1.589 + }
1.590 + }
1.591 + }
1.592 +
1.593 + /**
1.594 + * Returns ClassNotFoundException (if any) thrown while attempting to
1.595 + * resolve local class corresponding to this class descriptor.
1.596 + */
1.597 + ClassNotFoundException getResolveException() {
1.598 + return resolveEx;
1.599 + }
1.600 +
1.601 + /**
1.602 + * Throws an InvalidClassException if object instances referencing this
1.603 + * class descriptor should not be allowed to deserialize. This method does
1.604 + * not apply to deserialization of enum constants.
1.605 + */
1.606 + void checkDeserialize() throws InvalidClassException {
1.607 + if (deserializeEx != null) {
1.608 + InvalidClassException ice =
1.609 + new InvalidClassException(deserializeEx.classname,
1.610 + deserializeEx.getMessage());
1.611 + ice.initCause(deserializeEx);
1.612 + throw ice;
1.613 + }
1.614 + }
1.615 +
1.616 + /**
1.617 + * Throws an InvalidClassException if objects whose class is represented by
1.618 + * this descriptor should not be allowed to serialize. This method does
1.619 + * not apply to serialization of enum constants.
1.620 + */
1.621 + void checkSerialize() throws InvalidClassException {
1.622 + if (serializeEx != null) {
1.623 + InvalidClassException ice =
1.624 + new InvalidClassException(serializeEx.classname,
1.625 + serializeEx.getMessage());
1.626 + ice.initCause(serializeEx);
1.627 + throw ice;
1.628 + }
1.629 + }
1.630 +
1.631 + /**
1.632 + * Throws an InvalidClassException if objects whose class is represented by
1.633 + * this descriptor should not be permitted to use default serialization
1.634 + * (e.g., if the class declares serializable fields that do not correspond
1.635 + * to actual fields, and hence must use the GetField API). This method
1.636 + * does not apply to deserialization of enum constants.
1.637 + */
1.638 + void checkDefaultSerialize() throws InvalidClassException {
1.639 + if (defaultSerializeEx != null) {
1.640 + InvalidClassException ice =
1.641 + new InvalidClassException(defaultSerializeEx.classname,
1.642 + defaultSerializeEx.getMessage());
1.643 + ice.initCause(defaultSerializeEx);
1.644 + throw ice;
1.645 + }
1.646 + }
1.647 +
1.648 + /**
1.649 + * Returns superclass descriptor. Note that on the receiving side, the
1.650 + * superclass descriptor may be bound to a class that is not a superclass
1.651 + * of the subclass descriptor's bound class.
1.652 + */
1.653 + ObjectStreamClass getSuperDesc() {
1.654 + return superDesc;
1.655 + }
1.656 +
1.657 + /**
1.658 + * Returns the "local" class descriptor for the class associated with this
1.659 + * class descriptor (i.e., the result of
1.660 + * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
1.661 + * associated with this descriptor.
1.662 + */
1.663 + ObjectStreamClass getLocalDesc() {
1.664 + return localDesc;
1.665 + }
1.666 +
1.667 + /**
1.668 + * Returns arrays of ObjectStreamFields representing the serializable
1.669 + * fields of the represented class. If copy is true, a clone of this class
1.670 + * descriptor's field array is returned, otherwise the array itself is
1.671 + * returned.
1.672 + */
1.673 + ObjectStreamField[] getFields(boolean copy) {
1.674 + return copy ? fields.clone() : fields;
1.675 + }
1.676 +
1.677 + /**
1.678 + * Looks up a serializable field of the represented class by name and type.
1.679 + * A specified type of null matches all types, Object.class matches all
1.680 + * non-primitive types, and any other non-null type matches assignable
1.681 + * types only. Returns matching field, or null if no match found.
1.682 + */
1.683 + ObjectStreamField getField(String name, Class<?> type) {
1.684 + for (int i = 0; i < fields.length; i++) {
1.685 + ObjectStreamField f = fields[i];
1.686 + if (f.getName().equals(name)) {
1.687 + if (type == null ||
1.688 + (type == Object.class && !f.isPrimitive()))
1.689 + {
1.690 + return f;
1.691 + }
1.692 + Class<?> ftype = f.getType();
1.693 + if (ftype != null && type.isAssignableFrom(ftype)) {
1.694 + return f;
1.695 + }
1.696 + }
1.697 + }
1.698 + return null;
1.699 + }
1.700 +
1.701 + /**
1.702 + * Returns true if class descriptor represents a dynamic proxy class, false
1.703 + * otherwise.
1.704 + */
1.705 + boolean isProxy() {
1.706 + return isProxy;
1.707 + }
1.708 +
1.709 + /**
1.710 + * Returns true if class descriptor represents an enum type, false
1.711 + * otherwise.
1.712 + */
1.713 + boolean isEnum() {
1.714 + return isEnum;
1.715 + }
1.716 +
1.717 + /**
1.718 + * Returns true if represented class implements Externalizable, false
1.719 + * otherwise.
1.720 + */
1.721 + boolean isExternalizable() {
1.722 + return externalizable;
1.723 + }
1.724 +
1.725 + /**
1.726 + * Returns true if represented class implements Serializable, false
1.727 + * otherwise.
1.728 + */
1.729 + boolean isSerializable() {
1.730 + return serializable;
1.731 + }
1.732 +
1.733 + /**
1.734 + * Returns true if class descriptor represents externalizable class that
1.735 + * has written its data in 1.2 (block data) format, false otherwise.
1.736 + */
1.737 + boolean hasBlockExternalData() {
1.738 + return hasBlockExternalData;
1.739 + }
1.740 +
1.741 + /**
1.742 + * Returns true if class descriptor represents serializable (but not
1.743 + * externalizable) class which has written its data via a custom
1.744 + * writeObject() method, false otherwise.
1.745 + */
1.746 + boolean hasWriteObjectData() {
1.747 + return hasWriteObjectData;
1.748 + }
1.749 +
1.750 + /**
1.751 + * Returns true if represented class is serializable/externalizable and can
1.752 + * be instantiated by the serialization runtime--i.e., if it is
1.753 + * externalizable and defines a public no-arg constructor, or if it is
1.754 + * non-externalizable and its first non-serializable superclass defines an
1.755 + * accessible no-arg constructor. Otherwise, returns false.
1.756 + */
1.757 + boolean isInstantiable() {
1.758 + return (cons != null);
1.759 + }
1.760 +
1.761 + /**
1.762 + * Returns true if represented class is serializable (but not
1.763 + * externalizable) and defines a conformant writeObject method. Otherwise,
1.764 + * returns false.
1.765 + */
1.766 + boolean hasWriteObjectMethod() {
1.767 + return (writeObjectMethod != null);
1.768 + }
1.769 +
1.770 + /**
1.771 + * Returns true if represented class is serializable (but not
1.772 + * externalizable) and defines a conformant readObject method. Otherwise,
1.773 + * returns false.
1.774 + */
1.775 + boolean hasReadObjectMethod() {
1.776 + return (readObjectMethod != null);
1.777 + }
1.778 +
1.779 + /**
1.780 + * Returns true if represented class is serializable (but not
1.781 + * externalizable) and defines a conformant readObjectNoData method.
1.782 + * Otherwise, returns false.
1.783 + */
1.784 + boolean hasReadObjectNoDataMethod() {
1.785 + return (readObjectNoDataMethod != null);
1.786 + }
1.787 +
1.788 + /**
1.789 + * Returns true if represented class is serializable or externalizable and
1.790 + * defines a conformant writeReplace method. Otherwise, returns false.
1.791 + */
1.792 + boolean hasWriteReplaceMethod() {
1.793 + return (writeReplaceMethod != null);
1.794 + }
1.795 +
1.796 + /**
1.797 + * Returns true if represented class is serializable or externalizable and
1.798 + * defines a conformant readResolve method. Otherwise, returns false.
1.799 + */
1.800 + boolean hasReadResolveMethod() {
1.801 + return (readResolveMethod != null);
1.802 + }
1.803 +
1.804 + /**
1.805 + * Creates a new instance of the represented class. If the class is
1.806 + * externalizable, invokes its public no-arg constructor; otherwise, if the
1.807 + * class is serializable, invokes the no-arg constructor of the first
1.808 + * non-serializable superclass. Throws UnsupportedOperationException if
1.809 + * this class descriptor is not associated with a class, if the associated
1.810 + * class is non-serializable or if the appropriate no-arg constructor is
1.811 + * inaccessible/unavailable.
1.812 + */
1.813 + Object newInstance()
1.814 + throws InstantiationException, InvocationTargetException,
1.815 + UnsupportedOperationException
1.816 + {
1.817 + if (cons != null) {
1.818 + try {
1.819 + return cons.newInstance();
1.820 + } catch (IllegalAccessException ex) {
1.821 + // should not occur, as access checks have been suppressed
1.822 + throw new InternalError();
1.823 + }
1.824 + } else {
1.825 + throw new UnsupportedOperationException();
1.826 + }
1.827 + }
1.828 +
1.829 + /**
1.830 + * Invokes the writeObject method of the represented serializable class.
1.831 + * Throws UnsupportedOperationException if this class descriptor is not
1.832 + * associated with a class, or if the class is externalizable,
1.833 + * non-serializable or does not define writeObject.
1.834 + */
1.835 + void invokeWriteObject(Object obj, ObjectOutputStream out)
1.836 + throws IOException, UnsupportedOperationException
1.837 + {
1.838 + if (writeObjectMethod != null) {
1.839 + try {
1.840 + writeObjectMethod.invoke(obj, new Object[]{ out });
1.841 + } catch (InvocationTargetException ex) {
1.842 + Throwable th = ex.getTargetException();
1.843 + if (th instanceof IOException) {
1.844 + throw (IOException) th;
1.845 + } else {
1.846 + throwMiscException(th);
1.847 + }
1.848 + } catch (IllegalAccessException ex) {
1.849 + // should not occur, as access checks have been suppressed
1.850 + throw new InternalError();
1.851 + }
1.852 + } else {
1.853 + throw new UnsupportedOperationException();
1.854 + }
1.855 + }
1.856 +
1.857 + /**
1.858 + * Invokes the readObject method of the represented serializable class.
1.859 + * Throws UnsupportedOperationException if this class descriptor is not
1.860 + * associated with a class, or if the class is externalizable,
1.861 + * non-serializable or does not define readObject.
1.862 + */
1.863 + void invokeReadObject(Object obj, ObjectInputStream in)
1.864 + throws ClassNotFoundException, IOException,
1.865 + UnsupportedOperationException
1.866 + {
1.867 + if (readObjectMethod != null) {
1.868 + try {
1.869 + readObjectMethod.invoke(obj, new Object[]{ in });
1.870 + } catch (InvocationTargetException ex) {
1.871 + Throwable th = ex.getTargetException();
1.872 + if (th instanceof ClassNotFoundException) {
1.873 + throw (ClassNotFoundException) th;
1.874 + } else if (th instanceof IOException) {
1.875 + throw (IOException) th;
1.876 + } else {
1.877 + throwMiscException(th);
1.878 + }
1.879 + } catch (IllegalAccessException ex) {
1.880 + // should not occur, as access checks have been suppressed
1.881 + throw new InternalError();
1.882 + }
1.883 + } else {
1.884 + throw new UnsupportedOperationException();
1.885 + }
1.886 + }
1.887 +
1.888 + /**
1.889 + * Invokes the readObjectNoData method of the represented serializable
1.890 + * class. Throws UnsupportedOperationException if this class descriptor is
1.891 + * not associated with a class, or if the class is externalizable,
1.892 + * non-serializable or does not define readObjectNoData.
1.893 + */
1.894 + void invokeReadObjectNoData(Object obj)
1.895 + throws IOException, UnsupportedOperationException
1.896 + {
1.897 + if (readObjectNoDataMethod != null) {
1.898 + try {
1.899 + readObjectNoDataMethod.invoke(obj, (Object[]) null);
1.900 + } catch (InvocationTargetException ex) {
1.901 + Throwable th = ex.getTargetException();
1.902 + if (th instanceof ObjectStreamException) {
1.903 + throw (ObjectStreamException) th;
1.904 + } else {
1.905 + throwMiscException(th);
1.906 + }
1.907 + } catch (IllegalAccessException ex) {
1.908 + // should not occur, as access checks have been suppressed
1.909 + throw new InternalError();
1.910 + }
1.911 + } else {
1.912 + throw new UnsupportedOperationException();
1.913 + }
1.914 + }
1.915 +
1.916 + /**
1.917 + * Invokes the writeReplace method of the represented serializable class and
1.918 + * returns the result. Throws UnsupportedOperationException if this class
1.919 + * descriptor is not associated with a class, or if the class is
1.920 + * non-serializable or does not define writeReplace.
1.921 + */
1.922 + Object invokeWriteReplace(Object obj)
1.923 + throws IOException, UnsupportedOperationException
1.924 + {
1.925 + if (writeReplaceMethod != null) {
1.926 + try {
1.927 + return writeReplaceMethod.invoke(obj, (Object[]) null);
1.928 + } catch (InvocationTargetException ex) {
1.929 + Throwable th = ex.getTargetException();
1.930 + if (th instanceof ObjectStreamException) {
1.931 + throw (ObjectStreamException) th;
1.932 + } else {
1.933 + throwMiscException(th);
1.934 + throw new InternalError(); // never reached
1.935 + }
1.936 + } catch (IllegalAccessException ex) {
1.937 + // should not occur, as access checks have been suppressed
1.938 + throw new InternalError();
1.939 + }
1.940 + } else {
1.941 + throw new UnsupportedOperationException();
1.942 + }
1.943 + }
1.944 +
1.945 + /**
1.946 + * Invokes the readResolve method of the represented serializable class and
1.947 + * returns the result. Throws UnsupportedOperationException if this class
1.948 + * descriptor is not associated with a class, or if the class is
1.949 + * non-serializable or does not define readResolve.
1.950 + */
1.951 + Object invokeReadResolve(Object obj)
1.952 + throws IOException, UnsupportedOperationException
1.953 + {
1.954 + if (readResolveMethod != null) {
1.955 + try {
1.956 + return readResolveMethod.invoke(obj, (Object[]) null);
1.957 + } catch (InvocationTargetException ex) {
1.958 + Throwable th = ex.getTargetException();
1.959 + if (th instanceof ObjectStreamException) {
1.960 + throw (ObjectStreamException) th;
1.961 + } else {
1.962 + throwMiscException(th);
1.963 + throw new InternalError(); // never reached
1.964 + }
1.965 + } catch (IllegalAccessException ex) {
1.966 + // should not occur, as access checks have been suppressed
1.967 + throw new InternalError();
1.968 + }
1.969 + } else {
1.970 + throw new UnsupportedOperationException();
1.971 + }
1.972 + }
1.973 +
1.974 + /**
1.975 + * Class representing the portion of an object's serialized form allotted
1.976 + * to data described by a given class descriptor. If "hasData" is false,
1.977 + * the object's serialized form does not contain data associated with the
1.978 + * class descriptor.
1.979 + */
1.980 + static class ClassDataSlot {
1.981 +
1.982 + /** class descriptor "occupying" this slot */
1.983 + final ObjectStreamClass desc;
1.984 + /** true if serialized form includes data for this slot's descriptor */
1.985 + final boolean hasData;
1.986 +
1.987 + ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
1.988 + this.desc = desc;
1.989 + this.hasData = hasData;
1.990 + }
1.991 + }
1.992 +
1.993 + /**
1.994 + * Returns array of ClassDataSlot instances representing the data layout
1.995 + * (including superclass data) for serialized objects described by this
1.996 + * class descriptor. ClassDataSlots are ordered by inheritance with those
1.997 + * containing "higher" superclasses appearing first. The final
1.998 + * ClassDataSlot contains a reference to this descriptor.
1.999 + */
1.1000 + ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
1.1001 + // REMIND: synchronize instead of relying on volatile?
1.1002 + if (dataLayout == null) {
1.1003 + dataLayout = getClassDataLayout0();
1.1004 + }
1.1005 + return dataLayout;
1.1006 + }
1.1007 +
1.1008 + private ClassDataSlot[] getClassDataLayout0()
1.1009 + throws InvalidClassException
1.1010 + {
1.1011 + ArrayList<ClassDataSlot> slots = new ArrayList<>();
1.1012 + Class<?> start = cl, end = cl;
1.1013 +
1.1014 + // locate closest non-serializable superclass
1.1015 + while (end != null && Serializable.class.isAssignableFrom(end)) {
1.1016 + end = end.getSuperclass();
1.1017 + }
1.1018 +
1.1019 + for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
1.1020 +
1.1021 + // search up inheritance hierarchy for class with matching name
1.1022 + String searchName = (d.cl != null) ? d.cl.getName() : d.name;
1.1023 + Class<?> match = null;
1.1024 + for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1.1025 + if (searchName.equals(c.getName())) {
1.1026 + match = c;
1.1027 + break;
1.1028 + }
1.1029 + }
1.1030 +
1.1031 + // add "no data" slot for each unmatched class below match
1.1032 + if (match != null) {
1.1033 + for (Class<?> c = start; c != match; c = c.getSuperclass()) {
1.1034 + slots.add(new ClassDataSlot(
1.1035 + ObjectStreamClass.lookup(c, true), false));
1.1036 + }
1.1037 + start = match.getSuperclass();
1.1038 + }
1.1039 +
1.1040 + // record descriptor/class pairing
1.1041 + slots.add(new ClassDataSlot(d.getVariantFor(match), true));
1.1042 + }
1.1043 +
1.1044 + // add "no data" slot for any leftover unmatched classes
1.1045 + for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1.1046 + slots.add(new ClassDataSlot(
1.1047 + ObjectStreamClass.lookup(c, true), false));
1.1048 + }
1.1049 +
1.1050 + // order slots from superclass -> subclass
1.1051 + Collections.reverse(slots);
1.1052 + return slots.toArray(new ClassDataSlot[slots.size()]);
1.1053 + }
1.1054 +
1.1055 + /**
1.1056 + * Returns aggregate size (in bytes) of marshalled primitive field values
1.1057 + * for represented class.
1.1058 + */
1.1059 + int getPrimDataSize() {
1.1060 + return primDataSize;
1.1061 + }
1.1062 +
1.1063 + /**
1.1064 + * Returns number of non-primitive serializable fields of represented
1.1065 + * class.
1.1066 + */
1.1067 + int getNumObjFields() {
1.1068 + return numObjFields;
1.1069 + }
1.1070 +
1.1071 + /**
1.1072 + * Fetches the serializable primitive field values of object obj and
1.1073 + * marshals them into byte array buf starting at offset 0. It is the
1.1074 + * responsibility of the caller to ensure that obj is of the proper type if
1.1075 + * non-null.
1.1076 + */
1.1077 + void getPrimFieldValues(Object obj, byte[] buf) {
1.1078 + }
1.1079 +
1.1080 + /**
1.1081 + * Sets the serializable primitive fields of object obj using values
1.1082 + * unmarshalled from byte array buf starting at offset 0. It is the
1.1083 + * responsibility of the caller to ensure that obj is of the proper type if
1.1084 + * non-null.
1.1085 + */
1.1086 + void setPrimFieldValues(Object obj, byte[] buf) {
1.1087 + }
1.1088 +
1.1089 + /**
1.1090 + * Fetches the serializable object field values of object obj and stores
1.1091 + * them in array vals starting at offset 0. It is the responsibility of
1.1092 + * the caller to ensure that obj is of the proper type if non-null.
1.1093 + */
1.1094 + void getObjFieldValues(Object obj, Object[] vals) {
1.1095 + }
1.1096 +
1.1097 + /**
1.1098 + * Sets the serializable object fields of object obj using values from
1.1099 + * array vals starting at offset 0. It is the responsibility of the caller
1.1100 + * to ensure that obj is of the proper type if non-null.
1.1101 + */
1.1102 + void setObjFieldValues(Object obj, Object[] vals) {
1.1103 + }
1.1104 +
1.1105 + /**
1.1106 + * Calculates and sets serializable field offsets, as well as primitive
1.1107 + * data size and object field count totals. Throws InvalidClassException
1.1108 + * if fields are illegally ordered.
1.1109 + */
1.1110 + private void computeFieldOffsets() throws InvalidClassException {
1.1111 + primDataSize = 0;
1.1112 + numObjFields = 0;
1.1113 + int firstObjIndex = -1;
1.1114 +
1.1115 + for (int i = 0; i < fields.length; i++) {
1.1116 + ObjectStreamField f = fields[i];
1.1117 + switch (f.getTypeCode()) {
1.1118 + case 'Z':
1.1119 + case 'B':
1.1120 + f.setOffset(primDataSize++);
1.1121 + break;
1.1122 +
1.1123 + case 'C':
1.1124 + case 'S':
1.1125 + f.setOffset(primDataSize);
1.1126 + primDataSize += 2;
1.1127 + break;
1.1128 +
1.1129 + case 'I':
1.1130 + case 'F':
1.1131 + f.setOffset(primDataSize);
1.1132 + primDataSize += 4;
1.1133 + break;
1.1134 +
1.1135 + case 'J':
1.1136 + case 'D':
1.1137 + f.setOffset(primDataSize);
1.1138 + primDataSize += 8;
1.1139 + break;
1.1140 +
1.1141 + case '[':
1.1142 + case 'L':
1.1143 + f.setOffset(numObjFields++);
1.1144 + if (firstObjIndex == -1) {
1.1145 + firstObjIndex = i;
1.1146 + }
1.1147 + break;
1.1148 +
1.1149 + default:
1.1150 + throw new InternalError();
1.1151 + }
1.1152 + }
1.1153 + if (firstObjIndex != -1 &&
1.1154 + firstObjIndex + numObjFields != fields.length)
1.1155 + {
1.1156 + throw new InvalidClassException(name, "illegal field order");
1.1157 + }
1.1158 + }
1.1159 +
1.1160 + /**
1.1161 + * If given class is the same as the class associated with this class
1.1162 + * descriptor, returns reference to this class descriptor. Otherwise,
1.1163 + * returns variant of this class descriptor bound to given class.
1.1164 + */
1.1165 + private ObjectStreamClass getVariantFor(Class<?> cl)
1.1166 + throws InvalidClassException
1.1167 + {
1.1168 + if (this.cl == cl) {
1.1169 + return this;
1.1170 + }
1.1171 + ObjectStreamClass desc = new ObjectStreamClass();
1.1172 + if (isProxy) {
1.1173 + desc.initProxy(cl, null, superDesc);
1.1174 + } else {
1.1175 + desc.initNonProxy(this, cl, null, superDesc);
1.1176 + }
1.1177 + return desc;
1.1178 + }
1.1179 +
1.1180 + /**
1.1181 + * Returns public no-arg constructor of given class, or null if none found.
1.1182 + * Access checks are disabled on the returned constructor (if any), since
1.1183 + * the defining class may still be non-public.
1.1184 + */
1.1185 + private static Constructor getExternalizableConstructor(Class<?> cl) {
1.1186 + throw new SecurityException();
1.1187 + }
1.1188 +
1.1189 + /**
1.1190 + * Returns subclass-accessible no-arg constructor of first non-serializable
1.1191 + * superclass, or null if none found. Access checks are disabled on the
1.1192 + * returned constructor (if any).
1.1193 + */
1.1194 + private static Constructor getSerializableConstructor(Class<?> cl) {
1.1195 + Class<?> initCl = cl;
1.1196 + while (Serializable.class.isAssignableFrom(initCl)) {
1.1197 + if ((initCl = initCl.getSuperclass()) == null) {
1.1198 + return null;
1.1199 + }
1.1200 + }
1.1201 + throw new SecurityException();
1.1202 + }
1.1203 +
1.1204 + /**
1.1205 + * Returns non-static, non-abstract method with given signature provided it
1.1206 + * is defined by or accessible (via inheritance) by the given class, or
1.1207 + * null if no match found. Access checks are disabled on the returned
1.1208 + * method (if any).
1.1209 + */
1.1210 + private static Method getInheritableMethod(Class<?> cl, String name,
1.1211 + Class<?>[] argTypes,
1.1212 + Class<?> returnType)
1.1213 + {
1.1214 + throw new SecurityException();
1.1215 + }
1.1216 +
1.1217 + /**
1.1218 + * Returns non-static private method with given signature defined by given
1.1219 + * class, or null if none found. Access checks are disabled on the
1.1220 + * returned method (if any).
1.1221 + */
1.1222 + private static Method getPrivateMethod(Class<?> cl, String name,
1.1223 + Class<?>[] argTypes,
1.1224 + Class<?> returnType)
1.1225 + {
1.1226 + throw new SecurityException();
1.1227 + }
1.1228 +
1.1229 + /**
1.1230 + * Returns true if classes are defined in the same runtime package, false
1.1231 + * otherwise.
1.1232 + */
1.1233 + private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
1.1234 + return (cl1.getClassLoader() == cl2.getClassLoader() &&
1.1235 + getPackageName(cl1).equals(getPackageName(cl2)));
1.1236 + }
1.1237 +
1.1238 + /**
1.1239 + * Returns package name of given class.
1.1240 + */
1.1241 + private static String getPackageName(Class<?> cl) {
1.1242 + String s = cl.getName();
1.1243 + int i = s.lastIndexOf('[');
1.1244 + if (i >= 0) {
1.1245 + s = s.substring(i + 2);
1.1246 + }
1.1247 + i = s.lastIndexOf('.');
1.1248 + return (i >= 0) ? s.substring(0, i) : "";
1.1249 + }
1.1250 +
1.1251 + /**
1.1252 + * Compares class names for equality, ignoring package names. Returns true
1.1253 + * if class names equal, false otherwise.
1.1254 + */
1.1255 + private static boolean classNamesEqual(String name1, String name2) {
1.1256 + name1 = name1.substring(name1.lastIndexOf('.') + 1);
1.1257 + name2 = name2.substring(name2.lastIndexOf('.') + 1);
1.1258 + return name1.equals(name2);
1.1259 + }
1.1260 +
1.1261 + /**
1.1262 + * Returns JVM type signature for given class.
1.1263 + */
1.1264 + private static String getClassSignature(Class<?> cl) {
1.1265 + StringBuilder sbuf = new StringBuilder();
1.1266 + while (cl.isArray()) {
1.1267 + sbuf.append('[');
1.1268 + cl = cl.getComponentType();
1.1269 + }
1.1270 + if (cl.isPrimitive()) {
1.1271 + if (cl == Integer.TYPE) {
1.1272 + sbuf.append('I');
1.1273 + } else if (cl == Byte.TYPE) {
1.1274 + sbuf.append('B');
1.1275 + } else if (cl == Long.TYPE) {
1.1276 + sbuf.append('J');
1.1277 + } else if (cl == Float.TYPE) {
1.1278 + sbuf.append('F');
1.1279 + } else if (cl == Double.TYPE) {
1.1280 + sbuf.append('D');
1.1281 + } else if (cl == Short.TYPE) {
1.1282 + sbuf.append('S');
1.1283 + } else if (cl == Character.TYPE) {
1.1284 + sbuf.append('C');
1.1285 + } else if (cl == Boolean.TYPE) {
1.1286 + sbuf.append('Z');
1.1287 + } else if (cl == Void.TYPE) {
1.1288 + sbuf.append('V');
1.1289 + } else {
1.1290 + throw new InternalError();
1.1291 + }
1.1292 + } else {
1.1293 + sbuf.append('L' + cl.getName().replace('.', '/') + ';');
1.1294 + }
1.1295 + return sbuf.toString();
1.1296 + }
1.1297 +
1.1298 + /**
1.1299 + * Returns JVM type signature for given list of parameters and return type.
1.1300 + */
1.1301 + private static String getMethodSignature(Class<?>[] paramTypes,
1.1302 + Class<?> retType)
1.1303 + {
1.1304 + StringBuilder sbuf = new StringBuilder();
1.1305 + sbuf.append('(');
1.1306 + for (int i = 0; i < paramTypes.length; i++) {
1.1307 + sbuf.append(getClassSignature(paramTypes[i]));
1.1308 + }
1.1309 + sbuf.append(')');
1.1310 + sbuf.append(getClassSignature(retType));
1.1311 + return sbuf.toString();
1.1312 + }
1.1313 +
1.1314 + /**
1.1315 + * Convenience method for throwing an exception that is either a
1.1316 + * RuntimeException, Error, or of some unexpected type (in which case it is
1.1317 + * wrapped inside an IOException).
1.1318 + */
1.1319 + private static void throwMiscException(Throwable th) throws IOException {
1.1320 + if (th instanceof RuntimeException) {
1.1321 + throw (RuntimeException) th;
1.1322 + } else if (th instanceof Error) {
1.1323 + throw (Error) th;
1.1324 + } else {
1.1325 + IOException ex = new IOException("unexpected exception type");
1.1326 + ex.initCause(th);
1.1327 + throw ex;
1.1328 + }
1.1329 + }
1.1330 +
1.1331 + /**
1.1332 + * Returns ObjectStreamField array describing the serializable fields of
1.1333 + * the given class. Serializable fields backed by an actual field of the
1.1334 + * class are represented by ObjectStreamFields with corresponding non-null
1.1335 + * Field objects. Throws InvalidClassException if the (explicitly
1.1336 + * declared) serializable fields are invalid.
1.1337 + */
1.1338 + private static ObjectStreamField[] getSerialFields(Class<?> cl)
1.1339 + throws InvalidClassException
1.1340 + {
1.1341 + ObjectStreamField[] fields;
1.1342 + if (Serializable.class.isAssignableFrom(cl) &&
1.1343 + !Externalizable.class.isAssignableFrom(cl) &&
1.1344 + !Proxy.isProxyClass(cl) &&
1.1345 + !cl.isInterface())
1.1346 + {
1.1347 + if ((fields = getDeclaredSerialFields(cl)) == null) {
1.1348 + fields = getDefaultSerialFields(cl);
1.1349 + }
1.1350 + Arrays.sort(fields);
1.1351 + } else {
1.1352 + fields = NO_FIELDS;
1.1353 + }
1.1354 + return fields;
1.1355 + }
1.1356 +
1.1357 + /**
1.1358 + * Returns serializable fields of given class as defined explicitly by a
1.1359 + * "serialPersistentFields" field, or null if no appropriate
1.1360 + * "serialPersistentFields" field is defined. Serializable fields backed
1.1361 + * by an actual field of the class are represented by ObjectStreamFields
1.1362 + * with corresponding non-null Field objects. For compatibility with past
1.1363 + * releases, a "serialPersistentFields" field with a null value is
1.1364 + * considered equivalent to not declaring "serialPersistentFields". Throws
1.1365 + * InvalidClassException if the declared serializable fields are
1.1366 + * invalid--e.g., if multiple fields share the same name.
1.1367 + */
1.1368 + private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
1.1369 + throws InvalidClassException
1.1370 + {
1.1371 + throw new SecurityException();
1.1372 + }
1.1373 +
1.1374 + /**
1.1375 + * Returns array of ObjectStreamFields corresponding to all non-static
1.1376 + * non-transient fields declared by given class. Each ObjectStreamField
1.1377 + * contains a Field object for the field it represents. If no default
1.1378 + * serializable fields exist, NO_FIELDS is returned.
1.1379 + */
1.1380 + private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
1.1381 + throw new SecurityException();
1.1382 + }
1.1383 +
1.1384 + /**
1.1385 + * Returns explicit serial version UID value declared by given class, or
1.1386 + * null if none.
1.1387 + */
1.1388 + private static Long getDeclaredSUID(Class<?> cl) {
1.1389 + return null;
1.1390 + }
1.1391 +
1.1392 + /**
1.1393 + * Computes the default serial version UID value for the given class.
1.1394 + */
1.1395 + private static long computeDefaultSUID(Class<?> cl) {
1.1396 + throw new SecurityException();
1.1397 + }
1.1398 +
1.1399 +}