
org.jppf.serialization.Deserializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jppf-common Show documentation
Show all versions of jppf-common Show documentation
JPPF, the open source grid computing solution
/*
* JPPF.
* Copyright (C) 2005-2015 JPPF Team.
* http://www.jppf.org
*
* 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.jppf.serialization;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;
import org.jppf.utils.StringUtils;
import org.slf4j.*;
/**
* Instances of this class are intended to deserialize object graphs from an underlying input stream.
* @author Laurent Cohen
* @exclude
*/
class Deserializer {
/**
* Logger for this class.
*/
private static Logger log = LoggerFactory.getLogger(Deserializer.class);
/**
* Determines whether the debug level is enabled in the log configuration, without the cost of a method call.
*/
private static boolean traceEnabled = log.isTraceEnabled();
/**
* The underlying input stream.
*/
ObjectInputStream in;
/**
* Holds object and class descriptors caches.
*/
DeserializationCaches caches = new DeserializationCaches();
/**
* The class loader to use.
*/
ClassLoader classloader = initClassLoader();
/**
* Handle of the object being read.
*/
int currentHandle;
/**
* Descriptor the class of the object currently being written.
*/
ClassDescriptor currentClassDescriptor;
/**
* The object currently being written.
*/
Object currentObject;
/**
* Temporary buffer used to read arrays of primitive values from the stream.
*/
private byte[] buf = new byte[4096];
/**
* Initialize this deserializer with the specified input stream.
* @param in the stream from which objects are read.
* @throws IOException if an error occurs while reading the header.
*/
Deserializer(final ObjectInputStream in) throws IOException {
this.in = in;
readToBuf(4);
if ( (buf[0] != Serializer.HEADER[0]) || (buf[1] != Serializer.HEADER[1]) || (buf[2] != Serializer.HEADER[2]) || (buf[3] != Serializer.HEADER[3]))
throw new IOException("bad header: " + StringUtils.toHexString(buf, 0, 4, " "));
}
/**
* Read an object graph from the stream.
* @return the next object read from the stream.
* @throws Exception if any error occurs.
*/
Object readObject() throws Exception {
byte b = in.readByte();
while (b == Serializer.CLASS_HEADER) {
readClassDescriptors();
b = in.readByte();
}
if (b == Serializer.NULL_OBJECT_HEADER) return null;
else if (b == Serializer.CLASS_OBJECT_HEADER) return readClassObject();
int handle = in.readInt();
Object o = caches.handleToObjectMap.get(handle);
if (o != null) return o;
readObject(handle);
return caches.handleToObjectMap.get(handle);
}
/**
* Read the next object in the stream.
* @param handle the handle of the object to read.
* @throws Exception if any error occurs.
*/
@SuppressWarnings("unchecked")
private void readObject(final int handle) throws Exception {
int cdHandle = in.readInt();
ClassDescriptor cd = caches.getDescriptor(cdHandle);
if (cd.array) readArray(handle, cd);
else if (cd.enumType) {
String name = (String) readObject();
//if (traceEnabled) try { log.trace("reading enum[" + cd.signature + "] : " + name); } catch(Exception e) {}
Object val = (name == null) ? null : Enum.valueOf((Class extends Enum>) cd.clazz, name);
caches.handleToObjectMap.put(handle, val);
} else {
Object obj = newInstance(cd);
currentObject = obj;
currentClassDescriptor = cd;
//if (traceEnabled) try { log.trace("reading object " + obj); } catch(Exception e) {}
caches.handleToObjectMap.put(handle, obj);
readFields(cd, obj);
}
}
/**
* Read the next object in the stream, which is a class object.
* @return the class object whose handle was read.
* @throws Exception if any error occurs.
*/
@SuppressWarnings("unchecked")
private Object readClassObject() throws Exception {
int cdHandle = in.readInt();
ClassDescriptor cd = caches.getDescriptor(cdHandle);
return cd.clazz;
}
/**
* Read all the fields for the specified object.
* @param cd the class descriptor for the object.
* @param obj the object to set the fields on.
* @throws Exception if any error occurs.
*/
void readFields(final ClassDescriptor cd, final Object obj) throws Exception {
ClassDescriptor tmpDesc = cd;
Deque stack = new LinkedBlockingDeque<>();
while (tmpDesc != null) {
stack.addFirst(tmpDesc);
tmpDesc = caches.getDescriptor(tmpDesc.superClassHandle);
}
for (ClassDescriptor desc: stack) {
if (desc.hasWriteObject) {
Method m = SerializationReflectionHelper.getReadObjectMethod(desc.clazz);
if (!m.isAccessible()) m.setAccessible(true);
//if (traceEnabled) try { log.trace("invoking readObject() for class=" + desc + " on object " + obj); } catch(Exception e) {}
try {
tmpDesc = currentClassDescriptor;
currentClassDescriptor = desc;
m.invoke(obj, in);
} finally {
currentClassDescriptor = tmpDesc;
}
}
else if (desc.externalizable) ((Externalizable) obj).readExternal(in);
else readDeclaredFields(desc, obj);
}
}
/**
* Read the fields declared by the class described by the specified class descriptor.
* @param cd the class descriptor to use.
* @param obj the object ot set the field values on.
* @throws Exception if any error occurs.
*/
@SuppressWarnings("unchecked")
void readDeclaredFields(final ClassDescriptor cd, final Object obj) throws Exception {
for (int i=0; i) typeDesc.clazz, name);
field.set(obj, val);
} else {
Object val = readObject();
field.set(obj, val);
}
}
}
/**
* Create and read an array from the stream.
* @param handle the handle of the array.
* @param cd the class descriptor for the array's class.
* @throws Exception if any error occurs.
*/
@SuppressWarnings("unchecked")
private void readArray(final int handle, final ClassDescriptor cd) throws Exception {
int len = in.readInt();
//if (traceEnabled) try { log.trace("reading array with signature=" + cd.signature + ", length=" + len); } catch(Exception e) {}
ClassDescriptor eltDesc = caches.getDescriptor(cd.componentTypeHandle);
Object obj = null;
if (eltDesc.primitive) {
switch(eltDesc.signature.charAt(0)) {
case 'B': obj = readByteArray(len); break;
case 'S': obj = readShortArray(len); break;
case 'I': obj = readIntArray(len); break;
case 'J': obj = readLongArray(len); break;
case 'F': obj = readFloatArray(len); break;
case 'D': obj = readDoubleArray(len); break;
case 'C': obj = readCharArray(len); break;
case 'Z': obj = readBooleanArray(len); break;
}
caches.handleToObjectMap.put(handle, obj);
} else if (eltDesc.enumType) {
obj = Array.newInstance(eltDesc.clazz, len);
caches.handleToObjectMap.put(handle, obj);
for (int i=0; i) eltDesc.clazz, name);
Array.set(obj, i, val);
}
} else {
obj = Array.newInstance(eltDesc.clazz, len);
caches.handleToObjectMap.put(handle, obj);
for (int i=0; i list = new ArrayList<>(n > 0 ? n : 10);
for (int i=0; i 0) pos += n;
else if (n < 0) throw new EOFException("could only read " + pos + " bytes out of " + len);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy