2009-07-23 20:01:37 +02:00
|
|
|
/**
|
2009-12-27 16:01:53 +01:00
|
|
|
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
|
2009-07-23 20:01:37 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package se.scalablesolutions.akka.serialization
|
|
|
|
|
|
|
|
|
|
import java.io.{ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream}
|
2009-12-08 08:51:10 +01:00
|
|
|
|
2009-12-27 22:56:55 +01:00
|
|
|
import org.apache.commons.io.input.ClassLoaderObjectInputStream
|
|
|
|
|
|
2009-12-08 08:51:10 +01:00
|
|
|
import com.google.protobuf.Message
|
|
|
|
|
|
2009-07-23 20:01:37 +02:00
|
|
|
import org.codehaus.jackson.map.ObjectMapper
|
2009-12-08 08:51:10 +01:00
|
|
|
|
2009-12-17 19:29:19 +01:00
|
|
|
import sjson.json.{Serializer => SJSONSerializer}
|
2009-07-23 20:01:37 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
|
|
|
*/
|
|
|
|
|
trait Serializer {
|
2010-03-17 21:38:27 +01:00
|
|
|
var classLoader: Option[ClassLoader] = None
|
2010-06-10 13:42:42 +02:00
|
|
|
def deepClone(obj: AnyRef): AnyRef = fromBinary(toBinary(obj), Some(obj.getClass))
|
2010-03-17 21:38:27 +01:00
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def toBinary(obj: AnyRef): Array[Byte]
|
|
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef
|
2009-07-23 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-28 12:55:13 +02:00
|
|
|
// For Java API
|
|
|
|
|
class SerializerFactory {
|
|
|
|
|
import Serializer._
|
|
|
|
|
def getJava: Java.type = Java
|
|
|
|
|
def getJavaJSON: JavaJSON.type = JavaJSON
|
|
|
|
|
def getScalaJSON: ScalaJSON.type = ScalaJSON
|
2010-03-25 21:50:27 +01:00
|
|
|
def getSBinary: SBinary.type = SBinary
|
2010-05-21 20:08:49 +02:00
|
|
|
def getProtobuf: Protobuf.type = Protobuf
|
2009-07-28 12:55:13 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-23 20:01:37 +02:00
|
|
|
/**
|
|
|
|
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
|
|
|
*/
|
|
|
|
|
object Serializer {
|
2009-07-28 12:55:13 +02:00
|
|
|
val EMPTY_CLASS_ARRAY = Array[Class[_]]()
|
|
|
|
|
val EMPTY_ANY_REF_ARRAY = Array[AnyRef]()
|
|
|
|
|
|
2009-12-26 22:14:06 +01:00
|
|
|
object NOOP extends NOOP
|
|
|
|
|
class NOOP extends Serializer {
|
2010-06-10 13:42:42 +02:00
|
|
|
def toBinary(obj: AnyRef): Array[Byte] = Array[Byte]()
|
|
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = null.asInstanceOf[AnyRef]
|
2009-10-14 22:18:41 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-23 20:01:37 +02:00
|
|
|
/**
|
|
|
|
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
|
|
|
*/
|
2009-12-26 22:14:06 +01:00
|
|
|
object Java extends Java
|
2010-03-17 21:38:27 +01:00
|
|
|
trait Java extends Serializer {
|
2010-06-10 13:42:42 +02:00
|
|
|
def toBinary(obj: AnyRef): Array[Byte] = {
|
2009-07-23 20:01:37 +02:00
|
|
|
val bos = new ByteArrayOutputStream
|
|
|
|
|
val out = new ObjectOutputStream(bos)
|
|
|
|
|
out.writeObject(obj)
|
|
|
|
|
out.close
|
|
|
|
|
bos.toByteArray
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
2010-05-21 20:08:49 +02:00
|
|
|
val in =
|
2010-03-17 21:38:27 +01:00
|
|
|
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes))
|
|
|
|
|
else new ObjectInputStream(new ByteArrayInputStream(bytes))
|
2009-07-23 20:01:37 +02:00
|
|
|
val obj = in.readObject
|
|
|
|
|
in.close
|
|
|
|
|
obj
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
|
|
|
*/
|
2009-12-26 22:14:06 +01:00
|
|
|
object Protobuf extends Protobuf
|
2010-03-17 21:38:27 +01:00
|
|
|
trait Protobuf extends Serializer {
|
2010-06-10 13:42:42 +02:00
|
|
|
def toBinary(obj: AnyRef): Array[Byte] = {
|
2010-03-17 21:38:27 +01:00
|
|
|
if (!obj.isInstanceOf[Message]) throw new IllegalArgumentException(
|
|
|
|
|
"Can't serialize a non-protobuf message using protobuf [" + obj + "]")
|
2009-07-28 12:55:13 +02:00
|
|
|
obj.asInstanceOf[Message].toByteArray
|
|
|
|
|
}
|
2010-05-21 20:08:49 +02:00
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
2010-03-17 21:38:27 +01:00
|
|
|
if (!clazz.isDefined) throw new IllegalArgumentException(
|
2010-05-21 20:08:49 +02:00
|
|
|
"Need a protobuf message class to be able to serialize bytes using protobuf")
|
2009-07-28 12:55:13 +02:00
|
|
|
// TODO: should we cache this method lookup?
|
2010-03-17 21:38:27 +01:00
|
|
|
val message = clazz.get.getDeclaredMethod(
|
|
|
|
|
"getDefaultInstance", EMPTY_CLASS_ARRAY: _*).invoke(null, EMPTY_ANY_REF_ARRAY: _*).asInstanceOf[Message]
|
2010-05-21 20:08:49 +02:00
|
|
|
message.toBuilder().mergeFrom(bytes).build
|
2009-07-23 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Class[_]): AnyRef = {
|
2009-12-27 08:24:11 +01:00
|
|
|
if (clazz eq null) throw new IllegalArgumentException("Protobuf message can't be null")
|
2010-06-10 13:42:42 +02:00
|
|
|
fromBinary(bytes, Some(clazz))
|
2009-07-23 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
|
|
|
*/
|
2009-12-26 22:14:06 +01:00
|
|
|
object JavaJSON extends JavaJSON
|
2010-03-17 21:38:27 +01:00
|
|
|
trait JavaJSON extends Serializer {
|
2009-07-23 20:01:37 +02:00
|
|
|
private val mapper = new ObjectMapper
|
|
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def toBinary(obj: AnyRef): Array[Byte] = {
|
2009-07-23 20:01:37 +02:00
|
|
|
val bos = new ByteArrayOutputStream
|
|
|
|
|
val out = new ObjectOutputStream(bos)
|
|
|
|
|
mapper.writeValue(out, obj)
|
|
|
|
|
out.close
|
|
|
|
|
bos.toByteArray
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
2010-03-17 21:38:27 +01:00
|
|
|
if (!clazz.isDefined) throw new IllegalArgumentException(
|
|
|
|
|
"Can't deserialize JSON to instance if no class is provided")
|
2010-05-21 20:08:49 +02:00
|
|
|
val in =
|
2010-03-17 21:38:27 +01:00
|
|
|
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes))
|
|
|
|
|
else new ObjectInputStream(new ByteArrayInputStream(bytes))
|
2009-07-23 20:01:37 +02:00
|
|
|
val obj = mapper.readValue(in, clazz.get).asInstanceOf[AnyRef]
|
|
|
|
|
in.close
|
|
|
|
|
obj
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-10 16:00:17 +02:00
|
|
|
def fromJSON(json: String, clazz: Class[_]): AnyRef = {
|
2009-12-27 08:24:11 +01:00
|
|
|
if (clazz eq null) throw new IllegalArgumentException("Can't deserialize JSON to instance if no class is provided")
|
2009-07-28 13:28:01 +02:00
|
|
|
mapper.readValue(json, clazz).asInstanceOf[AnyRef]
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-05-21 20:08:49 +02:00
|
|
|
|
2009-07-23 20:01:37 +02:00
|
|
|
/**
|
|
|
|
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
|
|
|
*/
|
2009-12-26 22:14:06 +01:00
|
|
|
object ScalaJSON extends ScalaJSON
|
2010-03-17 21:38:27 +01:00
|
|
|
trait ScalaJSON extends Serializer {
|
2010-06-10 13:42:42 +02:00
|
|
|
def toBinary(obj: AnyRef): Array[Byte] = SJSONSerializer.SJSON.out(obj)
|
2009-07-23 20:01:37 +02:00
|
|
|
|
2009-12-27 22:56:55 +01:00
|
|
|
// FIXME set ClassLoader on SJSONSerializer.SJSON
|
2010-06-10 13:42:42 +02:00
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = SJSONSerializer.SJSON.in(bytes)
|
2010-05-21 20:08:49 +02:00
|
|
|
|
2010-02-17 16:02:50 +05:30
|
|
|
import scala.reflect.Manifest
|
2010-06-10 16:00:17 +02:00
|
|
|
def fromJSON[T](json: String)(implicit m: Manifest[T]): AnyRef = {
|
2010-02-17 16:02:50 +05:30
|
|
|
SJSONSerializer.SJSON.in(json)(m)
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def fromBinary[T](bytes: Array[Byte])(implicit m: Manifest[T]): AnyRef = {
|
2010-02-17 16:02:50 +05:30
|
|
|
SJSONSerializer.SJSON.in(bytes)(m)
|
|
|
|
|
}
|
2009-07-23 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
|
|
|
*/
|
2010-03-25 21:50:27 +01:00
|
|
|
object SBinary extends SBinary
|
2009-12-26 22:14:06 +01:00
|
|
|
class SBinary {
|
2010-03-25 21:50:27 +01:00
|
|
|
import sbinary._
|
|
|
|
|
import sbinary.Operations._
|
2009-07-23 20:01:37 +02:00
|
|
|
import sbinary.DefaultProtocol._
|
2010-05-21 20:08:49 +02:00
|
|
|
|
2010-05-25 15:14:53 +02:00
|
|
|
var classLoader: Option[ClassLoader] = None
|
|
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def deepClone[T <: AnyRef](obj: T)(implicit w : Writes[T], r : Reads[T]): T = fromBinary[T](toBinary[T](obj), None)
|
2009-07-23 20:01:37 +02:00
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def toBinary[T](t : T)(implicit bin : Writes[T]): Array[Byte] = toByteArray[T](t)
|
2009-07-23 20:01:37 +02:00
|
|
|
|
2010-06-10 13:42:42 +02:00
|
|
|
def fromBinary[T](array : Array[Byte], clazz: Option[Class[T]])(implicit bin : Reads[T]): T = fromByteArray[T](array)
|
2010-03-25 21:50:27 +01:00
|
|
|
}
|
2009-07-23 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
|