Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jboss.marshalling.river.RiverMarshaller Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.marshalling.river;
import static java.lang.System.getSecurityManager;
import static java.security.AccessController.doPrivileged;
import static org.jboss.marshalling.river.Protocol.*;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.NotSerializableException;
import java.io.ObjectOutput;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.AbstractQueue;
import java.util.AbstractSequentialList;
import java.util.AbstractSet;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import org.jboss.marshalling.AbstractMarshaller;
import org.jboss.marshalling.ByteOutput;
import org.jboss.marshalling.ClassExternalizerFactory;
import org.jboss.marshalling.ClassTable;
import org.jboss.marshalling.Externalizer;
import org.jboss.marshalling.MarshallingConfiguration;
import org.jboss.marshalling.ObjectResolver;
import org.jboss.marshalling.ObjectTable;
import org.jboss.marshalling.Pair;
import org.jboss.marshalling.TraceInformation;
import org.jboss.marshalling.UTFUtils;
import org.jboss.marshalling._private.GetDeclaredFieldAction;
import org.jboss.marshalling.reflect.SerializableClass;
import org.jboss.marshalling.reflect.SerializableClassRegistry;
import org.jboss.marshalling.reflect.SerializableField;
import org.jboss.marshalling.util.IdentityIntMap;
import org.jboss.marshalling.util.Kind;
/**
*
*/
public class RiverMarshaller extends AbstractMarshaller {
private final IdentityIntMap instanceCache;
private final IdentityIntMap> classCache;
private final IdentityIntMap> serialClassCache;
private final IdentityHashMap, Externalizer> externalizers;
private int instanceSeq;
private int classSeq;
private final SerializableClassRegistry registry;
private RiverObjectOutputStream objectOutputStream;
private ObjectOutput objectOutput;
private BlockMarshaller blockMarshaller;
protected RiverMarshaller(final RiverMarshallerFactory marshallerFactory, final SerializableClassRegistry registry, final MarshallingConfiguration configuration) throws IOException {
super(marshallerFactory, configuration);
final int configuredVersion = this.configuredVersion;
if (configuredVersion < MIN_VERSION || configuredVersion > MAX_VERSION) {
throw new IOException("Unsupported protocol version " + configuredVersion);
}
this.registry = registry;
final float loadFactor = 0x0.5p0f;
instanceCache = new IdentityIntMap((int) ((double)configuration.getInstanceCount() / (double)loadFactor), loadFactor);
classCache = new IdentityIntMap>((int) ((double)configuration.getClassCount() / (double)loadFactor), loadFactor);
serialClassCache = new IdentityIntMap>((int) ((double)configuration.getClassCount() / (double)loadFactor), loadFactor);
externalizers = new IdentityHashMap, Externalizer>(configuration.getClassCount());
}
protected void doWriteObject(final Object original, final boolean unshared) throws IOException {
final ClassExternalizerFactory classExternalizerFactory = this.classExternalizerFactory;
final ObjectResolver objectResolver = this.objectResolver;
final ObjectResolver objectPreResolver = this.objectPreResolver;
Object obj = original;
Class> objClass;
int id;
boolean isArray, isEnum;
SerializableClass info;
boolean unreplaced = true;
final int configuredVersion = this.configuredVersion;
try {
for (;;) {
if (obj == null) {
write(ID_NULL);
return;
}
final int rid;
if (! unshared && (rid = instanceCache.get(obj, -1)) != -1) {
final int diff = rid - instanceSeq;
if (diff >= -256) {
write(ID_REPEAT_OBJECT_NEAR);
write(diff);
} else if (diff >= -65536) {
write(ID_REPEAT_OBJECT_NEARISH);
writeShort(diff);
} else {
write(ID_REPEAT_OBJECT_FAR);
writeInt(rid);
}
return;
}
// Check for a global pre replacement, before any user replacement is called
obj = objectPreResolver.writeReplace(obj);
final ObjectTable.Writer objectTableWriter;
if (! unshared && (objectTableWriter = objectTable.getObjectWriter(obj)) != null) {
write(ID_PREDEFINED_OBJECT);
if (configuredVersion == 1) {
objectTableWriter.writeObject(getBlockMarshaller(), obj);
writeEndBlock();
} else {
objectTableWriter.writeObject(this, obj);
}
return;
}
objClass = obj.getClass();
id = getBasicClasses(configuredVersion).get(objClass, -1);
// First, non-replaceable classes
if (id == ID_CLASS_CLASS) {
final Class> classObj = (Class>) obj;
// If a class is one we have an entry for, we just write that byte directly.
// These guys can't be written directly though, otherwise they'll get confused with the objects
// of the corresponding type.
final int cid = BASIC_CLASSES_V2.get(classObj, -1);
switch (cid) {
case -1:
case ID_SINGLETON_MAP_OBJECT:
case ID_SINGLETON_SET_OBJECT:
case ID_SINGLETON_LIST_OBJECT:
case ID_EMPTY_MAP_OBJECT:
case ID_EMPTY_SET_OBJECT:
case ID_EMPTY_LIST_OBJECT: {
// If the class is one of the above special object types, then we write a
// full NEW_OBJECT+CLASS_CLASS header followed by the class byte, or if there is none, write
// the full class descriptor.
write(ID_NEW_OBJECT);
writeClassClass(classObj);
return;
}
default: {
write(cid);
return;
}
}
// not reached
}
isEnum = obj instanceof Enum;
isArray = objClass.isArray();
// objects with id != -1 will never make use of the "info" param in *any* way
info = isArray || isEnum || id != -1 ? null : registry.lookup(objClass);
// replace once - objects with id != -1 will not have replacement methods but might be globally replaced
if (unreplaced) {
if (info != null) {
// check for a user replacement
if (info.hasWriteReplace()) {
obj = info.callWriteReplace(obj);
}
}
// Check for a global replacement
obj = objectResolver.writeReplace(obj);
if (obj != original) {
unreplaced = false;
continue;
} else {
break;
}
} else {
break;
}
}
if (isEnum) {
// objClass cannot equal Enum.class because it is abstract
final Enum> theEnum = (Enum>) obj;
// enums are always shared
write(ID_NEW_OBJECT);
writeEnumClass(theEnum.getDeclaringClass());
writeString(theEnum.name());
instanceCache.put(obj, instanceSeq++);
return;
}
if (id != -1) {
if (id == ID_CC_COPY_ON_WRITE_ARRAY_LIST ||
id == ID_CC_COPY_ON_WRITE_ARRAY_SET) {
info = registry.lookup(objClass);
} else {
writeKnownObject(unshared, obj, objClass, id);
return;
}
}
if (isArray) {
writeArrayObject(unshared, obj, objClass);
return;
}
// serialize proxies efficiently
if (obj instanceof Proxy) {
write(unshared ? ID_NEW_OBJECT_UNSHARED : ID_NEW_OBJECT);
writeProxyClass(objClass);
instanceCache.put(obj, instanceSeq++);
doWriteObject(Proxy.getInvocationHandler(obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
// it's a user type
// user type #1: externalizer
Externalizer externalizer;
if (externalizers.containsKey(objClass)) {
externalizer = externalizers.get(objClass);
} else {
externalizer = classExternalizerFactory.getExternalizer(objClass);
externalizers.put(objClass, externalizer);
}
if (externalizer != null) {
write(unshared ? ID_NEW_OBJECT_UNSHARED : ID_NEW_OBJECT);
writeExternalizerClass(objClass, externalizer);
instanceCache.put(obj, instanceSeq++);
final ObjectOutput objectOutput;
objectOutput = getObjectOutput();
externalizer.writeExternal(obj, objectOutput);
writeEndBlock();
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
// user type #2: externalizable
if (obj instanceof Externalizable) {
writeExternalizable(unshared, obj, objClass);
return;
}
// user type #3: serializable
if (serializabilityChecker.isSerializable(objClass)) {
write(unshared ? ID_NEW_OBJECT_UNSHARED : ID_NEW_OBJECT);
writeSerializableClass(objClass, false);
instanceCache.put(obj, instanceSeq++);
if (info != null && info.isRecord()) {
doWriteRecord(obj, info);
} else {
doWriteSerializableObject(info, obj, objClass);
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
throw new NotSerializableException(objClass.getName());
} finally {
if (! unreplaced && obj != original) {
final int replId = instanceCache.get(obj, -1);
if (replId != -1) {
instanceCache.put(original, replId);
}
}
}
}
private void writeExternalizable(boolean unshared, Object obj, Class> objClass) throws IOException {
write(unshared ? ID_NEW_OBJECT_UNSHARED : ID_NEW_OBJECT);
final Externalizable ext = (Externalizable) obj;
final ObjectOutput objectOutput = getObjectOutput();
writeExternalizableClass(objClass);
instanceCache.put(obj, instanceSeq++);
ext.writeExternal(objectOutput);
writeEndBlock();
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
private void writeArrayObject(boolean unshared, Object obj, Class> objClass) throws IOException {
final Object[] objects = (Object[]) obj;
final int len = objects.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
writeClass(objClass.getComponentType());
instanceCache.put(obj, instanceSeq++);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
writeClass(objClass.getComponentType());
instanceCache.put(obj, instanceSeq++);
for (int i = 0; i < len; i++) {
doWriteObject(objects[i], unshared);
}
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
writeClass(objClass.getComponentType());
instanceCache.put(obj, instanceSeq++);
for (int i = 0; i < len; i++) {
doWriteObject(objects[i], unshared);
}
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
writeClass(objClass.getComponentType());
instanceCache.put(obj, instanceSeq++);
for (int i = 0; i < len; i++) {
doWriteObject(objects[i], unshared);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
private void doWriteRecord(Object object, SerializableClass info) throws IOException {
final SerializableField[] serializableFields = info.getFields();
for (SerializableField serializableField : serializableFields) {
switch (serializableField.getKind()) {
case BOOLEAN:
writeBoolean((boolean) serializableField.getRecordComponentValue(object));
break;
case BYTE:
writeByte((byte) serializableField.getRecordComponentValue(object));
break;
case SHORT:
writeShort((short) serializableField.getRecordComponentValue(object));
break;
case INT:
writeInt((int) serializableField.getRecordComponentValue(object));
break;
case CHAR:
writeChar((char) serializableField.getRecordComponentValue(object));
break;
case LONG:
writeLong((long) serializableField.getRecordComponentValue(object));
break;
case DOUBLE:
writeDouble((double) serializableField.getRecordComponentValue(object));
break;
case FLOAT:
writeFloat((float) serializableField.getRecordComponentValue(object));
break;
case OBJECT:
doWriteObject(serializableField.getRecordComponentValue(object), serializableField.isUnshared());
break;
}
}
}
private void writeKnownObject(boolean unshared, Object obj, Class> objClass, int id) throws IOException {
// Now replaceable classes
switch (id) {
case ID_BYTE_CLASS: {
write(ID_BYTE_OBJECT);
writeByte(((Byte) obj).byteValue());
return;
}
case ID_BOOLEAN_CLASS: {
write(((Boolean) obj).booleanValue() ? ID_BOOLEAN_OBJECT_TRUE : ID_BOOLEAN_OBJECT_FALSE);
return;
}
case ID_CHARACTER_CLASS: {
write(ID_CHARACTER_OBJECT);
writeChar(((Character) obj).charValue());
return;
}
case ID_DOUBLE_CLASS: {
write(ID_DOUBLE_OBJECT);
writeDouble(((Double) obj).doubleValue());
return;
}
case ID_FLOAT_CLASS: {
write(ID_FLOAT_OBJECT);
writeFloat(((Float) obj).floatValue());
return;
}
case ID_INTEGER_CLASS: {
write(ID_INTEGER_OBJECT);
writeInt(((Integer) obj).intValue());
return;
}
case ID_LONG_CLASS: {
write(ID_LONG_OBJECT);
writeLong(((Long) obj).longValue());
return;
}
case ID_SHORT_CLASS: {
write(ID_SHORT_OBJECT);
writeShort(((Short) obj).shortValue());
return;
}
case ID_STRING_CLASS: {
final String string = (String) obj;
final int len = string.length();
if (len == 0) {
write(ID_STRING_EMPTY);
// don't cache empty strings
return;
} else if (len <= 0x100) {
write(ID_STRING_SMALL);
write(len);
} else if (len <= 0x10000) {
write(ID_STRING_MEDIUM);
writeShort(len);
} else {
write(ID_STRING_LARGE);
writeInt(len);
}
shallowFlush();
UTFUtils.writeUTFBytes(byteOutput, string);
if (unshared) {
instanceCache.put(obj, -1);
instanceSeq++;
} else {
instanceCache.put(obj, instanceSeq++);
}
return;
}
case ID_BYTE_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final byte[] bytes = (byte[]) obj;
final int len = bytes.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_BYTE);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_BYTE);
write(bytes, 0, len);
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_BYTE);
write(bytes, 0, len);
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_BYTE);
write(bytes, 0, len);
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_BOOLEAN_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final boolean[] booleans = (boolean[]) obj;
final int len = booleans.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_BOOLEAN);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_BOOLEAN);
writeBooleanArray(booleans);
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_BOOLEAN);
writeBooleanArray(booleans);
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_BOOLEAN);
writeBooleanArray(booleans);
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_CHAR_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final char[] chars = (char[]) obj;
final int len = chars.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_CHAR);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_CHAR);
for (int i = 0; i < len; i++) {
writeChar(chars[i]);
}
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_CHAR);
for (int i = 0; i < len; i++) {
writeChar(chars[i]);
}
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_CHAR);
for (int i = 0; i < len; i++) {
writeChar(chars[i]);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_SHORT_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final short[] shorts = (short[]) obj;
final int len = shorts.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_SHORT);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_SHORT);
for (int i = 0; i < len; i++) {
writeShort(shorts[i]);
}
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_SHORT);
for (int i = 0; i < len; i++) {
writeShort(shorts[i]);
}
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_SHORT);
for (int i = 0; i < len; i++) {
writeShort(shorts[i]);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_INT_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final int[] ints = (int[]) obj;
final int len = ints.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_INT);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_INT);
for (int i = 0; i < len; i++) {
writeInt(ints[i]);
}
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_INT);
for (int i = 0; i < len; i++) {
writeInt(ints[i]);
}
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_INT);
for (int i = 0; i < len; i++) {
writeInt(ints[i]);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_LONG_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final long[] longs = (long[]) obj;
final int len = longs.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_LONG);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_LONG);
for (int i = 0; i < len; i++) {
writeLong(longs[i]);
}
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_LONG);
for (int i = 0; i < len; i++) {
writeLong(longs[i]);
}
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_LONG);
for (int i = 0; i < len; i++) {
writeLong(longs[i]);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_FLOAT_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final float[] floats = (float[]) obj;
final int len = floats.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_FLOAT);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_FLOAT);
for (int i = 0; i < len; i++) {
writeFloat(floats[i]);
}
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_FLOAT);
for (int i = 0; i < len; i++) {
writeFloat(floats[i]);
}
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_FLOAT);
for (int i = 0; i < len; i++) {
writeFloat(floats[i]);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_DOUBLE_ARRAY_CLASS: {
if (!unshared) {
instanceCache.put(obj, instanceSeq++);
}
final double[] doubles = (double[]) obj;
final int len = doubles.length;
if (len == 0) {
write(unshared ? ID_ARRAY_EMPTY_UNSHARED : ID_ARRAY_EMPTY);
write(ID_PRIM_DOUBLE);
} else if (len <= 256) {
write(unshared ? ID_ARRAY_SMALL_UNSHARED : ID_ARRAY_SMALL);
write(len);
write(ID_PRIM_DOUBLE);
for (int i = 0; i < len; i++) {
writeDouble(doubles[i]);
}
} else if (len <= 65536) {
write(unshared ? ID_ARRAY_MEDIUM_UNSHARED : ID_ARRAY_MEDIUM);
writeShort(len);
write(ID_PRIM_DOUBLE);
for (int i = 0; i < len; i++) {
writeDouble(doubles[i]);
}
} else {
write(unshared ? ID_ARRAY_LARGE_UNSHARED : ID_ARRAY_LARGE);
writeInt(len);
write(ID_PRIM_DOUBLE);
for (int i = 0; i < len; i++) {
writeDouble(doubles[i]);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_CC_ARRAY_LIST:
case ID_CC_LINKED_LIST:
case ID_CC_ARRAY_DEQUE: {
instanceCache.put(obj, instanceSeq++);
final Collection> collection = (Collection>) obj;
final int len = collection.size();
if (len == 0) {
write(unshared ? ID_COLLECTION_EMPTY_UNSHARED : ID_COLLECTION_EMPTY);
write(id);
} else if (len <= 256) {
write(unshared ? ID_COLLECTION_SMALL_UNSHARED : ID_COLLECTION_SMALL);
write(len);
write(id);
for (Object o : collection) {
doWriteObject(o, false);
}
} else if (len <= 65536) {
write(unshared ? ID_COLLECTION_MEDIUM_UNSHARED : ID_COLLECTION_MEDIUM);
writeShort(len);
write(id);
for (Object o : collection) {
doWriteObject(o, false);
}
} else {
write(unshared ? ID_COLLECTION_LARGE_UNSHARED : ID_COLLECTION_LARGE);
writeInt(len);
write(id);
for (Object o : collection) {
doWriteObject(o, false);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_CC_VECTOR:
case ID_CC_STACK: {
instanceCache.put(obj, instanceSeq++);
final Collection> collection = (Collection>) obj;
synchronized (collection) {
final int len = collection.size();
if (len == 0) {
write(unshared ? ID_COLLECTION_EMPTY_UNSHARED : ID_COLLECTION_EMPTY);
write(id);
} else if (len <= 256) {
write(unshared ? ID_COLLECTION_SMALL_UNSHARED : ID_COLLECTION_SMALL);
write(len);
write(id);
for (Object o : collection) {
doWriteObject(o, false);
}
} else if (len <= 65536) {
write(unshared ? ID_COLLECTION_MEDIUM_UNSHARED : ID_COLLECTION_MEDIUM);
writeShort(len);
write(id);
for (Object o : collection) {
doWriteObject(o, false);
}
} else {
write(unshared ? ID_COLLECTION_LARGE_UNSHARED : ID_COLLECTION_LARGE);
writeInt(len);
write(id);
for (Object o : collection) {
doWriteObject(o, false);
}
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_CC_ENUM_SET_PROXY: {
final Enum[] elements = getEnumSetElements(obj);
final int len = elements.length;
if (len == 0) {
write(unshared ? ID_COLLECTION_EMPTY_UNSHARED : ID_COLLECTION_EMPTY);
write(id);
writeClass(getEnumSetElementType(obj));
instanceCache.put(obj, instanceSeq++);
} else if (len <= 256) {
write(unshared ? ID_COLLECTION_SMALL_UNSHARED : ID_COLLECTION_SMALL);
write(len);
write(id);
writeClass(getEnumSetElementType(obj));
instanceCache.put(obj, instanceSeq++);
for (Object o : elements) {
doWriteObject(o, false);
}
} else if (len <= 65536) {
write(unshared ? ID_COLLECTION_MEDIUM_UNSHARED : ID_COLLECTION_MEDIUM);
writeShort(len);
write(id);
writeClass(getEnumSetElementType(obj));
instanceCache.put(obj, instanceSeq++);
for (Object o : elements) {
doWriteObject(o, false);
}
} else {
write(unshared ? ID_COLLECTION_LARGE_UNSHARED : ID_COLLECTION_LARGE);
writeInt(len);
write(id);
writeClass(getEnumSetElementType(obj));
instanceCache.put(obj, instanceSeq++);
for (Object o : elements) {
doWriteObject(o, false);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_CC_IDENTITY_HASH_MAP:
case ID_CC_ENUM_MAP: {
instanceCache.put(obj, instanceSeq++);
final Map, ?> map = (Map, ?>) obj;
final int len = map.size();
if (len == 0) {
write(unshared ? ID_COLLECTION_EMPTY_UNSHARED : ID_COLLECTION_EMPTY);
write(id);
switch (id) {
case ID_CC_ENUM_MAP:
writeClass(getEnumMapKeyType(obj));
break;
}
} else if (len <= 256) {
write(unshared ? ID_COLLECTION_SMALL_UNSHARED : ID_COLLECTION_SMALL);
write(len);
write(id);
switch (id) {
case ID_CC_ENUM_MAP:
writeClass(getEnumMapKeyType(obj));
break;
}
for (Map.Entry, ?> entry : map.entrySet()) {
doWriteObject(entry.getKey(), false);
doWriteObject(entry.getValue(), false);
}
} else if (len <= 65536) {
write(unshared ? ID_COLLECTION_MEDIUM_UNSHARED : ID_COLLECTION_MEDIUM);
writeShort(len);
write(id);
switch (id) {
case ID_CC_ENUM_MAP:
writeClass(getEnumMapKeyType(obj));
break;
}
for (Map.Entry, ?> entry : map.entrySet()) {
doWriteObject(entry.getKey(), false);
doWriteObject(entry.getValue(), false);
}
} else {
write(unshared ? ID_COLLECTION_LARGE_UNSHARED : ID_COLLECTION_LARGE);
writeInt(len);
write(id);
switch (id) {
case ID_CC_ENUM_MAP:
writeClass(getEnumMapKeyType(obj));
break;
}
for (Map.Entry, ?> entry : map.entrySet()) {
doWriteObject(entry.getKey(), false);
doWriteObject(entry.getValue(), false);
}
}
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_EMPTY_MAP_OBJECT:
case ID_EMPTY_SET_OBJECT:
case ID_EMPTY_LIST_OBJECT:
case ID_REVERSE_ORDER_OBJECT: {
write(id);
return;
}
case ID_SINGLETON_MAP_OBJECT: {
instanceCache.put(obj, instanceSeq++);
write(id);
final Map.Entry entry = (Map.Entry) ((Map) obj).entrySet().iterator().next();
doWriteObject(entry.getKey(), false);
doWriteObject(entry.getValue(), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_SINGLETON_LIST_OBJECT:
case ID_SINGLETON_SET_OBJECT: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(((Collection) obj).iterator().next(), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_REVERSE_ORDER2_OBJECT: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(reverseOrder2Field, obj), false);
return;
}
case ID_PAIR: {
instanceCache.put(obj, instanceSeq++);
write(id);
Pair, ?> pair = (Pair, ?>) obj;
doWriteObject(pair.getA(), unshared);
doWriteObject(pair.getB(), unshared);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_CC_NCOPIES: {
List> list = (List>) obj;
int size = list.size();
if (size == 0) {
write(ID_EMPTY_LIST_OBJECT);
return;
}
instanceCache.put(obj, instanceSeq++);
if (size <= 256) {
write(unshared ? ID_COLLECTION_SMALL_UNSHARED : ID_COLLECTION_SMALL);
write(size);
} else if (size <= 65536) {
write(unshared ? ID_COLLECTION_MEDIUM_UNSHARED : ID_COLLECTION_MEDIUM);
writeShort(size);
} else {
write(unshared ? ID_COLLECTION_LARGE_UNSHARED : ID_COLLECTION_LARGE);
writeInt(size);
}
write(id);
doWriteObject(list.iterator().next(), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_UNMODIFIABLE_COLLECTION: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(unmodifiableCollectionField, obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_UNMODIFIABLE_SET: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(unmodifiableSetField, obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_UNMODIFIABLE_LIST: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(objClass == unmodifiableRandomAccessListClass ? unmodifiableRandomAccessListField : unmodifiableListField, obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_UNMODIFIABLE_MAP: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(unmodifiableMapField, obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_UNMODIFIABLE_SORTED_MAP: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(unmodifiableSortedMapField, obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_UNMODIFIABLE_SORTED_SET: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(unmodifiableSortedSetField, obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
case ID_UNMODIFIABLE_MAP_ENTRY_SET: {
instanceCache.put(obj, instanceSeq++);
write(id);
doWriteObject(Protocol.readField(unmodifiableMapEntrySetField, obj), false);
if (unshared) {
instanceCache.put(obj, -1);
}
return;
}
default:
throw new NotSerializableException(objClass.getName());
}
}
private static IdentityIntMap> getBasicClasses(final int configuredVersion) {
return configuredVersion == 2 ? BASIC_CLASSES_V2 : configuredVersion == 3 ? BASIC_CLASSES_V3 : BASIC_CLASSES_V4;
}
private static Class extends Enum> getEnumMapKeyType(final Object obj) {
return ((Class>) Protocol.readField(ENUM_MAP_KEY_TYPE_FIELD, obj)).asSubclass(Enum.class);
}
private static Class extends Enum> getEnumSetElementType(final Object obj) {
return ((Class>) Protocol.readField(ENUM_SET_ELEMENT_TYPE_FIELD, obj)).asSubclass(Enum.class);
}
private static Enum[] getEnumSetElements(final Object obj) {
return (Enum[]) Protocol.readField(ENUM_SET_VALUES_FIELD, obj);
}
private void writeBooleanArray(final boolean[] booleans) throws IOException {
final int len = booleans.length;
final int bc = len & ~7;
for (int i = 0; i < bc;) {
write(
(booleans[i++] ? 1 : 0)
| (booleans[i++] ? 2 : 0)
| (booleans[i++] ? 4 : 0)
| (booleans[i++] ? 8 : 0)
| (booleans[i++] ? 16 : 0)
| (booleans[i++] ? 32 : 0)
| (booleans[i++] ? 64 : 0)
| (booleans[i++] ? 128 : 0)
);
}
if (bc < len) {
int out = 0;
int bit = 1;
for (int i = bc; i < len; i++) {
if (booleans[i]) out |= bit;
bit <<= 1;
}
write(out);
}
}
private void writeEndBlock() throws IOException {
final BlockMarshaller blockMarshaller = this.blockMarshaller;
if (blockMarshaller != null) {
blockMarshaller.flush();
writeByte(ID_END_BLOCK_DATA);
}
}
protected ObjectOutput getObjectOutput() {
final ObjectOutput output = objectOutput;
return output == null ? (objectOutput = getBlockMarshaller()) : output;
}
protected BlockMarshaller getBlockMarshaller() {
final BlockMarshaller blockMarshaller = this.blockMarshaller;
return blockMarshaller == null ? (this.blockMarshaller = new BlockMarshaller(this, bufferSize)) : blockMarshaller;
}
private RiverObjectOutputStream getObjectOutputStream() throws IOException {
final RiverObjectOutputStream objectOutputStream = this.objectOutputStream;
return objectOutputStream == null ? this.objectOutputStream = createObjectOutputStream() : objectOutputStream;
}
private final PrivilegedExceptionAction createObjectOutputStreamAction = new PrivilegedExceptionAction() {
public RiverObjectOutputStream run() throws IOException {
return new RiverObjectOutputStream(getBlockMarshaller(), RiverMarshaller.this);
}
};
private RiverObjectOutputStream createObjectOutputStream() throws IOException {
if (getSecurityManager() == null) {
return new RiverObjectOutputStream(getBlockMarshaller(), RiverMarshaller.this);
} else {
try {
return doPrivileged(createObjectOutputStreamAction);
} catch (PrivilegedActionException e) {
throw (IOException) e.getCause();
}
}
}
protected void doWriteSerializableObject(final SerializableClass info, final Object obj, final Class> objClass) throws IOException {
final Class> superclass = objClass.getSuperclass();
if (superclass != null && serializabilityChecker.isSerializable(superclass)) {
doWriteSerializableObject(registry.lookup(superclass), obj, superclass);
}
if (info.hasWriteObject()) {
final RiverObjectOutputStream objectOutputStream = getObjectOutputStream();
final SerializableClass oldInfo = objectOutputStream.swapClass(info);
final Object oldObj = objectOutputStream.swapCurrent(obj);
final int restoreState = objectOutputStream.start();
boolean ok = false;
try {
info.callWriteObject(obj, objectOutputStream);
objectOutputStream.finish(restoreState);
writeEndBlock();
objectOutputStream.swapCurrent(oldObj);
objectOutputStream.swapClass(oldInfo);
ok = true;
} finally {
if (! ok) {
objectOutputStream.fullReset();
}
}
} else {
doWriteFields(info, obj);
}
}
protected void doWriteFields(final SerializableClass info, final Object obj) throws IOException {
final SerializableField[] serializableFields = info.getFields();
for (SerializableField serializableField : serializableFields) {
try {
switch (serializableField.getKind()) {
case BOOLEAN: {
writeBoolean(serializableField.isAccessible() && serializableField.getBoolean(obj));
break;
}
case BYTE: {
writeByte(serializableField.isAccessible() ? serializableField.getByte(obj) : 0);
break;
}
case SHORT: {
writeShort(serializableField.isAccessible() ? serializableField.getShort(obj) : 0);
break;
}
case INT: {
writeInt(serializableField.isAccessible() ? serializableField.getInt(obj) : 0);
break;
}
case CHAR: {
writeChar(serializableField.isAccessible() ? serializableField.getChar(obj) : 0);
break;
}
case LONG: {
writeLong(serializableField.isAccessible() ? serializableField.getLong(obj) : 0);
break;
}
case DOUBLE: {
writeDouble(serializableField.isAccessible() ? serializableField.getDouble(obj) : 0);
break;
}
case FLOAT: {
writeFloat(serializableField.isAccessible() ? serializableField.getFloat(obj) : 0);
break;
}
case OBJECT: {
doWriteObject(serializableField.isAccessible() ? serializableField.getObject(obj) : null, serializableField.isUnshared());
break;
}
}
} catch (IOException | RuntimeException e) {
TraceInformation.addFieldInformation(e, info, serializableField);
TraceInformation.addObjectInformation(e, obj);
throw e;
}
}
}
protected void doWriteEmptyFields(final SerializableClass info) throws IOException {
final SerializableField[] serializableFields = info.getFields();
for (SerializableField serializableField : serializableFields) {
try {
switch (serializableField.getKind()) {
case BOOLEAN: {
writeBoolean(false);
break;
}
case BYTE: {
writeByte(0);
break;
}
case SHORT: {
writeShort(0);
break;
}
case INT: {
writeInt(0);
break;
}
case CHAR: {
writeChar(0);
break;
}
case LONG: {
writeLong(0L);
break;
}
case DOUBLE: {
writeDouble(0.0);
break;
}
case FLOAT: {
writeFloat(0.0f);
break;
}
case OBJECT: {
writeObject(null);
break;
}
}
} catch (IOException | RuntimeException e){
TraceInformation.addFieldInformation(e, info, serializableField);
throw e;
}
}
}
protected void writeProxyClass(final Class> objClass) throws IOException {
if (! writeKnownClass(objClass, false)) {
writeNewProxyClass(objClass);
}
}
protected void writeNewProxyClass(final Class> objClass) throws IOException {
ClassTable.Writer classTableWriter = classTable.getClassWriter(objClass);
if (classTableWriter != null) {
write(ID_PREDEFINED_PROXY_CLASS);
classCache.put(objClass, classSeq++);
writeClassTableData(objClass, classTableWriter);
} else {
write(ID_PROXY_CLASS);
final String[] names = classResolver.getProxyInterfaces(objClass);
writeInt(names.length);
for (String name : names) {
writeString(name);
}
classCache.put(objClass, classSeq++);
if (configuredVersion == 1) {
final BlockMarshaller blockMarshaller = getBlockMarshaller();
classResolver.annotateProxyClass(blockMarshaller, objClass);
writeEndBlock();
} else {
classResolver.annotateProxyClass(this, objClass);
}
}
}
protected void writeEnumClass(final Class extends Enum> objClass) throws IOException {
if (! writeKnownClass(objClass, false)) {
writeNewEnumClass(objClass);
}
}
protected void writeNewEnumClass(final Class extends Enum> objClass) throws IOException {
ClassTable.Writer classTableWriter = classTable.getClassWriter(objClass);
if (classTableWriter != null) {
write(ID_PREDEFINED_ENUM_TYPE_CLASS);
classCache.put(objClass, classSeq++);
writeClassTableData(objClass, classTableWriter);
} else {
write(ID_ENUM_TYPE_CLASS);
writeString(classResolver.getClassName(objClass));
classCache.put(objClass, classSeq++);
classResolver.annotateClass(this, objClass);
}
}
protected void writeClassClass(final Class> classObj) throws IOException {
write(ID_CLASS_CLASS);
writeClass(classObj);
// not cached
}
protected void writeObjectArrayClass(final Class> objClass) throws IOException {
write(ID_OBJECT_ARRAY_TYPE_CLASS);
writeClass(objClass.getComponentType());
classCache.put(objClass, classSeq++);
}
protected void writeClass(final Class> objClass) throws IOException {
if (! writeKnownClass(objClass, false)) {
writeNewClass(objClass);
}
}
protected void writeSerialSuperClass(final Class> objClass) throws IOException {
if (! writeKnownClass(objClass, true)) {
writeNewSerialSuperClass(objClass);
}
}
private static final IdentityIntMap> BASIC_CLASSES_V2;
private static final IdentityIntMap> BASIC_CLASSES_V3;
private static final IdentityIntMap> BASIC_CLASSES_V4;
private static final Field ENUM_SET_ELEMENT_TYPE_FIELD;
private static final Field ENUM_SET_VALUES_FIELD;
private static final Field ENUM_MAP_KEY_TYPE_FIELD;
static {
final IdentityIntMap> map = new IdentityIntMap>(0x0.6p0f);
map.put(byte.class, ID_PRIM_BYTE);
map.put(boolean.class, ID_PRIM_BOOLEAN);
map.put(char.class, ID_PRIM_CHAR);
map.put(double.class, ID_PRIM_DOUBLE);
map.put(float.class, ID_PRIM_FLOAT);
map.put(int.class, ID_PRIM_INT);
map.put(long.class, ID_PRIM_LONG);
map.put(short.class, ID_PRIM_SHORT);
map.put(void.class, ID_VOID);
map.put(Byte.class, ID_BYTE_CLASS);
map.put(Boolean.class, ID_BOOLEAN_CLASS);
map.put(Character.class, ID_CHARACTER_CLASS);
map.put(Double.class, ID_DOUBLE_CLASS);
map.put(Float.class, ID_FLOAT_CLASS);
map.put(Integer.class, ID_INTEGER_CLASS);
map.put(Long.class, ID_LONG_CLASS);
map.put(Short.class, ID_SHORT_CLASS);
map.put(Void.class, ID_VOID_CLASS);
map.put(Object.class, ID_OBJECT_CLASS);
map.put(Class.class, ID_CLASS_CLASS);
map.put(String.class, ID_STRING_CLASS);
map.put(Enum.class, ID_ENUM_CLASS);
map.put(byte[].class, ID_BYTE_ARRAY_CLASS);
map.put(boolean[].class, ID_BOOLEAN_ARRAY_CLASS);
map.put(char[].class, ID_CHAR_ARRAY_CLASS);
map.put(double[].class, ID_DOUBLE_ARRAY_CLASS);
map.put(float[].class, ID_FLOAT_ARRAY_CLASS);
map.put(int[].class, ID_INT_ARRAY_CLASS);
map.put(long[].class, ID_LONG_ARRAY_CLASS);
map.put(short[].class, ID_SHORT_ARRAY_CLASS);
map.put(ArrayList.class, ID_CC_ARRAY_LIST);
map.put(LinkedList.class, ID_CC_LINKED_LIST);
map.put(IdentityHashMap.class, ID_CC_IDENTITY_HASH_MAP);
map.put(AbstractCollection.class, ID_ABSTRACT_COLLECTION);
map.put(AbstractList.class, ID_ABSTRACT_LIST);
map.put(AbstractQueue.class, ID_ABSTRACT_QUEUE);
map.put(AbstractSequentialList.class, ID_ABSTRACT_SEQUENTIAL_LIST);
map.put(AbstractSet.class, ID_ABSTRACT_SET);
map.put(CopyOnWriteArrayList.class, ID_CC_COPY_ON_WRITE_ARRAY_LIST);
map.put(CopyOnWriteArraySet.class, ID_CC_COPY_ON_WRITE_ARRAY_SET);
map.put(Vector.class, ID_CC_VECTOR);
map.put(Stack.class, ID_CC_STACK);
map.put(emptyListClass, ID_EMPTY_LIST_OBJECT); // special case
map.put(singletonListClass, ID_SINGLETON_LIST_OBJECT); // special case
map.put(emptySetClass, ID_EMPTY_SET_OBJECT); // special case
map.put(singletonSetClass, ID_SINGLETON_SET_OBJECT); // special case
map.put(emptyMapClass, ID_EMPTY_MAP_OBJECT); // special case
map.put(singletonMapClass, ID_SINGLETON_MAP_OBJECT); // special case
map.put(EnumMap.class, ID_CC_ENUM_MAP);
map.put(EnumSet.class, ID_CC_ENUM_SET);
map.put(enumSetProxyClass, ID_CC_ENUM_SET_PROXY); // special case
BASIC_CLASSES_V2 = map.clone();
map.put(Pair.class, ID_PAIR);
map.put(ArrayDeque.class, ID_CC_ARRAY_DEQUE);
map.put(reverseOrderClass, ID_REVERSE_ORDER_OBJECT); // special case
map.put(reverseOrder2Class, ID_REVERSE_ORDER2_OBJECT); // special case
map.put(nCopiesClass, ID_CC_NCOPIES);
BASIC_CLASSES_V3 = map.clone();
map.put(unmodifiableCollectionClass, ID_UNMODIFIABLE_COLLECTION);
map.put(unmodifiableSetClass, ID_UNMODIFIABLE_SET);
map.put(unmodifiableListClass, ID_UNMODIFIABLE_LIST);
map.put(unmodifiableMapClass, ID_UNMODIFIABLE_MAP);
map.put(unmodifiableSortedSetClass, ID_UNMODIFIABLE_SORTED_SET);
map.put(unmodifiableSortedMapClass, ID_UNMODIFIABLE_SORTED_MAP);
map.put(unmodifiableMapEntrySetClass, ID_UNMODIFIABLE_MAP_ENTRY_SET);
BASIC_CLASSES_V4 = map;
final SecurityManager sm = getSecurityManager();
// this solution will work for any JDK which conforms to the serialization spec of Enum; unless they
// do something tricky involving ObjectStreamField anyway...
try {
if (sm == null) {
ENUM_SET_VALUES_FIELD = enumSetProxyClass.getDeclaredField("elements");
} else {
ENUM_SET_VALUES_FIELD = doPrivileged(new GetDeclaredFieldAction(enumSetProxyClass, "elements"));
}
} catch (NoSuchFieldError | NoSuchFieldException e) {
throw new RuntimeException("Cannot locate the elements field on EnumSet's serialization proxy!");
}
try {
if (sm == null) {
ENUM_SET_ELEMENT_TYPE_FIELD = enumSetProxyClass.getDeclaredField("elementType");
} else {
ENUM_SET_ELEMENT_TYPE_FIELD = doPrivileged(new GetDeclaredFieldAction(enumSetProxyClass, "elementType"));
}
} catch (NoSuchFieldError | NoSuchFieldException e) {
throw new RuntimeException("Cannot locate the elementType field on EnumSet's serialization proxy!");
}
try {
if (sm == null) {
ENUM_MAP_KEY_TYPE_FIELD = EnumMap.class.getDeclaredField("keyType");
} else {
ENUM_MAP_KEY_TYPE_FIELD = doPrivileged(new GetDeclaredFieldAction(EnumMap.class, "keyType"));
}
} catch (NoSuchFieldError | NoSuchFieldException e) {
throw new RuntimeException("Cannot locate the keyType field on EnumMap!");
}
}
protected void writeNewClass(final Class> objClass) throws IOException {
if (objClass.isEnum()) {
writeNewEnumClass(objClass.asSubclass(Enum.class));
} else if (Proxy.class.isAssignableFrom(objClass)) {
writeNewProxyClass(objClass);
} else if (objClass.isArray()) {
writeObjectArrayClass(objClass);
} else if (! objClass.isInterface() && serializabilityChecker.isSerializable(objClass)) {
if (Externalizable.class.isAssignableFrom(objClass)) {
writeNewExternalizableClass(objClass);
} else {
writeNewSerializableClass(objClass);
}
} else {
ClassTable.Writer classTableWriter = classTable.getClassWriter(objClass);
if (classTableWriter != null) {
write(ID_PREDEFINED_PLAIN_CLASS);
classCache.put(objClass, classSeq++);
writeClassTableData(objClass, classTableWriter);
} else {
write(ID_PLAIN_CLASS);
writeString(classResolver.getClassName(objClass));
classResolver.annotateClass(this, objClass);
classCache.put(objClass, classSeq++);
}
}
}
protected void writeNewSerialSuperClass(final Class> objClass) throws IOException {
if (! objClass.isInterface() && serializabilityChecker.isSerializable(objClass)) {
writeNewSerializableClass(objClass);
} else {
ClassTable.Writer classTableWriter = classTable.getClassWriter(objClass);
if (classTableWriter != null) {
write(ID_PREDEFINED_PLAIN_CLASS);
classCache.put(objClass, classSeq++);
writeClassTableData(objClass, classTableWriter);
} else {
write(ID_PLAIN_CLASS);
writeString(classResolver.getClassName(objClass));
classResolver.annotateClass(this, objClass);
classCache.put(objClass, classSeq++);
}
}
}
private void writeClassTableData(final Class> objClass, final ClassTable.Writer classTableWriter) throws IOException {
if (configuredVersion == 1) {
classTableWriter.writeClass(getBlockMarshaller(), objClass);
writeEndBlock();
} else {
classTableWriter.writeClass(this, objClass);
}
}
protected boolean writeKnownClass(final Class> objClass, final boolean isSuper) throws IOException {
final int configuredVersion = this.configuredVersion;
int i;
if (isSuper) {
// serialized superclasses may only be of certain types
i = getBasicClasses(configuredVersion).get(objClass, -1);
if (i == ID_OBJECT_CLASS) {
write(i);
return true;
}
// otherwise, we see if it's a known serialized class, ignoring other classes
i = serialClassCache.get(objClass, -1);
} else {
i = getBasicClasses(configuredVersion).get(objClass, -1);
if (i != -1) {
write(i);
return true;
}
i = classCache.get(objClass, -1);
if (i == -1) {
i = serialClassCache.get(objClass, -1);
}
}
if (i != -1) {
final int diff = i - classSeq;
if (diff >= -256) {
write(ID_REPEAT_CLASS_NEAR);
write(diff);
} else if (diff >= -65536) {
write(ID_REPEAT_CLASS_NEARISH);
writeShort(diff);
} else {
write(ID_REPEAT_CLASS_FAR);
writeInt(i);
}
return true;
}
return false;
}
protected void writeSerializableClass(final Class> objClass, final boolean isSuper) throws IOException {
if (! writeKnownClass(objClass, isSuper)) {
writeNewSerializableClass(objClass);
}
}
protected void writeNewSerializableClass(final Class> objClass) throws IOException {
ClassTable.Writer classTableWriter = classTable.getClassWriter(objClass);
if (classTableWriter != null) {
write(ID_PREDEFINED_SERIALIZABLE_CLASS);
serialClassCache.put(objClass, classSeq++);
writeClassTableData(objClass, classTableWriter);
} else {
final SerializableClass info = registry.lookup(objClass);
if (info.hasWriteObject()) {
write(ID_WRITE_OBJECT_CLASS);
} else {
write(ID_SERIALIZABLE_CLASS);
}
final String className = classResolver.getClassName(objClass);
if (configuredVersion >= 4) {
writeObject(className);
} else {
writeString(className);
}
writeLong(info.getEffectiveSerialVersionUID());
serialClassCache.put(objClass, classSeq++);
classResolver.annotateClass(this, objClass);
final SerializableField[] fields = info.getFields();
final int cnt = fields.length;
writeInt(cnt);
for (int i = 0; i < cnt; i++) {
SerializableField field = fields[i];
if (configuredVersion >= 4) {
writeObject(field.getName());
} else {
writeUTF(field.getName());
}
try {
writeClass(field.getKind() == Kind.OBJECT ? Object.class : field.getType());
} catch (ClassNotFoundException e) {
throw new InvalidClassException("Class of field was unloaded");
}
writeBoolean(field.isUnshared());
}
}
Class> sc = objClass.getSuperclass();
if (! serializabilityChecker.isSerializable(sc)) {
write(ID_OBJECT_CLASS);
return;
}
writeSerialSuperClass(sc);
}
protected void writeExternalizableClass(final Class> objClass) throws IOException {
if (! writeKnownClass(objClass, false)) {
writeNewExternalizableClass(objClass);
}
}
protected void writeNewExternalizableClass(final Class> objClass) throws IOException {
ClassTable.Writer classTableWriter = classTable.getClassWriter(objClass);
if (classTableWriter != null) {
write(ID_PREDEFINED_EXTERNALIZABLE_CLASS);
classCache.put(objClass, classSeq++);
writeClassTableData(objClass, classTableWriter);
} else {
write(ID_EXTERNALIZABLE_CLASS);
writeString(classResolver.getClassName(objClass));
writeLong(registry.lookup(objClass).getEffectiveSerialVersionUID());
classCache.put(objClass, classSeq++);
classResolver.annotateClass(this, objClass);
}
}
protected void writeExternalizerClass(final Class> objClass, final Externalizer externalizer) throws IOException {
if (! writeKnownClass(objClass, false)) {
writeNewExternalizerClass(objClass, externalizer);
}
}
protected void writeNewExternalizerClass(final Class> objClass, final Externalizer externalizer) throws IOException {
ClassTable.Writer classTableWriter = classTable.getClassWriter(objClass);
if (classTableWriter != null) {
write(ID_PREDEFINED_EXTERNALIZER_CLASS);
classCache.put(objClass, classSeq++);
writeClassTableData(objClass, classTableWriter);
} else {
write(ID_EXTERNALIZER_CLASS);
writeString(classResolver.getClassName(objClass));
classCache.put(objClass, classSeq++);
classResolver.annotateClass(this, objClass);
}
writeObject(externalizer);
}
public void clearInstanceCache() throws IOException {
instanceCache.clear();
instanceSeq = 0;
if (byteOutput != null) {
write(ID_CLEAR_INSTANCE_CACHE);
}
}
public void clearClassCache() throws IOException {
classCache.clear();
serialClassCache.clear();
externalizers.clear();
classSeq = 0;
instanceCache.clear();
instanceSeq = 0;
if (byteOutput != null) {
write(ID_CLEAR_CLASS_CACHE);
}
}
public void start(final ByteOutput byteOutput) throws IOException {
super.start(byteOutput);
writeByte(configuredVersion);
}
private void writeString(String string) throws IOException {
writeInt(string.length());
shallowFlush();
UTFUtils.writeUTFBytes(byteOutput, string);
}
// Replace writeUTF with a faster, non-scanning version
public void writeUTF(final String string) throws IOException {
writeInt(string.length());
shallowFlush();
UTFUtils.writeUTFBytes(byteOutput, string);
}
}