All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jppf.serialization.Deserializer Maven / Gradle / Ivy

There is a newer version: 6.3-alpha
Show newest version
/*
 * 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) 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