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

io.altoo.serialization.kryo.scala.KryoSerializerBackend.scala Maven / Gradle / Ivy

package io.altoo.serialization.kryo.scala

import com.esotericsoftware.kryo.kryo5.Kryo
import com.esotericsoftware.kryo.kryo5.io.{ByteBufferInput, ByteBufferOutput, Input, Output}
import com.esotericsoftware.kryo.kryo5.unsafe.{UnsafeInput, UnsafeOutput}
import org.slf4j.Logger

import java.nio.ByteBuffer

private[kryo] class KryoSerializerBackend(val kryo: Kryo, val bufferSize: Int, val maxBufferSize: Int, val useManifest: Boolean, val useUnsafe: Boolean)(log: Logger,
    classLoader: ClassLoader) {

  // "toBinary" serializes the given object to an Array of Bytes
  // Implements Serializer
  def toBinary(obj: Any): Array[Byte] = {
    val buffer = output
    try {
      if (useManifest)
        kryo.writeObject(buffer, obj)
      else
        kryo.writeClassAndObject(buffer, obj)
      buffer.toBytes
    } catch {
      case e: StackOverflowError if !kryo.getReferences => // when configured with "nograph" serialization can fail with stack overflow
        log.error(s"Could not serialize class with potentially circular references: $classLoader", e)
        throw new RuntimeException("Could not serialize class with potential circular references: " + obj)
    } finally {
      buffer.reset()
    }
  }

  // Implements ByteBufferSerializer
  def toBinary(obj: Any, buf: ByteBuffer): Unit = {
    val buffer = getOutput(buf)
    try {
      if (useManifest)
        kryo.writeObject(buffer, obj)
      else
        kryo.writeClassAndObject(buffer, obj)
      buffer.toBytes
    } catch {
      case e: StackOverflowError if !kryo.getReferences => // when configured with "nograph" serialization can fail with stack overflow
        log.error(s"Could not serialize class with potentially circular references: $obj", e)
        throw new RuntimeException("Could not serialize class with potential circular references: " + obj)
    }
  }

  // "fromBinary" deserializes the given array,
  // using the type hint (if any, see "includeManifest" above)
  // into the optionally provided classLoader.
  // Implements Serializer
  def fromBinary(bytes: Array[Byte], clazz: Option[Class[?]]): AnyRef = {
    val buffer = getInput(bytes)
    try {
      if (useManifest)
        clazz match {
          case Some(c) => kryo.readObject(buffer, c).asInstanceOf[AnyRef]
          case _       => throw new RuntimeException("Object of unknown class cannot be deserialized")
        }
      else
        kryo.readClassAndObject(buffer)
    } finally {
      buffer.close()
    }
  }

  // Implements ByteBufferSerializer
  def fromBinary(buf: ByteBuffer, manifest: Option[String]): AnyRef = {
    val buffer = getInput(buf)
    if (useManifest) {
      val clazz = manifest.flatMap(ReflectionHelper.getClassFor(_, classLoader).toOption)
      clazz match {
        case Some(c) => kryo.readObject(buffer, c)
        case _       => throw new RuntimeException("Object of unknown class cannot be deserialized")
      }
    } else
      kryo.readClassAndObject(buffer)
  }

  // Used by Serializer implementation
  private val output =
    if (useUnsafe)
      new UnsafeOutput(bufferSize, maxBufferSize)
    else
      new Output(bufferSize, maxBufferSize)

  // Used by ByteBufferSerializer implementation
  private def getOutput(buffer: ByteBuffer): Output =
    new ByteBufferOutput(buffer)

  // Used by Serializer implementation
  private def getInput(bytes: Array[Byte]): Input =
    if (useUnsafe)
      new UnsafeInput(bytes)
    else
      new Input(bytes)

  // Used by ByteBufferSerializer implementation
  private def getInput(buffer: ByteBuffer): Input =
    new ByteBufferInput(buffer)

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy