1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/emul/compact/src/main/java/java/io/ObjectStreamClass.java Mon Jan 28 18:12:47 2013 +0100
1.3 @@ -0,0 +1,2304 @@
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.security.AccessController;
1.43 +import java.security.MessageDigest;
1.44 +import java.security.NoSuchAlgorithmException;
1.45 +import java.security.PrivilegedAction;
1.46 +import java.util.ArrayList;
1.47 +import java.util.Arrays;
1.48 +import java.util.Collections;
1.49 +import java.util.Comparator;
1.50 +import java.util.HashSet;
1.51 +import java.util.Set;
1.52 +import java.util.concurrent.ConcurrentHashMap;
1.53 +import java.util.concurrent.ConcurrentMap;
1.54 +import sun.misc.Unsafe;
1.55 +import sun.reflect.ReflectionFactory;
1.56 +
1.57 +/**
1.58 + * Serialization's descriptor for classes. It contains the name and
1.59 + * serialVersionUID of the class. The ObjectStreamClass for a specific class
1.60 + * loaded in this Java VM can be found/created using the lookup method.
1.61 + *
1.62 + * <p>The algorithm to compute the SerialVersionUID is described in
1.63 + * <a href="../../../platform/serialization/spec/class.html#4100">Object
1.64 + * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
1.65 + *
1.66 + * @author Mike Warres
1.67 + * @author Roger Riggs
1.68 + * @see ObjectStreamField
1.69 + * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
1.70 + * @since JDK1.1
1.71 + */
1.72 +public class ObjectStreamClass implements Serializable {
1.73 +
1.74 + /** serialPersistentFields value indicating no serializable fields */
1.75 + public static final ObjectStreamField[] NO_FIELDS =
1.76 + new ObjectStreamField[0];
1.77 +
1.78 + private static final long serialVersionUID = -6120832682080437368L;
1.79 + private static final ObjectStreamField[] serialPersistentFields =
1.80 + NO_FIELDS;
1.81 +
1.82 + /** reflection factory for obtaining serialization constructors */
1.83 + private static final ReflectionFactory reflFactory =
1.84 + AccessController.doPrivileged(
1.85 + new ReflectionFactory.GetReflectionFactoryAction());
1.86 +
1.87 + private static class Caches {
1.88 + /** cache mapping local classes -> descriptors */
1.89 + static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs =
1.90 + new ConcurrentHashMap<>();
1.91 +
1.92 + /** cache mapping field group/local desc pairs -> field reflectors */
1.93 + static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors =
1.94 + new ConcurrentHashMap<>();
1.95 +
1.96 + /** queue for WeakReferences to local classes */
1.97 + private static final ReferenceQueue<Class<?>> localDescsQueue =
1.98 + new ReferenceQueue<>();
1.99 + /** queue for WeakReferences to field reflectors keys */
1.100 + private static final ReferenceQueue<Class<?>> reflectorsQueue =
1.101 + new ReferenceQueue<>();
1.102 + }
1.103 +
1.104 + /** class associated with this descriptor (if any) */
1.105 + private Class<?> cl;
1.106 + /** name of class represented by this descriptor */
1.107 + private String name;
1.108 + /** serialVersionUID of represented class (null if not computed yet) */
1.109 + private volatile Long suid;
1.110 +
1.111 + /** true if represents dynamic proxy class */
1.112 + private boolean isProxy;
1.113 + /** true if represents enum type */
1.114 + private boolean isEnum;
1.115 + /** true if represented class implements Serializable */
1.116 + private boolean serializable;
1.117 + /** true if represented class implements Externalizable */
1.118 + private boolean externalizable;
1.119 + /** true if desc has data written by class-defined writeObject method */
1.120 + private boolean hasWriteObjectData;
1.121 + /**
1.122 + * true if desc has externalizable data written in block data format; this
1.123 + * must be true by default to accommodate ObjectInputStream subclasses which
1.124 + * override readClassDescriptor() to return class descriptors obtained from
1.125 + * ObjectStreamClass.lookup() (see 4461737)
1.126 + */
1.127 + private boolean hasBlockExternalData = true;
1.128 +
1.129 + /** exception (if any) thrown while attempting to resolve class */
1.130 + private ClassNotFoundException resolveEx;
1.131 + /** exception (if any) to throw if non-enum deserialization attempted */
1.132 + private InvalidClassException deserializeEx;
1.133 + /** exception (if any) to throw if non-enum serialization attempted */
1.134 + private InvalidClassException serializeEx;
1.135 + /** exception (if any) to throw if default serialization attempted */
1.136 + private InvalidClassException defaultSerializeEx;
1.137 +
1.138 + /** serializable fields */
1.139 + private ObjectStreamField[] fields;
1.140 + /** aggregate marshalled size of primitive fields */
1.141 + private int primDataSize;
1.142 + /** number of non-primitive fields */
1.143 + private int numObjFields;
1.144 + /** reflector for setting/getting serializable field values */
1.145 + private FieldReflector fieldRefl;
1.146 + /** data layout of serialized objects described by this class desc */
1.147 + private volatile ClassDataSlot[] dataLayout;
1.148 +
1.149 + /** serialization-appropriate constructor, or null if none */
1.150 + private Constructor cons;
1.151 + /** class-defined writeObject method, or null if none */
1.152 + private Method writeObjectMethod;
1.153 + /** class-defined readObject method, or null if none */
1.154 + private Method readObjectMethod;
1.155 + /** class-defined readObjectNoData method, or null if none */
1.156 + private Method readObjectNoDataMethod;
1.157 + /** class-defined writeReplace method, or null if none */
1.158 + private Method writeReplaceMethod;
1.159 + /** class-defined readResolve method, or null if none */
1.160 + private Method readResolveMethod;
1.161 +
1.162 + /** local class descriptor for represented class (may point to self) */
1.163 + private ObjectStreamClass localDesc;
1.164 + /** superclass descriptor appearing in stream */
1.165 + private ObjectStreamClass superDesc;
1.166 +
1.167 + /**
1.168 + * Initializes native code.
1.169 + */
1.170 + private static native void initNative();
1.171 + static {
1.172 + initNative();
1.173 + }
1.174 +
1.175 + /**
1.176 + * Find the descriptor for a class that can be serialized. Creates an
1.177 + * ObjectStreamClass instance if one does not exist yet for class. Null is
1.178 + * returned if the specified class does not implement java.io.Serializable
1.179 + * or java.io.Externalizable.
1.180 + *
1.181 + * @param cl class for which to get the descriptor
1.182 + * @return the class descriptor for the specified class
1.183 + */
1.184 + public static ObjectStreamClass lookup(Class<?> cl) {
1.185 + return lookup(cl, false);
1.186 + }
1.187 +
1.188 + /**
1.189 + * Returns the descriptor for any class, regardless of whether it
1.190 + * implements {@link Serializable}.
1.191 + *
1.192 + * @param cl class for which to get the descriptor
1.193 + * @return the class descriptor for the specified class
1.194 + * @since 1.6
1.195 + */
1.196 + public static ObjectStreamClass lookupAny(Class<?> cl) {
1.197 + return lookup(cl, true);
1.198 + }
1.199 +
1.200 + /**
1.201 + * Returns the name of the class described by this descriptor.
1.202 + * This method returns the name of the class in the format that
1.203 + * is used by the {@link Class#getName} method.
1.204 + *
1.205 + * @return a string representing the name of the class
1.206 + */
1.207 + public String getName() {
1.208 + return name;
1.209 + }
1.210 +
1.211 + /**
1.212 + * Return the serialVersionUID for this class. The serialVersionUID
1.213 + * defines a set of classes all with the same name that have evolved from a
1.214 + * common root class and agree to be serialized and deserialized using a
1.215 + * common format. NonSerializable classes have a serialVersionUID of 0L.
1.216 + *
1.217 + * @return the SUID of the class described by this descriptor
1.218 + */
1.219 + public long getSerialVersionUID() {
1.220 + // REMIND: synchronize instead of relying on volatile?
1.221 + if (suid == null) {
1.222 + suid = AccessController.doPrivileged(
1.223 + new PrivilegedAction<Long>() {
1.224 + public Long run() {
1.225 + return computeDefaultSUID(cl);
1.226 + }
1.227 + }
1.228 + );
1.229 + }
1.230 + return suid.longValue();
1.231 + }
1.232 +
1.233 + /**
1.234 + * Return the class in the local VM that this version is mapped to. Null
1.235 + * is returned if there is no corresponding local class.
1.236 + *
1.237 + * @return the <code>Class</code> instance that this descriptor represents
1.238 + */
1.239 + public Class<?> forClass() {
1.240 + return cl;
1.241 + }
1.242 +
1.243 + /**
1.244 + * Return an array of the fields of this serializable class.
1.245 + *
1.246 + * @return an array containing an element for each persistent field of
1.247 + * this class. Returns an array of length zero if there are no
1.248 + * fields.
1.249 + * @since 1.2
1.250 + */
1.251 + public ObjectStreamField[] getFields() {
1.252 + return getFields(true);
1.253 + }
1.254 +
1.255 + /**
1.256 + * Get the field of this class by name.
1.257 + *
1.258 + * @param name the name of the data field to look for
1.259 + * @return The ObjectStreamField object of the named field or null if
1.260 + * there is no such named field.
1.261 + */
1.262 + public ObjectStreamField getField(String name) {
1.263 + return getField(name, null);
1.264 + }
1.265 +
1.266 + /**
1.267 + * Return a string describing this ObjectStreamClass.
1.268 + */
1.269 + public String toString() {
1.270 + return name + ": static final long serialVersionUID = " +
1.271 + getSerialVersionUID() + "L;";
1.272 + }
1.273 +
1.274 + /**
1.275 + * Looks up and returns class descriptor for given class, or null if class
1.276 + * is non-serializable and "all" is set to false.
1.277 + *
1.278 + * @param cl class to look up
1.279 + * @param all if true, return descriptors for all classes; if false, only
1.280 + * return descriptors for serializable classes
1.281 + */
1.282 + static ObjectStreamClass lookup(Class<?> cl, boolean all) {
1.283 + if (!(all || Serializable.class.isAssignableFrom(cl))) {
1.284 + return null;
1.285 + }
1.286 + processQueue(Caches.localDescsQueue, Caches.localDescs);
1.287 + WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
1.288 + Reference<?> ref = Caches.localDescs.get(key);
1.289 + Object entry = null;
1.290 + if (ref != null) {
1.291 + entry = ref.get();
1.292 + }
1.293 + EntryFuture future = null;
1.294 + if (entry == null) {
1.295 + EntryFuture newEntry = new EntryFuture();
1.296 + Reference<?> newRef = new SoftReference<>(newEntry);
1.297 + do {
1.298 + if (ref != null) {
1.299 + Caches.localDescs.remove(key, ref);
1.300 + }
1.301 + ref = Caches.localDescs.putIfAbsent(key, newRef);
1.302 + if (ref != null) {
1.303 + entry = ref.get();
1.304 + }
1.305 + } while (ref != null && entry == null);
1.306 + if (entry == null) {
1.307 + future = newEntry;
1.308 + }
1.309 + }
1.310 +
1.311 + if (entry instanceof ObjectStreamClass) { // check common case first
1.312 + return (ObjectStreamClass) entry;
1.313 + }
1.314 + if (entry instanceof EntryFuture) {
1.315 + future = (EntryFuture) entry;
1.316 + if (future.getOwner() == Thread.currentThread()) {
1.317 + /*
1.318 + * Handle nested call situation described by 4803747: waiting
1.319 + * for future value to be set by a lookup() call further up the
1.320 + * stack will result in deadlock, so calculate and set the
1.321 + * future value here instead.
1.322 + */
1.323 + entry = null;
1.324 + } else {
1.325 + entry = future.get();
1.326 + }
1.327 + }
1.328 + if (entry == null) {
1.329 + try {
1.330 + entry = new ObjectStreamClass(cl);
1.331 + } catch (Throwable th) {
1.332 + entry = th;
1.333 + }
1.334 + if (future.set(entry)) {
1.335 + Caches.localDescs.put(key, new SoftReference<Object>(entry));
1.336 + } else {
1.337 + // nested lookup call already set future
1.338 + entry = future.get();
1.339 + }
1.340 + }
1.341 +
1.342 + if (entry instanceof ObjectStreamClass) {
1.343 + return (ObjectStreamClass) entry;
1.344 + } else if (entry instanceof RuntimeException) {
1.345 + throw (RuntimeException) entry;
1.346 + } else if (entry instanceof Error) {
1.347 + throw (Error) entry;
1.348 + } else {
1.349 + throw new InternalError("unexpected entry: " + entry);
1.350 + }
1.351 + }
1.352 +
1.353 + /**
1.354 + * Placeholder used in class descriptor and field reflector lookup tables
1.355 + * for an entry in the process of being initialized. (Internal) callers
1.356 + * which receive an EntryFuture belonging to another thread as the result
1.357 + * of a lookup should call the get() method of the EntryFuture; this will
1.358 + * return the actual entry once it is ready for use and has been set(). To
1.359 + * conserve objects, EntryFutures synchronize on themselves.
1.360 + */
1.361 + private static class EntryFuture {
1.362 +
1.363 + private static final Object unset = new Object();
1.364 + private final Thread owner = Thread.currentThread();
1.365 + private Object entry = unset;
1.366 +
1.367 + /**
1.368 + * Attempts to set the value contained by this EntryFuture. If the
1.369 + * EntryFuture's value has not been set already, then the value is
1.370 + * saved, any callers blocked in the get() method are notified, and
1.371 + * true is returned. If the value has already been set, then no saving
1.372 + * or notification occurs, and false is returned.
1.373 + */
1.374 + synchronized boolean set(Object entry) {
1.375 + if (this.entry != unset) {
1.376 + return false;
1.377 + }
1.378 + this.entry = entry;
1.379 + notifyAll();
1.380 + return true;
1.381 + }
1.382 +
1.383 + /**
1.384 + * Returns the value contained by this EntryFuture, blocking if
1.385 + * necessary until a value is set.
1.386 + */
1.387 + synchronized Object get() {
1.388 + boolean interrupted = false;
1.389 + while (entry == unset) {
1.390 + try {
1.391 + wait();
1.392 + } catch (InterruptedException ex) {
1.393 + interrupted = true;
1.394 + }
1.395 + }
1.396 + if (interrupted) {
1.397 + AccessController.doPrivileged(
1.398 + new PrivilegedAction<Void>() {
1.399 + public Void run() {
1.400 + Thread.currentThread().interrupt();
1.401 + return null;
1.402 + }
1.403 + }
1.404 + );
1.405 + }
1.406 + return entry;
1.407 + }
1.408 +
1.409 + /**
1.410 + * Returns the thread that created this EntryFuture.
1.411 + */
1.412 + Thread getOwner() {
1.413 + return owner;
1.414 + }
1.415 + }
1.416 +
1.417 + /**
1.418 + * Creates local class descriptor representing given class.
1.419 + */
1.420 + private ObjectStreamClass(final Class<?> cl) {
1.421 + this.cl = cl;
1.422 + name = cl.getName();
1.423 + isProxy = Proxy.isProxyClass(cl);
1.424 + isEnum = Enum.class.isAssignableFrom(cl);
1.425 + serializable = Serializable.class.isAssignableFrom(cl);
1.426 + externalizable = Externalizable.class.isAssignableFrom(cl);
1.427 +
1.428 + Class<?> superCl = cl.getSuperclass();
1.429 + superDesc = (superCl != null) ? lookup(superCl, false) : null;
1.430 + localDesc = this;
1.431 +
1.432 + if (serializable) {
1.433 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
1.434 + public Void run() {
1.435 + if (isEnum) {
1.436 + suid = Long.valueOf(0);
1.437 + fields = NO_FIELDS;
1.438 + return null;
1.439 + }
1.440 + if (cl.isArray()) {
1.441 + fields = NO_FIELDS;
1.442 + return null;
1.443 + }
1.444 +
1.445 + suid = getDeclaredSUID(cl);
1.446 + try {
1.447 + fields = getSerialFields(cl);
1.448 + computeFieldOffsets();
1.449 + } catch (InvalidClassException e) {
1.450 + serializeEx = deserializeEx = e;
1.451 + fields = NO_FIELDS;
1.452 + }
1.453 +
1.454 + if (externalizable) {
1.455 + cons = getExternalizableConstructor(cl);
1.456 + } else {
1.457 + cons = getSerializableConstructor(cl);
1.458 + writeObjectMethod = getPrivateMethod(cl, "writeObject",
1.459 + new Class<?>[] { ObjectOutputStream.class },
1.460 + Void.TYPE);
1.461 + readObjectMethod = getPrivateMethod(cl, "readObject",
1.462 + new Class<?>[] { ObjectInputStream.class },
1.463 + Void.TYPE);
1.464 + readObjectNoDataMethod = getPrivateMethod(
1.465 + cl, "readObjectNoData", null, Void.TYPE);
1.466 + hasWriteObjectData = (writeObjectMethod != null);
1.467 + }
1.468 + writeReplaceMethod = getInheritableMethod(
1.469 + cl, "writeReplace", null, Object.class);
1.470 + readResolveMethod = getInheritableMethod(
1.471 + cl, "readResolve", null, Object.class);
1.472 + return null;
1.473 + }
1.474 + });
1.475 + } else {
1.476 + suid = Long.valueOf(0);
1.477 + fields = NO_FIELDS;
1.478 + }
1.479 +
1.480 + try {
1.481 + fieldRefl = getReflector(fields, this);
1.482 + } catch (InvalidClassException ex) {
1.483 + // field mismatches impossible when matching local fields vs. self
1.484 + throw new InternalError();
1.485 + }
1.486 +
1.487 + if (deserializeEx == null) {
1.488 + if (isEnum) {
1.489 + deserializeEx = new InvalidClassException(name, "enum type");
1.490 + } else if (cons == null) {
1.491 + deserializeEx = new InvalidClassException(
1.492 + name, "no valid constructor");
1.493 + }
1.494 + }
1.495 + for (int i = 0; i < fields.length; i++) {
1.496 + if (fields[i].getField() == null) {
1.497 + defaultSerializeEx = new InvalidClassException(
1.498 + name, "unmatched serializable field(s) declared");
1.499 + }
1.500 + }
1.501 + }
1.502 +
1.503 + /**
1.504 + * Creates blank class descriptor which should be initialized via a
1.505 + * subsequent call to initProxy(), initNonProxy() or readNonProxy().
1.506 + */
1.507 + ObjectStreamClass() {
1.508 + }
1.509 +
1.510 + /**
1.511 + * Initializes class descriptor representing a proxy class.
1.512 + */
1.513 + void initProxy(Class<?> cl,
1.514 + ClassNotFoundException resolveEx,
1.515 + ObjectStreamClass superDesc)
1.516 + throws InvalidClassException
1.517 + {
1.518 + this.cl = cl;
1.519 + this.resolveEx = resolveEx;
1.520 + this.superDesc = superDesc;
1.521 + isProxy = true;
1.522 + serializable = true;
1.523 + suid = Long.valueOf(0);
1.524 + fields = NO_FIELDS;
1.525 +
1.526 + if (cl != null) {
1.527 + localDesc = lookup(cl, true);
1.528 + if (!localDesc.isProxy) {
1.529 + throw new InvalidClassException(
1.530 + "cannot bind proxy descriptor to a non-proxy class");
1.531 + }
1.532 + name = localDesc.name;
1.533 + externalizable = localDesc.externalizable;
1.534 + cons = localDesc.cons;
1.535 + writeReplaceMethod = localDesc.writeReplaceMethod;
1.536 + readResolveMethod = localDesc.readResolveMethod;
1.537 + deserializeEx = localDesc.deserializeEx;
1.538 + }
1.539 + fieldRefl = getReflector(fields, localDesc);
1.540 + }
1.541 +
1.542 + /**
1.543 + * Initializes class descriptor representing a non-proxy class.
1.544 + */
1.545 + void initNonProxy(ObjectStreamClass model,
1.546 + Class<?> cl,
1.547 + ClassNotFoundException resolveEx,
1.548 + ObjectStreamClass superDesc)
1.549 + throws InvalidClassException
1.550 + {
1.551 + this.cl = cl;
1.552 + this.resolveEx = resolveEx;
1.553 + this.superDesc = superDesc;
1.554 + name = model.name;
1.555 + suid = Long.valueOf(model.getSerialVersionUID());
1.556 + isProxy = false;
1.557 + isEnum = model.isEnum;
1.558 + serializable = model.serializable;
1.559 + externalizable = model.externalizable;
1.560 + hasBlockExternalData = model.hasBlockExternalData;
1.561 + hasWriteObjectData = model.hasWriteObjectData;
1.562 + fields = model.fields;
1.563 + primDataSize = model.primDataSize;
1.564 + numObjFields = model.numObjFields;
1.565 +
1.566 + if (cl != null) {
1.567 + localDesc = lookup(cl, true);
1.568 + if (localDesc.isProxy) {
1.569 + throw new InvalidClassException(
1.570 + "cannot bind non-proxy descriptor to a proxy class");
1.571 + }
1.572 + if (isEnum != localDesc.isEnum) {
1.573 + throw new InvalidClassException(isEnum ?
1.574 + "cannot bind enum descriptor to a non-enum class" :
1.575 + "cannot bind non-enum descriptor to an enum class");
1.576 + }
1.577 +
1.578 + if (serializable == localDesc.serializable &&
1.579 + !cl.isArray() &&
1.580 + suid.longValue() != localDesc.getSerialVersionUID())
1.581 + {
1.582 + throw new InvalidClassException(localDesc.name,
1.583 + "local class incompatible: " +
1.584 + "stream classdesc serialVersionUID = " + suid +
1.585 + ", local class serialVersionUID = " +
1.586 + localDesc.getSerialVersionUID());
1.587 + }
1.588 +
1.589 + if (!classNamesEqual(name, localDesc.name)) {
1.590 + throw new InvalidClassException(localDesc.name,
1.591 + "local class name incompatible with stream class " +
1.592 + "name \"" + name + "\"");
1.593 + }
1.594 +
1.595 + if (!isEnum) {
1.596 + if ((serializable == localDesc.serializable) &&
1.597 + (externalizable != localDesc.externalizable))
1.598 + {
1.599 + throw new InvalidClassException(localDesc.name,
1.600 + "Serializable incompatible with Externalizable");
1.601 + }
1.602 +
1.603 + if ((serializable != localDesc.serializable) ||
1.604 + (externalizable != localDesc.externalizable) ||
1.605 + !(serializable || externalizable))
1.606 + {
1.607 + deserializeEx = new InvalidClassException(localDesc.name,
1.608 + "class invalid for deserialization");
1.609 + }
1.610 + }
1.611 +
1.612 + cons = localDesc.cons;
1.613 + writeObjectMethod = localDesc.writeObjectMethod;
1.614 + readObjectMethod = localDesc.readObjectMethod;
1.615 + readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
1.616 + writeReplaceMethod = localDesc.writeReplaceMethod;
1.617 + readResolveMethod = localDesc.readResolveMethod;
1.618 + if (deserializeEx == null) {
1.619 + deserializeEx = localDesc.deserializeEx;
1.620 + }
1.621 + }
1.622 + fieldRefl = getReflector(fields, localDesc);
1.623 + // reassign to matched fields so as to reflect local unshared settings
1.624 + fields = fieldRefl.getFields();
1.625 + }
1.626 +
1.627 + /**
1.628 + * Reads non-proxy class descriptor information from given input stream.
1.629 + * The resulting class descriptor is not fully functional; it can only be
1.630 + * used as input to the ObjectInputStream.resolveClass() and
1.631 + * ObjectStreamClass.initNonProxy() methods.
1.632 + */
1.633 + void readNonProxy(ObjectInputStream in)
1.634 + throws IOException, ClassNotFoundException
1.635 + {
1.636 + name = in.readUTF();
1.637 + suid = Long.valueOf(in.readLong());
1.638 + isProxy = false;
1.639 +
1.640 + byte flags = in.readByte();
1.641 + hasWriteObjectData =
1.642 + ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
1.643 + hasBlockExternalData =
1.644 + ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
1.645 + externalizable =
1.646 + ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
1.647 + boolean sflag =
1.648 + ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
1.649 + if (externalizable && sflag) {
1.650 + throw new InvalidClassException(
1.651 + name, "serializable and externalizable flags conflict");
1.652 + }
1.653 + serializable = externalizable || sflag;
1.654 + isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
1.655 + if (isEnum && suid.longValue() != 0L) {
1.656 + throw new InvalidClassException(name,
1.657 + "enum descriptor has non-zero serialVersionUID: " + suid);
1.658 + }
1.659 +
1.660 + int numFields = in.readShort();
1.661 + if (isEnum && numFields != 0) {
1.662 + throw new InvalidClassException(name,
1.663 + "enum descriptor has non-zero field count: " + numFields);
1.664 + }
1.665 + fields = (numFields > 0) ?
1.666 + new ObjectStreamField[numFields] : NO_FIELDS;
1.667 + for (int i = 0; i < numFields; i++) {
1.668 + char tcode = (char) in.readByte();
1.669 + String fname = in.readUTF();
1.670 + String signature = ((tcode == 'L') || (tcode == '[')) ?
1.671 + in.readTypeString() : new String(new char[] { tcode });
1.672 + try {
1.673 + fields[i] = new ObjectStreamField(fname, signature, false);
1.674 + } catch (RuntimeException e) {
1.675 + throw (IOException) new InvalidClassException(name,
1.676 + "invalid descriptor for field " + fname).initCause(e);
1.677 + }
1.678 + }
1.679 + computeFieldOffsets();
1.680 + }
1.681 +
1.682 + /**
1.683 + * Writes non-proxy class descriptor information to given output stream.
1.684 + */
1.685 + void writeNonProxy(ObjectOutputStream out) throws IOException {
1.686 + out.writeUTF(name);
1.687 + out.writeLong(getSerialVersionUID());
1.688 +
1.689 + byte flags = 0;
1.690 + if (externalizable) {
1.691 + flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
1.692 + int protocol = out.getProtocolVersion();
1.693 + if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
1.694 + flags |= ObjectStreamConstants.SC_BLOCK_DATA;
1.695 + }
1.696 + } else if (serializable) {
1.697 + flags |= ObjectStreamConstants.SC_SERIALIZABLE;
1.698 + }
1.699 + if (hasWriteObjectData) {
1.700 + flags |= ObjectStreamConstants.SC_WRITE_METHOD;
1.701 + }
1.702 + if (isEnum) {
1.703 + flags |= ObjectStreamConstants.SC_ENUM;
1.704 + }
1.705 + out.writeByte(flags);
1.706 +
1.707 + out.writeShort(fields.length);
1.708 + for (int i = 0; i < fields.length; i++) {
1.709 + ObjectStreamField f = fields[i];
1.710 + out.writeByte(f.getTypeCode());
1.711 + out.writeUTF(f.getName());
1.712 + if (!f.isPrimitive()) {
1.713 + out.writeTypeString(f.getTypeString());
1.714 + }
1.715 + }
1.716 + }
1.717 +
1.718 + /**
1.719 + * Returns ClassNotFoundException (if any) thrown while attempting to
1.720 + * resolve local class corresponding to this class descriptor.
1.721 + */
1.722 + ClassNotFoundException getResolveException() {
1.723 + return resolveEx;
1.724 + }
1.725 +
1.726 + /**
1.727 + * Throws an InvalidClassException if object instances referencing this
1.728 + * class descriptor should not be allowed to deserialize. This method does
1.729 + * not apply to deserialization of enum constants.
1.730 + */
1.731 + void checkDeserialize() throws InvalidClassException {
1.732 + if (deserializeEx != null) {
1.733 + InvalidClassException ice =
1.734 + new InvalidClassException(deserializeEx.classname,
1.735 + deserializeEx.getMessage());
1.736 + ice.initCause(deserializeEx);
1.737 + throw ice;
1.738 + }
1.739 + }
1.740 +
1.741 + /**
1.742 + * Throws an InvalidClassException if objects whose class is represented by
1.743 + * this descriptor should not be allowed to serialize. This method does
1.744 + * not apply to serialization of enum constants.
1.745 + */
1.746 + void checkSerialize() throws InvalidClassException {
1.747 + if (serializeEx != null) {
1.748 + InvalidClassException ice =
1.749 + new InvalidClassException(serializeEx.classname,
1.750 + serializeEx.getMessage());
1.751 + ice.initCause(serializeEx);
1.752 + throw ice;
1.753 + }
1.754 + }
1.755 +
1.756 + /**
1.757 + * Throws an InvalidClassException if objects whose class is represented by
1.758 + * this descriptor should not be permitted to use default serialization
1.759 + * (e.g., if the class declares serializable fields that do not correspond
1.760 + * to actual fields, and hence must use the GetField API). This method
1.761 + * does not apply to deserialization of enum constants.
1.762 + */
1.763 + void checkDefaultSerialize() throws InvalidClassException {
1.764 + if (defaultSerializeEx != null) {
1.765 + InvalidClassException ice =
1.766 + new InvalidClassException(defaultSerializeEx.classname,
1.767 + defaultSerializeEx.getMessage());
1.768 + ice.initCause(defaultSerializeEx);
1.769 + throw ice;
1.770 + }
1.771 + }
1.772 +
1.773 + /**
1.774 + * Returns superclass descriptor. Note that on the receiving side, the
1.775 + * superclass descriptor may be bound to a class that is not a superclass
1.776 + * of the subclass descriptor's bound class.
1.777 + */
1.778 + ObjectStreamClass getSuperDesc() {
1.779 + return superDesc;
1.780 + }
1.781 +
1.782 + /**
1.783 + * Returns the "local" class descriptor for the class associated with this
1.784 + * class descriptor (i.e., the result of
1.785 + * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
1.786 + * associated with this descriptor.
1.787 + */
1.788 + ObjectStreamClass getLocalDesc() {
1.789 + return localDesc;
1.790 + }
1.791 +
1.792 + /**
1.793 + * Returns arrays of ObjectStreamFields representing the serializable
1.794 + * fields of the represented class. If copy is true, a clone of this class
1.795 + * descriptor's field array is returned, otherwise the array itself is
1.796 + * returned.
1.797 + */
1.798 + ObjectStreamField[] getFields(boolean copy) {
1.799 + return copy ? fields.clone() : fields;
1.800 + }
1.801 +
1.802 + /**
1.803 + * Looks up a serializable field of the represented class by name and type.
1.804 + * A specified type of null matches all types, Object.class matches all
1.805 + * non-primitive types, and any other non-null type matches assignable
1.806 + * types only. Returns matching field, or null if no match found.
1.807 + */
1.808 + ObjectStreamField getField(String name, Class<?> type) {
1.809 + for (int i = 0; i < fields.length; i++) {
1.810 + ObjectStreamField f = fields[i];
1.811 + if (f.getName().equals(name)) {
1.812 + if (type == null ||
1.813 + (type == Object.class && !f.isPrimitive()))
1.814 + {
1.815 + return f;
1.816 + }
1.817 + Class<?> ftype = f.getType();
1.818 + if (ftype != null && type.isAssignableFrom(ftype)) {
1.819 + return f;
1.820 + }
1.821 + }
1.822 + }
1.823 + return null;
1.824 + }
1.825 +
1.826 + /**
1.827 + * Returns true if class descriptor represents a dynamic proxy class, false
1.828 + * otherwise.
1.829 + */
1.830 + boolean isProxy() {
1.831 + return isProxy;
1.832 + }
1.833 +
1.834 + /**
1.835 + * Returns true if class descriptor represents an enum type, false
1.836 + * otherwise.
1.837 + */
1.838 + boolean isEnum() {
1.839 + return isEnum;
1.840 + }
1.841 +
1.842 + /**
1.843 + * Returns true if represented class implements Externalizable, false
1.844 + * otherwise.
1.845 + */
1.846 + boolean isExternalizable() {
1.847 + return externalizable;
1.848 + }
1.849 +
1.850 + /**
1.851 + * Returns true if represented class implements Serializable, false
1.852 + * otherwise.
1.853 + */
1.854 + boolean isSerializable() {
1.855 + return serializable;
1.856 + }
1.857 +
1.858 + /**
1.859 + * Returns true if class descriptor represents externalizable class that
1.860 + * has written its data in 1.2 (block data) format, false otherwise.
1.861 + */
1.862 + boolean hasBlockExternalData() {
1.863 + return hasBlockExternalData;
1.864 + }
1.865 +
1.866 + /**
1.867 + * Returns true if class descriptor represents serializable (but not
1.868 + * externalizable) class which has written its data via a custom
1.869 + * writeObject() method, false otherwise.
1.870 + */
1.871 + boolean hasWriteObjectData() {
1.872 + return hasWriteObjectData;
1.873 + }
1.874 +
1.875 + /**
1.876 + * Returns true if represented class is serializable/externalizable and can
1.877 + * be instantiated by the serialization runtime--i.e., if it is
1.878 + * externalizable and defines a public no-arg constructor, or if it is
1.879 + * non-externalizable and its first non-serializable superclass defines an
1.880 + * accessible no-arg constructor. Otherwise, returns false.
1.881 + */
1.882 + boolean isInstantiable() {
1.883 + return (cons != null);
1.884 + }
1.885 +
1.886 + /**
1.887 + * Returns true if represented class is serializable (but not
1.888 + * externalizable) and defines a conformant writeObject method. Otherwise,
1.889 + * returns false.
1.890 + */
1.891 + boolean hasWriteObjectMethod() {
1.892 + return (writeObjectMethod != null);
1.893 + }
1.894 +
1.895 + /**
1.896 + * Returns true if represented class is serializable (but not
1.897 + * externalizable) and defines a conformant readObject method. Otherwise,
1.898 + * returns false.
1.899 + */
1.900 + boolean hasReadObjectMethod() {
1.901 + return (readObjectMethod != null);
1.902 + }
1.903 +
1.904 + /**
1.905 + * Returns true if represented class is serializable (but not
1.906 + * externalizable) and defines a conformant readObjectNoData method.
1.907 + * Otherwise, returns false.
1.908 + */
1.909 + boolean hasReadObjectNoDataMethod() {
1.910 + return (readObjectNoDataMethod != null);
1.911 + }
1.912 +
1.913 + /**
1.914 + * Returns true if represented class is serializable or externalizable and
1.915 + * defines a conformant writeReplace method. Otherwise, returns false.
1.916 + */
1.917 + boolean hasWriteReplaceMethod() {
1.918 + return (writeReplaceMethod != null);
1.919 + }
1.920 +
1.921 + /**
1.922 + * Returns true if represented class is serializable or externalizable and
1.923 + * defines a conformant readResolve method. Otherwise, returns false.
1.924 + */
1.925 + boolean hasReadResolveMethod() {
1.926 + return (readResolveMethod != null);
1.927 + }
1.928 +
1.929 + /**
1.930 + * Creates a new instance of the represented class. If the class is
1.931 + * externalizable, invokes its public no-arg constructor; otherwise, if the
1.932 + * class is serializable, invokes the no-arg constructor of the first
1.933 + * non-serializable superclass. Throws UnsupportedOperationException if
1.934 + * this class descriptor is not associated with a class, if the associated
1.935 + * class is non-serializable or if the appropriate no-arg constructor is
1.936 + * inaccessible/unavailable.
1.937 + */
1.938 + Object newInstance()
1.939 + throws InstantiationException, InvocationTargetException,
1.940 + UnsupportedOperationException
1.941 + {
1.942 + if (cons != null) {
1.943 + try {
1.944 + return cons.newInstance();
1.945 + } catch (IllegalAccessException ex) {
1.946 + // should not occur, as access checks have been suppressed
1.947 + throw new InternalError();
1.948 + }
1.949 + } else {
1.950 + throw new UnsupportedOperationException();
1.951 + }
1.952 + }
1.953 +
1.954 + /**
1.955 + * Invokes the writeObject method of the represented serializable class.
1.956 + * Throws UnsupportedOperationException if this class descriptor is not
1.957 + * associated with a class, or if the class is externalizable,
1.958 + * non-serializable or does not define writeObject.
1.959 + */
1.960 + void invokeWriteObject(Object obj, ObjectOutputStream out)
1.961 + throws IOException, UnsupportedOperationException
1.962 + {
1.963 + if (writeObjectMethod != null) {
1.964 + try {
1.965 + writeObjectMethod.invoke(obj, new Object[]{ out });
1.966 + } catch (InvocationTargetException ex) {
1.967 + Throwable th = ex.getTargetException();
1.968 + if (th instanceof IOException) {
1.969 + throw (IOException) th;
1.970 + } else {
1.971 + throwMiscException(th);
1.972 + }
1.973 + } catch (IllegalAccessException ex) {
1.974 + // should not occur, as access checks have been suppressed
1.975 + throw new InternalError();
1.976 + }
1.977 + } else {
1.978 + throw new UnsupportedOperationException();
1.979 + }
1.980 + }
1.981 +
1.982 + /**
1.983 + * Invokes the readObject method of the represented serializable class.
1.984 + * Throws UnsupportedOperationException if this class descriptor is not
1.985 + * associated with a class, or if the class is externalizable,
1.986 + * non-serializable or does not define readObject.
1.987 + */
1.988 + void invokeReadObject(Object obj, ObjectInputStream in)
1.989 + throws ClassNotFoundException, IOException,
1.990 + UnsupportedOperationException
1.991 + {
1.992 + if (readObjectMethod != null) {
1.993 + try {
1.994 + readObjectMethod.invoke(obj, new Object[]{ in });
1.995 + } catch (InvocationTargetException ex) {
1.996 + Throwable th = ex.getTargetException();
1.997 + if (th instanceof ClassNotFoundException) {
1.998 + throw (ClassNotFoundException) th;
1.999 + } else if (th instanceof IOException) {
1.1000 + throw (IOException) th;
1.1001 + } else {
1.1002 + throwMiscException(th);
1.1003 + }
1.1004 + } catch (IllegalAccessException ex) {
1.1005 + // should not occur, as access checks have been suppressed
1.1006 + throw new InternalError();
1.1007 + }
1.1008 + } else {
1.1009 + throw new UnsupportedOperationException();
1.1010 + }
1.1011 + }
1.1012 +
1.1013 + /**
1.1014 + * Invokes the readObjectNoData method of the represented serializable
1.1015 + * class. Throws UnsupportedOperationException if this class descriptor is
1.1016 + * not associated with a class, or if the class is externalizable,
1.1017 + * non-serializable or does not define readObjectNoData.
1.1018 + */
1.1019 + void invokeReadObjectNoData(Object obj)
1.1020 + throws IOException, UnsupportedOperationException
1.1021 + {
1.1022 + if (readObjectNoDataMethod != null) {
1.1023 + try {
1.1024 + readObjectNoDataMethod.invoke(obj, (Object[]) null);
1.1025 + } catch (InvocationTargetException ex) {
1.1026 + Throwable th = ex.getTargetException();
1.1027 + if (th instanceof ObjectStreamException) {
1.1028 + throw (ObjectStreamException) th;
1.1029 + } else {
1.1030 + throwMiscException(th);
1.1031 + }
1.1032 + } catch (IllegalAccessException ex) {
1.1033 + // should not occur, as access checks have been suppressed
1.1034 + throw new InternalError();
1.1035 + }
1.1036 + } else {
1.1037 + throw new UnsupportedOperationException();
1.1038 + }
1.1039 + }
1.1040 +
1.1041 + /**
1.1042 + * Invokes the writeReplace method of the represented serializable class and
1.1043 + * returns the result. Throws UnsupportedOperationException if this class
1.1044 + * descriptor is not associated with a class, or if the class is
1.1045 + * non-serializable or does not define writeReplace.
1.1046 + */
1.1047 + Object invokeWriteReplace(Object obj)
1.1048 + throws IOException, UnsupportedOperationException
1.1049 + {
1.1050 + if (writeReplaceMethod != null) {
1.1051 + try {
1.1052 + return writeReplaceMethod.invoke(obj, (Object[]) null);
1.1053 + } catch (InvocationTargetException ex) {
1.1054 + Throwable th = ex.getTargetException();
1.1055 + if (th instanceof ObjectStreamException) {
1.1056 + throw (ObjectStreamException) th;
1.1057 + } else {
1.1058 + throwMiscException(th);
1.1059 + throw new InternalError(); // never reached
1.1060 + }
1.1061 + } catch (IllegalAccessException ex) {
1.1062 + // should not occur, as access checks have been suppressed
1.1063 + throw new InternalError();
1.1064 + }
1.1065 + } else {
1.1066 + throw new UnsupportedOperationException();
1.1067 + }
1.1068 + }
1.1069 +
1.1070 + /**
1.1071 + * Invokes the readResolve method of the represented serializable class and
1.1072 + * returns the result. Throws UnsupportedOperationException if this class
1.1073 + * descriptor is not associated with a class, or if the class is
1.1074 + * non-serializable or does not define readResolve.
1.1075 + */
1.1076 + Object invokeReadResolve(Object obj)
1.1077 + throws IOException, UnsupportedOperationException
1.1078 + {
1.1079 + if (readResolveMethod != null) {
1.1080 + try {
1.1081 + return readResolveMethod.invoke(obj, (Object[]) null);
1.1082 + } catch (InvocationTargetException ex) {
1.1083 + Throwable th = ex.getTargetException();
1.1084 + if (th instanceof ObjectStreamException) {
1.1085 + throw (ObjectStreamException) th;
1.1086 + } else {
1.1087 + throwMiscException(th);
1.1088 + throw new InternalError(); // never reached
1.1089 + }
1.1090 + } catch (IllegalAccessException ex) {
1.1091 + // should not occur, as access checks have been suppressed
1.1092 + throw new InternalError();
1.1093 + }
1.1094 + } else {
1.1095 + throw new UnsupportedOperationException();
1.1096 + }
1.1097 + }
1.1098 +
1.1099 + /**
1.1100 + * Class representing the portion of an object's serialized form allotted
1.1101 + * to data described by a given class descriptor. If "hasData" is false,
1.1102 + * the object's serialized form does not contain data associated with the
1.1103 + * class descriptor.
1.1104 + */
1.1105 + static class ClassDataSlot {
1.1106 +
1.1107 + /** class descriptor "occupying" this slot */
1.1108 + final ObjectStreamClass desc;
1.1109 + /** true if serialized form includes data for this slot's descriptor */
1.1110 + final boolean hasData;
1.1111 +
1.1112 + ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
1.1113 + this.desc = desc;
1.1114 + this.hasData = hasData;
1.1115 + }
1.1116 + }
1.1117 +
1.1118 + /**
1.1119 + * Returns array of ClassDataSlot instances representing the data layout
1.1120 + * (including superclass data) for serialized objects described by this
1.1121 + * class descriptor. ClassDataSlots are ordered by inheritance with those
1.1122 + * containing "higher" superclasses appearing first. The final
1.1123 + * ClassDataSlot contains a reference to this descriptor.
1.1124 + */
1.1125 + ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
1.1126 + // REMIND: synchronize instead of relying on volatile?
1.1127 + if (dataLayout == null) {
1.1128 + dataLayout = getClassDataLayout0();
1.1129 + }
1.1130 + return dataLayout;
1.1131 + }
1.1132 +
1.1133 + private ClassDataSlot[] getClassDataLayout0()
1.1134 + throws InvalidClassException
1.1135 + {
1.1136 + ArrayList<ClassDataSlot> slots = new ArrayList<>();
1.1137 + Class<?> start = cl, end = cl;
1.1138 +
1.1139 + // locate closest non-serializable superclass
1.1140 + while (end != null && Serializable.class.isAssignableFrom(end)) {
1.1141 + end = end.getSuperclass();
1.1142 + }
1.1143 +
1.1144 + for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
1.1145 +
1.1146 + // search up inheritance hierarchy for class with matching name
1.1147 + String searchName = (d.cl != null) ? d.cl.getName() : d.name;
1.1148 + Class<?> match = null;
1.1149 + for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1.1150 + if (searchName.equals(c.getName())) {
1.1151 + match = c;
1.1152 + break;
1.1153 + }
1.1154 + }
1.1155 +
1.1156 + // add "no data" slot for each unmatched class below match
1.1157 + if (match != null) {
1.1158 + for (Class<?> c = start; c != match; c = c.getSuperclass()) {
1.1159 + slots.add(new ClassDataSlot(
1.1160 + ObjectStreamClass.lookup(c, true), false));
1.1161 + }
1.1162 + start = match.getSuperclass();
1.1163 + }
1.1164 +
1.1165 + // record descriptor/class pairing
1.1166 + slots.add(new ClassDataSlot(d.getVariantFor(match), true));
1.1167 + }
1.1168 +
1.1169 + // add "no data" slot for any leftover unmatched classes
1.1170 + for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1.1171 + slots.add(new ClassDataSlot(
1.1172 + ObjectStreamClass.lookup(c, true), false));
1.1173 + }
1.1174 +
1.1175 + // order slots from superclass -> subclass
1.1176 + Collections.reverse(slots);
1.1177 + return slots.toArray(new ClassDataSlot[slots.size()]);
1.1178 + }
1.1179 +
1.1180 + /**
1.1181 + * Returns aggregate size (in bytes) of marshalled primitive field values
1.1182 + * for represented class.
1.1183 + */
1.1184 + int getPrimDataSize() {
1.1185 + return primDataSize;
1.1186 + }
1.1187 +
1.1188 + /**
1.1189 + * Returns number of non-primitive serializable fields of represented
1.1190 + * class.
1.1191 + */
1.1192 + int getNumObjFields() {
1.1193 + return numObjFields;
1.1194 + }
1.1195 +
1.1196 + /**
1.1197 + * Fetches the serializable primitive field values of object obj and
1.1198 + * marshals them into byte array buf starting at offset 0. It is the
1.1199 + * responsibility of the caller to ensure that obj is of the proper type if
1.1200 + * non-null.
1.1201 + */
1.1202 + void getPrimFieldValues(Object obj, byte[] buf) {
1.1203 + fieldRefl.getPrimFieldValues(obj, buf);
1.1204 + }
1.1205 +
1.1206 + /**
1.1207 + * Sets the serializable primitive fields of object obj using values
1.1208 + * unmarshalled from byte array buf starting at offset 0. It is the
1.1209 + * responsibility of the caller to ensure that obj is of the proper type if
1.1210 + * non-null.
1.1211 + */
1.1212 + void setPrimFieldValues(Object obj, byte[] buf) {
1.1213 + fieldRefl.setPrimFieldValues(obj, buf);
1.1214 + }
1.1215 +
1.1216 + /**
1.1217 + * Fetches the serializable object field values of object obj and stores
1.1218 + * them in array vals starting at offset 0. It is the responsibility of
1.1219 + * the caller to ensure that obj is of the proper type if non-null.
1.1220 + */
1.1221 + void getObjFieldValues(Object obj, Object[] vals) {
1.1222 + fieldRefl.getObjFieldValues(obj, vals);
1.1223 + }
1.1224 +
1.1225 + /**
1.1226 + * Sets the serializable object fields of object obj using values from
1.1227 + * array vals starting at offset 0. It is the responsibility of the caller
1.1228 + * to ensure that obj is of the proper type if non-null.
1.1229 + */
1.1230 + void setObjFieldValues(Object obj, Object[] vals) {
1.1231 + fieldRefl.setObjFieldValues(obj, vals);
1.1232 + }
1.1233 +
1.1234 + /**
1.1235 + * Calculates and sets serializable field offsets, as well as primitive
1.1236 + * data size and object field count totals. Throws InvalidClassException
1.1237 + * if fields are illegally ordered.
1.1238 + */
1.1239 + private void computeFieldOffsets() throws InvalidClassException {
1.1240 + primDataSize = 0;
1.1241 + numObjFields = 0;
1.1242 + int firstObjIndex = -1;
1.1243 +
1.1244 + for (int i = 0; i < fields.length; i++) {
1.1245 + ObjectStreamField f = fields[i];
1.1246 + switch (f.getTypeCode()) {
1.1247 + case 'Z':
1.1248 + case 'B':
1.1249 + f.setOffset(primDataSize++);
1.1250 + break;
1.1251 +
1.1252 + case 'C':
1.1253 + case 'S':
1.1254 + f.setOffset(primDataSize);
1.1255 + primDataSize += 2;
1.1256 + break;
1.1257 +
1.1258 + case 'I':
1.1259 + case 'F':
1.1260 + f.setOffset(primDataSize);
1.1261 + primDataSize += 4;
1.1262 + break;
1.1263 +
1.1264 + case 'J':
1.1265 + case 'D':
1.1266 + f.setOffset(primDataSize);
1.1267 + primDataSize += 8;
1.1268 + break;
1.1269 +
1.1270 + case '[':
1.1271 + case 'L':
1.1272 + f.setOffset(numObjFields++);
1.1273 + if (firstObjIndex == -1) {
1.1274 + firstObjIndex = i;
1.1275 + }
1.1276 + break;
1.1277 +
1.1278 + default:
1.1279 + throw new InternalError();
1.1280 + }
1.1281 + }
1.1282 + if (firstObjIndex != -1 &&
1.1283 + firstObjIndex + numObjFields != fields.length)
1.1284 + {
1.1285 + throw new InvalidClassException(name, "illegal field order");
1.1286 + }
1.1287 + }
1.1288 +
1.1289 + /**
1.1290 + * If given class is the same as the class associated with this class
1.1291 + * descriptor, returns reference to this class descriptor. Otherwise,
1.1292 + * returns variant of this class descriptor bound to given class.
1.1293 + */
1.1294 + private ObjectStreamClass getVariantFor(Class<?> cl)
1.1295 + throws InvalidClassException
1.1296 + {
1.1297 + if (this.cl == cl) {
1.1298 + return this;
1.1299 + }
1.1300 + ObjectStreamClass desc = new ObjectStreamClass();
1.1301 + if (isProxy) {
1.1302 + desc.initProxy(cl, null, superDesc);
1.1303 + } else {
1.1304 + desc.initNonProxy(this, cl, null, superDesc);
1.1305 + }
1.1306 + return desc;
1.1307 + }
1.1308 +
1.1309 + /**
1.1310 + * Returns public no-arg constructor of given class, or null if none found.
1.1311 + * Access checks are disabled on the returned constructor (if any), since
1.1312 + * the defining class may still be non-public.
1.1313 + */
1.1314 + private static Constructor getExternalizableConstructor(Class<?> cl) {
1.1315 + try {
1.1316 + Constructor cons = cl.getDeclaredConstructor((Class<?>[]) null);
1.1317 + cons.setAccessible(true);
1.1318 + return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1.1319 + cons : null;
1.1320 + } catch (NoSuchMethodException ex) {
1.1321 + return null;
1.1322 + }
1.1323 + }
1.1324 +
1.1325 + /**
1.1326 + * Returns subclass-accessible no-arg constructor of first non-serializable
1.1327 + * superclass, or null if none found. Access checks are disabled on the
1.1328 + * returned constructor (if any).
1.1329 + */
1.1330 + private static Constructor getSerializableConstructor(Class<?> cl) {
1.1331 + Class<?> initCl = cl;
1.1332 + while (Serializable.class.isAssignableFrom(initCl)) {
1.1333 + if ((initCl = initCl.getSuperclass()) == null) {
1.1334 + return null;
1.1335 + }
1.1336 + }
1.1337 + try {
1.1338 + Constructor cons = initCl.getDeclaredConstructor((Class<?>[]) null);
1.1339 + int mods = cons.getModifiers();
1.1340 + if ((mods & Modifier.PRIVATE) != 0 ||
1.1341 + ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
1.1342 + !packageEquals(cl, initCl)))
1.1343 + {
1.1344 + return null;
1.1345 + }
1.1346 + cons = reflFactory.newConstructorForSerialization(cl, cons);
1.1347 + cons.setAccessible(true);
1.1348 + return cons;
1.1349 + } catch (NoSuchMethodException ex) {
1.1350 + return null;
1.1351 + }
1.1352 + }
1.1353 +
1.1354 + /**
1.1355 + * Returns non-static, non-abstract method with given signature provided it
1.1356 + * is defined by or accessible (via inheritance) by the given class, or
1.1357 + * null if no match found. Access checks are disabled on the returned
1.1358 + * method (if any).
1.1359 + */
1.1360 + private static Method getInheritableMethod(Class<?> cl, String name,
1.1361 + Class<?>[] argTypes,
1.1362 + Class<?> returnType)
1.1363 + {
1.1364 + Method meth = null;
1.1365 + Class<?> defCl = cl;
1.1366 + while (defCl != null) {
1.1367 + try {
1.1368 + meth = defCl.getDeclaredMethod(name, argTypes);
1.1369 + break;
1.1370 + } catch (NoSuchMethodException ex) {
1.1371 + defCl = defCl.getSuperclass();
1.1372 + }
1.1373 + }
1.1374 +
1.1375 + if ((meth == null) || (meth.getReturnType() != returnType)) {
1.1376 + return null;
1.1377 + }
1.1378 + meth.setAccessible(true);
1.1379 + int mods = meth.getModifiers();
1.1380 + if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
1.1381 + return null;
1.1382 + } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
1.1383 + return meth;
1.1384 + } else if ((mods & Modifier.PRIVATE) != 0) {
1.1385 + return (cl == defCl) ? meth : null;
1.1386 + } else {
1.1387 + return packageEquals(cl, defCl) ? meth : null;
1.1388 + }
1.1389 + }
1.1390 +
1.1391 + /**
1.1392 + * Returns non-static private method with given signature defined by given
1.1393 + * class, or null if none found. Access checks are disabled on the
1.1394 + * returned method (if any).
1.1395 + */
1.1396 + private static Method getPrivateMethod(Class<?> cl, String name,
1.1397 + Class<?>[] argTypes,
1.1398 + Class<?> returnType)
1.1399 + {
1.1400 + try {
1.1401 + Method meth = cl.getDeclaredMethod(name, argTypes);
1.1402 + meth.setAccessible(true);
1.1403 + int mods = meth.getModifiers();
1.1404 + return ((meth.getReturnType() == returnType) &&
1.1405 + ((mods & Modifier.STATIC) == 0) &&
1.1406 + ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
1.1407 + } catch (NoSuchMethodException ex) {
1.1408 + return null;
1.1409 + }
1.1410 + }
1.1411 +
1.1412 + /**
1.1413 + * Returns true if classes are defined in the same runtime package, false
1.1414 + * otherwise.
1.1415 + */
1.1416 + private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
1.1417 + return (cl1.getClassLoader() == cl2.getClassLoader() &&
1.1418 + getPackageName(cl1).equals(getPackageName(cl2)));
1.1419 + }
1.1420 +
1.1421 + /**
1.1422 + * Returns package name of given class.
1.1423 + */
1.1424 + private static String getPackageName(Class<?> cl) {
1.1425 + String s = cl.getName();
1.1426 + int i = s.lastIndexOf('[');
1.1427 + if (i >= 0) {
1.1428 + s = s.substring(i + 2);
1.1429 + }
1.1430 + i = s.lastIndexOf('.');
1.1431 + return (i >= 0) ? s.substring(0, i) : "";
1.1432 + }
1.1433 +
1.1434 + /**
1.1435 + * Compares class names for equality, ignoring package names. Returns true
1.1436 + * if class names equal, false otherwise.
1.1437 + */
1.1438 + private static boolean classNamesEqual(String name1, String name2) {
1.1439 + name1 = name1.substring(name1.lastIndexOf('.') + 1);
1.1440 + name2 = name2.substring(name2.lastIndexOf('.') + 1);
1.1441 + return name1.equals(name2);
1.1442 + }
1.1443 +
1.1444 + /**
1.1445 + * Returns JVM type signature for given class.
1.1446 + */
1.1447 + private static String getClassSignature(Class<?> cl) {
1.1448 + StringBuilder sbuf = new StringBuilder();
1.1449 + while (cl.isArray()) {
1.1450 + sbuf.append('[');
1.1451 + cl = cl.getComponentType();
1.1452 + }
1.1453 + if (cl.isPrimitive()) {
1.1454 + if (cl == Integer.TYPE) {
1.1455 + sbuf.append('I');
1.1456 + } else if (cl == Byte.TYPE) {
1.1457 + sbuf.append('B');
1.1458 + } else if (cl == Long.TYPE) {
1.1459 + sbuf.append('J');
1.1460 + } else if (cl == Float.TYPE) {
1.1461 + sbuf.append('F');
1.1462 + } else if (cl == Double.TYPE) {
1.1463 + sbuf.append('D');
1.1464 + } else if (cl == Short.TYPE) {
1.1465 + sbuf.append('S');
1.1466 + } else if (cl == Character.TYPE) {
1.1467 + sbuf.append('C');
1.1468 + } else if (cl == Boolean.TYPE) {
1.1469 + sbuf.append('Z');
1.1470 + } else if (cl == Void.TYPE) {
1.1471 + sbuf.append('V');
1.1472 + } else {
1.1473 + throw new InternalError();
1.1474 + }
1.1475 + } else {
1.1476 + sbuf.append('L' + cl.getName().replace('.', '/') + ';');
1.1477 + }
1.1478 + return sbuf.toString();
1.1479 + }
1.1480 +
1.1481 + /**
1.1482 + * Returns JVM type signature for given list of parameters and return type.
1.1483 + */
1.1484 + private static String getMethodSignature(Class<?>[] paramTypes,
1.1485 + Class<?> retType)
1.1486 + {
1.1487 + StringBuilder sbuf = new StringBuilder();
1.1488 + sbuf.append('(');
1.1489 + for (int i = 0; i < paramTypes.length; i++) {
1.1490 + sbuf.append(getClassSignature(paramTypes[i]));
1.1491 + }
1.1492 + sbuf.append(')');
1.1493 + sbuf.append(getClassSignature(retType));
1.1494 + return sbuf.toString();
1.1495 + }
1.1496 +
1.1497 + /**
1.1498 + * Convenience method for throwing an exception that is either a
1.1499 + * RuntimeException, Error, or of some unexpected type (in which case it is
1.1500 + * wrapped inside an IOException).
1.1501 + */
1.1502 + private static void throwMiscException(Throwable th) throws IOException {
1.1503 + if (th instanceof RuntimeException) {
1.1504 + throw (RuntimeException) th;
1.1505 + } else if (th instanceof Error) {
1.1506 + throw (Error) th;
1.1507 + } else {
1.1508 + IOException ex = new IOException("unexpected exception type");
1.1509 + ex.initCause(th);
1.1510 + throw ex;
1.1511 + }
1.1512 + }
1.1513 +
1.1514 + /**
1.1515 + * Returns ObjectStreamField array describing the serializable fields of
1.1516 + * the given class. Serializable fields backed by an actual field of the
1.1517 + * class are represented by ObjectStreamFields with corresponding non-null
1.1518 + * Field objects. Throws InvalidClassException if the (explicitly
1.1519 + * declared) serializable fields are invalid.
1.1520 + */
1.1521 + private static ObjectStreamField[] getSerialFields(Class<?> cl)
1.1522 + throws InvalidClassException
1.1523 + {
1.1524 + ObjectStreamField[] fields;
1.1525 + if (Serializable.class.isAssignableFrom(cl) &&
1.1526 + !Externalizable.class.isAssignableFrom(cl) &&
1.1527 + !Proxy.isProxyClass(cl) &&
1.1528 + !cl.isInterface())
1.1529 + {
1.1530 + if ((fields = getDeclaredSerialFields(cl)) == null) {
1.1531 + fields = getDefaultSerialFields(cl);
1.1532 + }
1.1533 + Arrays.sort(fields);
1.1534 + } else {
1.1535 + fields = NO_FIELDS;
1.1536 + }
1.1537 + return fields;
1.1538 + }
1.1539 +
1.1540 + /**
1.1541 + * Returns serializable fields of given class as defined explicitly by a
1.1542 + * "serialPersistentFields" field, or null if no appropriate
1.1543 + * "serialPersistentFields" field is defined. Serializable fields backed
1.1544 + * by an actual field of the class are represented by ObjectStreamFields
1.1545 + * with corresponding non-null Field objects. For compatibility with past
1.1546 + * releases, a "serialPersistentFields" field with a null value is
1.1547 + * considered equivalent to not declaring "serialPersistentFields". Throws
1.1548 + * InvalidClassException if the declared serializable fields are
1.1549 + * invalid--e.g., if multiple fields share the same name.
1.1550 + */
1.1551 + private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
1.1552 + throws InvalidClassException
1.1553 + {
1.1554 + ObjectStreamField[] serialPersistentFields = null;
1.1555 + try {
1.1556 + Field f = cl.getDeclaredField("serialPersistentFields");
1.1557 + int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
1.1558 + if ((f.getModifiers() & mask) == mask) {
1.1559 + f.setAccessible(true);
1.1560 + serialPersistentFields = (ObjectStreamField[]) f.get(null);
1.1561 + }
1.1562 + } catch (Exception ex) {
1.1563 + }
1.1564 + if (serialPersistentFields == null) {
1.1565 + return null;
1.1566 + } else if (serialPersistentFields.length == 0) {
1.1567 + return NO_FIELDS;
1.1568 + }
1.1569 +
1.1570 + ObjectStreamField[] boundFields =
1.1571 + new ObjectStreamField[serialPersistentFields.length];
1.1572 + Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
1.1573 +
1.1574 + for (int i = 0; i < serialPersistentFields.length; i++) {
1.1575 + ObjectStreamField spf = serialPersistentFields[i];
1.1576 +
1.1577 + String fname = spf.getName();
1.1578 + if (fieldNames.contains(fname)) {
1.1579 + throw new InvalidClassException(
1.1580 + "multiple serializable fields named " + fname);
1.1581 + }
1.1582 + fieldNames.add(fname);
1.1583 +
1.1584 + try {
1.1585 + Field f = cl.getDeclaredField(fname);
1.1586 + if ((f.getType() == spf.getType()) &&
1.1587 + ((f.getModifiers() & Modifier.STATIC) == 0))
1.1588 + {
1.1589 + boundFields[i] =
1.1590 + new ObjectStreamField(f, spf.isUnshared(), true);
1.1591 + }
1.1592 + } catch (NoSuchFieldException ex) {
1.1593 + }
1.1594 + if (boundFields[i] == null) {
1.1595 + boundFields[i] = new ObjectStreamField(
1.1596 + fname, spf.getType(), spf.isUnshared());
1.1597 + }
1.1598 + }
1.1599 + return boundFields;
1.1600 + }
1.1601 +
1.1602 + /**
1.1603 + * Returns array of ObjectStreamFields corresponding to all non-static
1.1604 + * non-transient fields declared by given class. Each ObjectStreamField
1.1605 + * contains a Field object for the field it represents. If no default
1.1606 + * serializable fields exist, NO_FIELDS is returned.
1.1607 + */
1.1608 + private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
1.1609 + Field[] clFields = cl.getDeclaredFields();
1.1610 + ArrayList<ObjectStreamField> list = new ArrayList<>();
1.1611 + int mask = Modifier.STATIC | Modifier.TRANSIENT;
1.1612 +
1.1613 + for (int i = 0; i < clFields.length; i++) {
1.1614 + if ((clFields[i].getModifiers() & mask) == 0) {
1.1615 + list.add(new ObjectStreamField(clFields[i], false, true));
1.1616 + }
1.1617 + }
1.1618 + int size = list.size();
1.1619 + return (size == 0) ? NO_FIELDS :
1.1620 + list.toArray(new ObjectStreamField[size]);
1.1621 + }
1.1622 +
1.1623 + /**
1.1624 + * Returns explicit serial version UID value declared by given class, or
1.1625 + * null if none.
1.1626 + */
1.1627 + private static Long getDeclaredSUID(Class<?> cl) {
1.1628 + try {
1.1629 + Field f = cl.getDeclaredField("serialVersionUID");
1.1630 + int mask = Modifier.STATIC | Modifier.FINAL;
1.1631 + if ((f.getModifiers() & mask) == mask) {
1.1632 + f.setAccessible(true);
1.1633 + return Long.valueOf(f.getLong(null));
1.1634 + }
1.1635 + } catch (Exception ex) {
1.1636 + }
1.1637 + return null;
1.1638 + }
1.1639 +
1.1640 + /**
1.1641 + * Computes the default serial version UID value for the given class.
1.1642 + */
1.1643 + private static long computeDefaultSUID(Class<?> cl) {
1.1644 + if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
1.1645 + {
1.1646 + return 0L;
1.1647 + }
1.1648 +
1.1649 + try {
1.1650 + ByteArrayOutputStream bout = new ByteArrayOutputStream();
1.1651 + DataOutputStream dout = new DataOutputStream(bout);
1.1652 +
1.1653 + dout.writeUTF(cl.getName());
1.1654 +
1.1655 + int classMods = cl.getModifiers() &
1.1656 + (Modifier.PUBLIC | Modifier.FINAL |
1.1657 + Modifier.INTERFACE | Modifier.ABSTRACT);
1.1658 +
1.1659 + /*
1.1660 + * compensate for javac bug in which ABSTRACT bit was set for an
1.1661 + * interface only if the interface declared methods
1.1662 + */
1.1663 + Method[] methods = cl.getDeclaredMethods();
1.1664 + if ((classMods & Modifier.INTERFACE) != 0) {
1.1665 + classMods = (methods.length > 0) ?
1.1666 + (classMods | Modifier.ABSTRACT) :
1.1667 + (classMods & ~Modifier.ABSTRACT);
1.1668 + }
1.1669 + dout.writeInt(classMods);
1.1670 +
1.1671 + if (!cl.isArray()) {
1.1672 + /*
1.1673 + * compensate for change in 1.2FCS in which
1.1674 + * Class.getInterfaces() was modified to return Cloneable and
1.1675 + * Serializable for array classes.
1.1676 + */
1.1677 + Class<?>[] interfaces = cl.getInterfaces();
1.1678 + String[] ifaceNames = new String[interfaces.length];
1.1679 + for (int i = 0; i < interfaces.length; i++) {
1.1680 + ifaceNames[i] = interfaces[i].getName();
1.1681 + }
1.1682 + Arrays.sort(ifaceNames);
1.1683 + for (int i = 0; i < ifaceNames.length; i++) {
1.1684 + dout.writeUTF(ifaceNames[i]);
1.1685 + }
1.1686 + }
1.1687 +
1.1688 + Field[] fields = cl.getDeclaredFields();
1.1689 + MemberSignature[] fieldSigs = new MemberSignature[fields.length];
1.1690 + for (int i = 0; i < fields.length; i++) {
1.1691 + fieldSigs[i] = new MemberSignature(fields[i]);
1.1692 + }
1.1693 + Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
1.1694 + public int compare(MemberSignature ms1, MemberSignature ms2) {
1.1695 + return ms1.name.compareTo(ms2.name);
1.1696 + }
1.1697 + });
1.1698 + for (int i = 0; i < fieldSigs.length; i++) {
1.1699 + MemberSignature sig = fieldSigs[i];
1.1700 + int mods = sig.member.getModifiers() &
1.1701 + (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1.1702 + Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
1.1703 + Modifier.TRANSIENT);
1.1704 + if (((mods & Modifier.PRIVATE) == 0) ||
1.1705 + ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
1.1706 + {
1.1707 + dout.writeUTF(sig.name);
1.1708 + dout.writeInt(mods);
1.1709 + dout.writeUTF(sig.signature);
1.1710 + }
1.1711 + }
1.1712 +
1.1713 + if (hasStaticInitializer(cl)) {
1.1714 + dout.writeUTF("<clinit>");
1.1715 + dout.writeInt(Modifier.STATIC);
1.1716 + dout.writeUTF("()V");
1.1717 + }
1.1718 +
1.1719 + Constructor[] cons = cl.getDeclaredConstructors();
1.1720 + MemberSignature[] consSigs = new MemberSignature[cons.length];
1.1721 + for (int i = 0; i < cons.length; i++) {
1.1722 + consSigs[i] = new MemberSignature(cons[i]);
1.1723 + }
1.1724 + Arrays.sort(consSigs, new Comparator<MemberSignature>() {
1.1725 + public int compare(MemberSignature ms1, MemberSignature ms2) {
1.1726 + return ms1.signature.compareTo(ms2.signature);
1.1727 + }
1.1728 + });
1.1729 + for (int i = 0; i < consSigs.length; i++) {
1.1730 + MemberSignature sig = consSigs[i];
1.1731 + int mods = sig.member.getModifiers() &
1.1732 + (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1.1733 + Modifier.STATIC | Modifier.FINAL |
1.1734 + Modifier.SYNCHRONIZED | Modifier.NATIVE |
1.1735 + Modifier.ABSTRACT | Modifier.STRICT);
1.1736 + if ((mods & Modifier.PRIVATE) == 0) {
1.1737 + dout.writeUTF("<init>");
1.1738 + dout.writeInt(mods);
1.1739 + dout.writeUTF(sig.signature.replace('/', '.'));
1.1740 + }
1.1741 + }
1.1742 +
1.1743 + MemberSignature[] methSigs = new MemberSignature[methods.length];
1.1744 + for (int i = 0; i < methods.length; i++) {
1.1745 + methSigs[i] = new MemberSignature(methods[i]);
1.1746 + }
1.1747 + Arrays.sort(methSigs, new Comparator<MemberSignature>() {
1.1748 + public int compare(MemberSignature ms1, MemberSignature ms2) {
1.1749 + int comp = ms1.name.compareTo(ms2.name);
1.1750 + if (comp == 0) {
1.1751 + comp = ms1.signature.compareTo(ms2.signature);
1.1752 + }
1.1753 + return comp;
1.1754 + }
1.1755 + });
1.1756 + for (int i = 0; i < methSigs.length; i++) {
1.1757 + MemberSignature sig = methSigs[i];
1.1758 + int mods = sig.member.getModifiers() &
1.1759 + (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1.1760 + Modifier.STATIC | Modifier.FINAL |
1.1761 + Modifier.SYNCHRONIZED | Modifier.NATIVE |
1.1762 + Modifier.ABSTRACT | Modifier.STRICT);
1.1763 + if ((mods & Modifier.PRIVATE) == 0) {
1.1764 + dout.writeUTF(sig.name);
1.1765 + dout.writeInt(mods);
1.1766 + dout.writeUTF(sig.signature.replace('/', '.'));
1.1767 + }
1.1768 + }
1.1769 +
1.1770 + dout.flush();
1.1771 +
1.1772 + MessageDigest md = MessageDigest.getInstance("SHA");
1.1773 + byte[] hashBytes = md.digest(bout.toByteArray());
1.1774 + long hash = 0;
1.1775 + for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
1.1776 + hash = (hash << 8) | (hashBytes[i] & 0xFF);
1.1777 + }
1.1778 + return hash;
1.1779 + } catch (IOException ex) {
1.1780 + throw new InternalError();
1.1781 + } catch (NoSuchAlgorithmException ex) {
1.1782 + throw new SecurityException(ex.getMessage());
1.1783 + }
1.1784 + }
1.1785 +
1.1786 + /**
1.1787 + * Returns true if the given class defines a static initializer method,
1.1788 + * false otherwise.
1.1789 + */
1.1790 + private native static boolean hasStaticInitializer(Class<?> cl);
1.1791 +
1.1792 + /**
1.1793 + * Class for computing and caching field/constructor/method signatures
1.1794 + * during serialVersionUID calculation.
1.1795 + */
1.1796 + private static class MemberSignature {
1.1797 +
1.1798 + public final Member member;
1.1799 + public final String name;
1.1800 + public final String signature;
1.1801 +
1.1802 + public MemberSignature(Field field) {
1.1803 + member = field;
1.1804 + name = field.getName();
1.1805 + signature = getClassSignature(field.getType());
1.1806 + }
1.1807 +
1.1808 + public MemberSignature(Constructor cons) {
1.1809 + member = cons;
1.1810 + name = cons.getName();
1.1811 + signature = getMethodSignature(
1.1812 + cons.getParameterTypes(), Void.TYPE);
1.1813 + }
1.1814 +
1.1815 + public MemberSignature(Method meth) {
1.1816 + member = meth;
1.1817 + name = meth.getName();
1.1818 + signature = getMethodSignature(
1.1819 + meth.getParameterTypes(), meth.getReturnType());
1.1820 + }
1.1821 + }
1.1822 +
1.1823 + /**
1.1824 + * Class for setting and retrieving serializable field values in batch.
1.1825 + */
1.1826 + // REMIND: dynamically generate these?
1.1827 + private static class FieldReflector {
1.1828 +
1.1829 + /** handle for performing unsafe operations */
1.1830 + private static final Unsafe unsafe = Unsafe.getUnsafe();
1.1831 +
1.1832 + /** fields to operate on */
1.1833 + private final ObjectStreamField[] fields;
1.1834 + /** number of primitive fields */
1.1835 + private final int numPrimFields;
1.1836 + /** unsafe field keys for reading fields - may contain dupes */
1.1837 + private final long[] readKeys;
1.1838 + /** unsafe fields keys for writing fields - no dupes */
1.1839 + private final long[] writeKeys;
1.1840 + /** field data offsets */
1.1841 + private final int[] offsets;
1.1842 + /** field type codes */
1.1843 + private final char[] typeCodes;
1.1844 + /** field types */
1.1845 + private final Class<?>[] types;
1.1846 +
1.1847 + /**
1.1848 + * Constructs FieldReflector capable of setting/getting values from the
1.1849 + * subset of fields whose ObjectStreamFields contain non-null
1.1850 + * reflective Field objects. ObjectStreamFields with null Fields are
1.1851 + * treated as filler, for which get operations return default values
1.1852 + * and set operations discard given values.
1.1853 + */
1.1854 + FieldReflector(ObjectStreamField[] fields) {
1.1855 + this.fields = fields;
1.1856 + int nfields = fields.length;
1.1857 + readKeys = new long[nfields];
1.1858 + writeKeys = new long[nfields];
1.1859 + offsets = new int[nfields];
1.1860 + typeCodes = new char[nfields];
1.1861 + ArrayList<Class<?>> typeList = new ArrayList<>();
1.1862 + Set<Long> usedKeys = new HashSet<>();
1.1863 +
1.1864 +
1.1865 + for (int i = 0; i < nfields; i++) {
1.1866 + ObjectStreamField f = fields[i];
1.1867 + Field rf = f.getField();
1.1868 + long key = (rf != null) ?
1.1869 + unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
1.1870 + readKeys[i] = key;
1.1871 + writeKeys[i] = usedKeys.add(key) ?
1.1872 + key : Unsafe.INVALID_FIELD_OFFSET;
1.1873 + offsets[i] = f.getOffset();
1.1874 + typeCodes[i] = f.getTypeCode();
1.1875 + if (!f.isPrimitive()) {
1.1876 + typeList.add((rf != null) ? rf.getType() : null);
1.1877 + }
1.1878 + }
1.1879 +
1.1880 + types = typeList.toArray(new Class<?>[typeList.size()]);
1.1881 + numPrimFields = nfields - types.length;
1.1882 + }
1.1883 +
1.1884 + /**
1.1885 + * Returns list of ObjectStreamFields representing fields operated on
1.1886 + * by this reflector. The shared/unshared values and Field objects
1.1887 + * contained by ObjectStreamFields in the list reflect their bindings
1.1888 + * to locally defined serializable fields.
1.1889 + */
1.1890 + ObjectStreamField[] getFields() {
1.1891 + return fields;
1.1892 + }
1.1893 +
1.1894 + /**
1.1895 + * Fetches the serializable primitive field values of object obj and
1.1896 + * marshals them into byte array buf starting at offset 0. The caller
1.1897 + * is responsible for ensuring that obj is of the proper type.
1.1898 + */
1.1899 + void getPrimFieldValues(Object obj, byte[] buf) {
1.1900 + if (obj == null) {
1.1901 + throw new NullPointerException();
1.1902 + }
1.1903 + /* assuming checkDefaultSerialize() has been called on the class
1.1904 + * descriptor this FieldReflector was obtained from, no field keys
1.1905 + * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
1.1906 + */
1.1907 + for (int i = 0; i < numPrimFields; i++) {
1.1908 + long key = readKeys[i];
1.1909 + int off = offsets[i];
1.1910 + switch (typeCodes[i]) {
1.1911 + case 'Z':
1.1912 + Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key));
1.1913 + break;
1.1914 +
1.1915 + case 'B':
1.1916 + buf[off] = unsafe.getByte(obj, key);
1.1917 + break;
1.1918 +
1.1919 + case 'C':
1.1920 + Bits.putChar(buf, off, unsafe.getChar(obj, key));
1.1921 + break;
1.1922 +
1.1923 + case 'S':
1.1924 + Bits.putShort(buf, off, unsafe.getShort(obj, key));
1.1925 + break;
1.1926 +
1.1927 + case 'I':
1.1928 + Bits.putInt(buf, off, unsafe.getInt(obj, key));
1.1929 + break;
1.1930 +
1.1931 + case 'F':
1.1932 + Bits.putFloat(buf, off, unsafe.getFloat(obj, key));
1.1933 + break;
1.1934 +
1.1935 + case 'J':
1.1936 + Bits.putLong(buf, off, unsafe.getLong(obj, key));
1.1937 + break;
1.1938 +
1.1939 + case 'D':
1.1940 + Bits.putDouble(buf, off, unsafe.getDouble(obj, key));
1.1941 + break;
1.1942 +
1.1943 + default:
1.1944 + throw new InternalError();
1.1945 + }
1.1946 + }
1.1947 + }
1.1948 +
1.1949 + /**
1.1950 + * Sets the serializable primitive fields of object obj using values
1.1951 + * unmarshalled from byte array buf starting at offset 0. The caller
1.1952 + * is responsible for ensuring that obj is of the proper type.
1.1953 + */
1.1954 + void setPrimFieldValues(Object obj, byte[] buf) {
1.1955 + if (obj == null) {
1.1956 + throw new NullPointerException();
1.1957 + }
1.1958 + for (int i = 0; i < numPrimFields; i++) {
1.1959 + long key = writeKeys[i];
1.1960 + if (key == Unsafe.INVALID_FIELD_OFFSET) {
1.1961 + continue; // discard value
1.1962 + }
1.1963 + int off = offsets[i];
1.1964 + switch (typeCodes[i]) {
1.1965 + case 'Z':
1.1966 + unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off));
1.1967 + break;
1.1968 +
1.1969 + case 'B':
1.1970 + unsafe.putByte(obj, key, buf[off]);
1.1971 + break;
1.1972 +
1.1973 + case 'C':
1.1974 + unsafe.putChar(obj, key, Bits.getChar(buf, off));
1.1975 + break;
1.1976 +
1.1977 + case 'S':
1.1978 + unsafe.putShort(obj, key, Bits.getShort(buf, off));
1.1979 + break;
1.1980 +
1.1981 + case 'I':
1.1982 + unsafe.putInt(obj, key, Bits.getInt(buf, off));
1.1983 + break;
1.1984 +
1.1985 + case 'F':
1.1986 + unsafe.putFloat(obj, key, Bits.getFloat(buf, off));
1.1987 + break;
1.1988 +
1.1989 + case 'J':
1.1990 + unsafe.putLong(obj, key, Bits.getLong(buf, off));
1.1991 + break;
1.1992 +
1.1993 + case 'D':
1.1994 + unsafe.putDouble(obj, key, Bits.getDouble(buf, off));
1.1995 + break;
1.1996 +
1.1997 + default:
1.1998 + throw new InternalError();
1.1999 + }
1.2000 + }
1.2001 + }
1.2002 +
1.2003 + /**
1.2004 + * Fetches the serializable object field values of object obj and
1.2005 + * stores them in array vals starting at offset 0. The caller is
1.2006 + * responsible for ensuring that obj is of the proper type.
1.2007 + */
1.2008 + void getObjFieldValues(Object obj, Object[] vals) {
1.2009 + if (obj == null) {
1.2010 + throw new NullPointerException();
1.2011 + }
1.2012 + /* assuming checkDefaultSerialize() has been called on the class
1.2013 + * descriptor this FieldReflector was obtained from, no field keys
1.2014 + * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
1.2015 + */
1.2016 + for (int i = numPrimFields; i < fields.length; i++) {
1.2017 + switch (typeCodes[i]) {
1.2018 + case 'L':
1.2019 + case '[':
1.2020 + vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]);
1.2021 + break;
1.2022 +
1.2023 + default:
1.2024 + throw new InternalError();
1.2025 + }
1.2026 + }
1.2027 + }
1.2028 +
1.2029 + /**
1.2030 + * Sets the serializable object fields of object obj using values from
1.2031 + * array vals starting at offset 0. The caller is responsible for
1.2032 + * ensuring that obj is of the proper type; however, attempts to set a
1.2033 + * field with a value of the wrong type will trigger an appropriate
1.2034 + * ClassCastException.
1.2035 + */
1.2036 + void setObjFieldValues(Object obj, Object[] vals) {
1.2037 + if (obj == null) {
1.2038 + throw new NullPointerException();
1.2039 + }
1.2040 + for (int i = numPrimFields; i < fields.length; i++) {
1.2041 + long key = writeKeys[i];
1.2042 + if (key == Unsafe.INVALID_FIELD_OFFSET) {
1.2043 + continue; // discard value
1.2044 + }
1.2045 + switch (typeCodes[i]) {
1.2046 + case 'L':
1.2047 + case '[':
1.2048 + Object val = vals[offsets[i]];
1.2049 + if (val != null &&
1.2050 + !types[i - numPrimFields].isInstance(val))
1.2051 + {
1.2052 + Field f = fields[i].getField();
1.2053 + throw new ClassCastException(
1.2054 + "cannot assign instance of " +
1.2055 + val.getClass().getName() + " to field " +
1.2056 + f.getDeclaringClass().getName() + "." +
1.2057 + f.getName() + " of type " +
1.2058 + f.getType().getName() + " in instance of " +
1.2059 + obj.getClass().getName());
1.2060 + }
1.2061 + unsafe.putObject(obj, key, val);
1.2062 + break;
1.2063 +
1.2064 + default:
1.2065 + throw new InternalError();
1.2066 + }
1.2067 + }
1.2068 + }
1.2069 + }
1.2070 +
1.2071 + /**
1.2072 + * Matches given set of serializable fields with serializable fields
1.2073 + * described by the given local class descriptor, and returns a
1.2074 + * FieldReflector instance capable of setting/getting values from the
1.2075 + * subset of fields that match (non-matching fields are treated as filler,
1.2076 + * for which get operations return default values and set operations
1.2077 + * discard given values). Throws InvalidClassException if unresolvable
1.2078 + * type conflicts exist between the two sets of fields.
1.2079 + */
1.2080 + private static FieldReflector getReflector(ObjectStreamField[] fields,
1.2081 + ObjectStreamClass localDesc)
1.2082 + throws InvalidClassException
1.2083 + {
1.2084 + // class irrelevant if no fields
1.2085 + Class<?> cl = (localDesc != null && fields.length > 0) ?
1.2086 + localDesc.cl : null;
1.2087 + processQueue(Caches.reflectorsQueue, Caches.reflectors);
1.2088 + FieldReflectorKey key = new FieldReflectorKey(cl, fields,
1.2089 + Caches.reflectorsQueue);
1.2090 + Reference<?> ref = Caches.reflectors.get(key);
1.2091 + Object entry = null;
1.2092 + if (ref != null) {
1.2093 + entry = ref.get();
1.2094 + }
1.2095 + EntryFuture future = null;
1.2096 + if (entry == null) {
1.2097 + EntryFuture newEntry = new EntryFuture();
1.2098 + Reference<?> newRef = new SoftReference<>(newEntry);
1.2099 + do {
1.2100 + if (ref != null) {
1.2101 + Caches.reflectors.remove(key, ref);
1.2102 + }
1.2103 + ref = Caches.reflectors.putIfAbsent(key, newRef);
1.2104 + if (ref != null) {
1.2105 + entry = ref.get();
1.2106 + }
1.2107 + } while (ref != null && entry == null);
1.2108 + if (entry == null) {
1.2109 + future = newEntry;
1.2110 + }
1.2111 + }
1.2112 +
1.2113 + if (entry instanceof FieldReflector) { // check common case first
1.2114 + return (FieldReflector) entry;
1.2115 + } else if (entry instanceof EntryFuture) {
1.2116 + entry = ((EntryFuture) entry).get();
1.2117 + } else if (entry == null) {
1.2118 + try {
1.2119 + entry = new FieldReflector(matchFields(fields, localDesc));
1.2120 + } catch (Throwable th) {
1.2121 + entry = th;
1.2122 + }
1.2123 + future.set(entry);
1.2124 + Caches.reflectors.put(key, new SoftReference<Object>(entry));
1.2125 + }
1.2126 +
1.2127 + if (entry instanceof FieldReflector) {
1.2128 + return (FieldReflector) entry;
1.2129 + } else if (entry instanceof InvalidClassException) {
1.2130 + throw (InvalidClassException) entry;
1.2131 + } else if (entry instanceof RuntimeException) {
1.2132 + throw (RuntimeException) entry;
1.2133 + } else if (entry instanceof Error) {
1.2134 + throw (Error) entry;
1.2135 + } else {
1.2136 + throw new InternalError("unexpected entry: " + entry);
1.2137 + }
1.2138 + }
1.2139 +
1.2140 + /**
1.2141 + * FieldReflector cache lookup key. Keys are considered equal if they
1.2142 + * refer to the same class and equivalent field formats.
1.2143 + */
1.2144 + private static class FieldReflectorKey extends WeakReference<Class<?>> {
1.2145 +
1.2146 + private final String sigs;
1.2147 + private final int hash;
1.2148 + private final boolean nullClass;
1.2149 +
1.2150 + FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields,
1.2151 + ReferenceQueue<Class<?>> queue)
1.2152 + {
1.2153 + super(cl, queue);
1.2154 + nullClass = (cl == null);
1.2155 + StringBuilder sbuf = new StringBuilder();
1.2156 + for (int i = 0; i < fields.length; i++) {
1.2157 + ObjectStreamField f = fields[i];
1.2158 + sbuf.append(f.getName()).append(f.getSignature());
1.2159 + }
1.2160 + sigs = sbuf.toString();
1.2161 + hash = System.identityHashCode(cl) + sigs.hashCode();
1.2162 + }
1.2163 +
1.2164 + public int hashCode() {
1.2165 + return hash;
1.2166 + }
1.2167 +
1.2168 + public boolean equals(Object obj) {
1.2169 + if (obj == this) {
1.2170 + return true;
1.2171 + }
1.2172 +
1.2173 + if (obj instanceof FieldReflectorKey) {
1.2174 + FieldReflectorKey other = (FieldReflectorKey) obj;
1.2175 + Class<?> referent;
1.2176 + return (nullClass ? other.nullClass
1.2177 + : ((referent = get()) != null) &&
1.2178 + (referent == other.get())) &&
1.2179 + sigs.equals(other.sigs);
1.2180 + } else {
1.2181 + return false;
1.2182 + }
1.2183 + }
1.2184 + }
1.2185 +
1.2186 + /**
1.2187 + * Matches given set of serializable fields with serializable fields
1.2188 + * obtained from the given local class descriptor (which contain bindings
1.2189 + * to reflective Field objects). Returns list of ObjectStreamFields in
1.2190 + * which each ObjectStreamField whose signature matches that of a local
1.2191 + * field contains a Field object for that field; unmatched
1.2192 + * ObjectStreamFields contain null Field objects. Shared/unshared settings
1.2193 + * of the returned ObjectStreamFields also reflect those of matched local
1.2194 + * ObjectStreamFields. Throws InvalidClassException if unresolvable type
1.2195 + * conflicts exist between the two sets of fields.
1.2196 + */
1.2197 + private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
1.2198 + ObjectStreamClass localDesc)
1.2199 + throws InvalidClassException
1.2200 + {
1.2201 + ObjectStreamField[] localFields = (localDesc != null) ?
1.2202 + localDesc.fields : NO_FIELDS;
1.2203 +
1.2204 + /*
1.2205 + * Even if fields == localFields, we cannot simply return localFields
1.2206 + * here. In previous implementations of serialization,
1.2207 + * ObjectStreamField.getType() returned Object.class if the
1.2208 + * ObjectStreamField represented a non-primitive field and belonged to
1.2209 + * a non-local class descriptor. To preserve this (questionable)
1.2210 + * behavior, the ObjectStreamField instances returned by matchFields
1.2211 + * cannot report non-primitive types other than Object.class; hence
1.2212 + * localFields cannot be returned directly.
1.2213 + */
1.2214 +
1.2215 + ObjectStreamField[] matches = new ObjectStreamField[fields.length];
1.2216 + for (int i = 0; i < fields.length; i++) {
1.2217 + ObjectStreamField f = fields[i], m = null;
1.2218 + for (int j = 0; j < localFields.length; j++) {
1.2219 + ObjectStreamField lf = localFields[j];
1.2220 + if (f.getName().equals(lf.getName())) {
1.2221 + if ((f.isPrimitive() || lf.isPrimitive()) &&
1.2222 + f.getTypeCode() != lf.getTypeCode())
1.2223 + {
1.2224 + throw new InvalidClassException(localDesc.name,
1.2225 + "incompatible types for field " + f.getName());
1.2226 + }
1.2227 + if (lf.getField() != null) {
1.2228 + m = new ObjectStreamField(
1.2229 + lf.getField(), lf.isUnshared(), false);
1.2230 + } else {
1.2231 + m = new ObjectStreamField(
1.2232 + lf.getName(), lf.getSignature(), lf.isUnshared());
1.2233 + }
1.2234 + }
1.2235 + }
1.2236 + if (m == null) {
1.2237 + m = new ObjectStreamField(
1.2238 + f.getName(), f.getSignature(), false);
1.2239 + }
1.2240 + m.setOffset(f.getOffset());
1.2241 + matches[i] = m;
1.2242 + }
1.2243 + return matches;
1.2244 + }
1.2245 +
1.2246 + /**
1.2247 + * Removes from the specified map any keys that have been enqueued
1.2248 + * on the specified reference queue.
1.2249 + */
1.2250 + static void processQueue(ReferenceQueue<Class<?>> queue,
1.2251 + ConcurrentMap<? extends
1.2252 + WeakReference<Class<?>>, ?> map)
1.2253 + {
1.2254 + Reference<? extends Class<?>> ref;
1.2255 + while((ref = queue.poll()) != null) {
1.2256 + map.remove(ref);
1.2257 + }
1.2258 + }
1.2259 +
1.2260 + /**
1.2261 + * Weak key for Class objects.
1.2262 + *
1.2263 + **/
1.2264 + static class WeakClassKey extends WeakReference<Class<?>> {
1.2265 + /**
1.2266 + * saved value of the referent's identity hash code, to maintain
1.2267 + * a consistent hash code after the referent has been cleared
1.2268 + */
1.2269 + private final int hash;
1.2270 +
1.2271 + /**
1.2272 + * Create a new WeakClassKey to the given object, registered
1.2273 + * with a queue.
1.2274 + */
1.2275 + WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
1.2276 + super(cl, refQueue);
1.2277 + hash = System.identityHashCode(cl);
1.2278 + }
1.2279 +
1.2280 + /**
1.2281 + * Returns the identity hash code of the original referent.
1.2282 + */
1.2283 + public int hashCode() {
1.2284 + return hash;
1.2285 + }
1.2286 +
1.2287 + /**
1.2288 + * Returns true if the given object is this identical
1.2289 + * WeakClassKey instance, or, if this object's referent has not
1.2290 + * been cleared, if the given object is another WeakClassKey
1.2291 + * instance with the identical non-null referent as this one.
1.2292 + */
1.2293 + public boolean equals(Object obj) {
1.2294 + if (obj == this) {
1.2295 + return true;
1.2296 + }
1.2297 +
1.2298 + if (obj instanceof WeakClassKey) {
1.2299 + Object referent = get();
1.2300 + return (referent != null) &&
1.2301 + (referent == ((WeakClassKey) obj).get());
1.2302 + } else {
1.2303 + return false;
1.2304 + }
1.2305 + }
1.2306 + }
1.2307 +}