2011-06-07 06:36:21 +05:30
|
|
|
/**
|
2012-01-19 18:21:06 +01:00
|
|
|
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
2011-06-07 06:36:21 +05:30
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.serialization
|
|
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
import akka.testkit.AkkaSpec
|
2011-12-08 16:07:03 +01:00
|
|
|
import akka.actor._
|
|
|
|
|
import java.io._
|
2011-12-27 17:30:05 +01:00
|
|
|
import akka.dispatch.Await
|
|
|
|
|
import akka.util.Timeout
|
|
|
|
|
import akka.util.duration._
|
2011-12-21 11:25:40 +01:00
|
|
|
import scala.reflect.BeanInfo
|
|
|
|
|
import com.google.protobuf.Message
|
2012-01-18 10:18:51 +01:00
|
|
|
import akka.pattern.ask
|
2011-12-21 11:25:40 +01:00
|
|
|
|
2011-06-07 06:36:21 +05:30
|
|
|
object SerializeSpec {
|
2011-11-22 13:04:10 +01:00
|
|
|
|
2012-02-06 21:12:26 +01:00
|
|
|
val config = """
|
2011-11-22 13:04:10 +01:00
|
|
|
akka {
|
|
|
|
|
actor {
|
|
|
|
|
serializers {
|
2012-02-03 17:32:32 +01:00
|
|
|
test = "akka.serialization.TestSerializer"
|
2011-11-22 13:04:10 +01:00
|
|
|
}
|
2012-02-03 17:32:32 +01:00
|
|
|
|
2011-11-22 13:04:10 +01:00
|
|
|
serialization-bindings {
|
2012-02-06 21:12:26 +01:00
|
|
|
"akka.serialization.SerializeSpec$Person" = java
|
|
|
|
|
"akka.serialization.SerializeSpec$Address" = java
|
|
|
|
|
"akka.serialization.TestSerializble" = test
|
|
|
|
|
"akka.serialization.SerializeSpec$PlainMessage" = test
|
|
|
|
|
"akka.serialization.SerializeSpec$A" = java
|
|
|
|
|
"akka.serialization.SerializeSpec$B" = test
|
|
|
|
|
"akka.serialization.SerializeSpec$D" = test
|
2011-11-22 13:04:10 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-02-06 21:12:26 +01:00
|
|
|
"""
|
2011-11-22 13:04:10 +01:00
|
|
|
|
2011-06-07 06:36:21 +05:30
|
|
|
@BeanInfo
|
|
|
|
|
case class Address(no: String, street: String, city: String, zip: String) { def this() = this("", "", "", "") }
|
|
|
|
|
@BeanInfo
|
|
|
|
|
case class Person(name: String, age: Int, address: Address) { def this() = this("", 0, null) }
|
|
|
|
|
|
|
|
|
|
case class Record(id: Int, person: Person)
|
2012-02-03 17:32:32 +01:00
|
|
|
|
|
|
|
|
class SimpleMessage(s: String) extends TestSerializble
|
|
|
|
|
|
|
|
|
|
class ExtendedSimpleMessage(s: String, i: Int) extends SimpleMessage(s)
|
|
|
|
|
|
|
|
|
|
trait AnotherInterface extends TestSerializble
|
|
|
|
|
|
|
|
|
|
class AnotherMessage extends AnotherInterface
|
|
|
|
|
|
|
|
|
|
class ExtendedAnotherMessage extends AnotherMessage
|
|
|
|
|
|
|
|
|
|
class PlainMessage
|
|
|
|
|
|
|
|
|
|
class ExtendedPlainMessage extends PlainMessage
|
|
|
|
|
|
2012-02-06 21:12:26 +01:00
|
|
|
class Both(s: String) extends SimpleMessage(s) with Serializable
|
|
|
|
|
|
|
|
|
|
trait A
|
|
|
|
|
trait B
|
|
|
|
|
class C extends B with A
|
|
|
|
|
class D extends A
|
|
|
|
|
class E extends D
|
|
|
|
|
|
2011-06-07 06:36:21 +05:30
|
|
|
}
|
|
|
|
|
|
2011-10-21 17:01:22 +02:00
|
|
|
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
2012-02-06 21:12:26 +01:00
|
|
|
class SerializeSpec extends AkkaSpec(SerializeSpec.config) {
|
2011-06-07 06:36:21 +05:30
|
|
|
import SerializeSpec._
|
|
|
|
|
|
2011-11-24 18:53:18 +01:00
|
|
|
val ser = SerializationExtension(system)
|
2011-11-16 17:18:36 +01:00
|
|
|
import ser._
|
2011-06-07 06:36:21 +05:30
|
|
|
|
2011-11-22 13:04:10 +01:00
|
|
|
val addr = Address("120", "Monroe Street", "Santa Clara", "95050")
|
|
|
|
|
val person = Person("debasish ghosh", 25, Address("120", "Monroe Street", "Santa Clara", "95050"))
|
|
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
"Serialization" must {
|
|
|
|
|
|
2011-11-22 13:04:10 +01:00
|
|
|
"have correct bindings" in {
|
2012-02-06 22:20:38 +01:00
|
|
|
ser.bindings.collectFirst { case (c, s) if c == addr.getClass ⇒ s.getClass } must be(Some(classOf[JavaSerializer]))
|
|
|
|
|
ser.bindings.collectFirst { case (c, s) if c == classOf[PlainMessage] ⇒ s.getClass } must be(Some(classOf[TestSerializer]))
|
2011-11-22 13:04:10 +01:00
|
|
|
}
|
|
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
"serialize Address" in {
|
|
|
|
|
val b = serialize(addr) match {
|
|
|
|
|
case Left(exception) ⇒ fail(exception)
|
|
|
|
|
case Right(bytes) ⇒ bytes
|
|
|
|
|
}
|
|
|
|
|
deserialize(b.asInstanceOf[Array[Byte]], classOf[Address], None) match {
|
|
|
|
|
case Left(exception) ⇒ fail(exception)
|
|
|
|
|
case Right(add) ⇒ assert(add === addr)
|
|
|
|
|
}
|
2011-06-07 06:36:21 +05:30
|
|
|
}
|
|
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
"serialize Person" in {
|
2011-11-22 13:04:10 +01:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
val b = serialize(person) match {
|
|
|
|
|
case Left(exception) ⇒ fail(exception)
|
|
|
|
|
case Right(bytes) ⇒ bytes
|
|
|
|
|
}
|
|
|
|
|
deserialize(b.asInstanceOf[Array[Byte]], classOf[Person], None) match {
|
|
|
|
|
case Left(exception) ⇒ fail(exception)
|
|
|
|
|
case Right(p) ⇒ assert(p === person)
|
|
|
|
|
}
|
2011-06-07 06:36:21 +05:30
|
|
|
}
|
2011-10-11 16:05:48 +02:00
|
|
|
|
|
|
|
|
"serialize record with default serializer" in {
|
2011-11-22 13:04:10 +01:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
val r = Record(100, person)
|
|
|
|
|
val b = serialize(r) match {
|
|
|
|
|
case Left(exception) ⇒ fail(exception)
|
|
|
|
|
case Right(bytes) ⇒ bytes
|
|
|
|
|
}
|
|
|
|
|
deserialize(b.asInstanceOf[Array[Byte]], classOf[Record], None) match {
|
|
|
|
|
case Left(exception) ⇒ fail(exception)
|
|
|
|
|
case Right(p) ⇒ assert(p === r)
|
|
|
|
|
}
|
2011-06-07 06:36:21 +05:30
|
|
|
}
|
2011-11-01 11:20:02 +01:00
|
|
|
|
2011-12-08 16:07:03 +01:00
|
|
|
"not serialize ActorCell" in {
|
|
|
|
|
val a = system.actorOf(Props(new Actor {
|
|
|
|
|
def receive = {
|
|
|
|
|
case o: ObjectOutputStream ⇒
|
|
|
|
|
try {
|
|
|
|
|
o.writeObject(this)
|
|
|
|
|
} catch {
|
|
|
|
|
case _: NotSerializableException ⇒ testActor ! "pass"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
a ! new ObjectOutputStream(new ByteArrayOutputStream())
|
|
|
|
|
expectMsg("pass")
|
2011-12-14 00:06:36 +01:00
|
|
|
system.stop(a)
|
2011-12-08 16:07:03 +01:00
|
|
|
}
|
|
|
|
|
|
2011-11-01 11:20:02 +01:00
|
|
|
"serialize DeadLetterActorRef" in {
|
|
|
|
|
val outbuf = new ByteArrayOutputStream()
|
|
|
|
|
val out = new ObjectOutputStream(outbuf)
|
2011-11-30 15:16:20 +01:00
|
|
|
val a = ActorSystem("SerializeDeadLeterActorRef", AkkaSpec.testConf)
|
|
|
|
|
try {
|
|
|
|
|
out.writeObject(a.deadLetters)
|
|
|
|
|
out.flush()
|
|
|
|
|
out.close()
|
|
|
|
|
|
|
|
|
|
val in = new ObjectInputStream(new ByteArrayInputStream(outbuf.toByteArray))
|
|
|
|
|
Serialization.currentSystem.withValue(a.asInstanceOf[ActorSystemImpl]) {
|
|
|
|
|
val deadLetters = in.readObject().asInstanceOf[DeadLetterActorRef]
|
|
|
|
|
(deadLetters eq a.deadLetters) must be(true)
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
2011-12-14 01:06:20 +01:00
|
|
|
a.shutdown()
|
2011-11-01 11:20:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
2012-02-03 17:32:32 +01:00
|
|
|
|
2012-02-06 21:12:26 +01:00
|
|
|
"resolve serializer by direct interface" in {
|
|
|
|
|
ser.serializerFor(classOf[SimpleMessage]).getClass must be(classOf[TestSerializer])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"resolve serializer by interface implemented by super class" in {
|
|
|
|
|
ser.serializerFor(classOf[ExtendedSimpleMessage]).getClass must be(classOf[TestSerializer])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"resolve serializer by indirect interface" in {
|
|
|
|
|
ser.serializerFor(classOf[AnotherMessage]).getClass must be(classOf[TestSerializer])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"resolve serializer by indirect interface implemented by super class" in {
|
|
|
|
|
ser.serializerFor(classOf[ExtendedAnotherMessage]).getClass must be(classOf[TestSerializer])
|
2012-02-03 17:32:32 +01:00
|
|
|
}
|
|
|
|
|
|
2012-02-06 21:12:26 +01:00
|
|
|
"resolve serializer for message with binding" in {
|
|
|
|
|
ser.serializerFor(classOf[PlainMessage]).getClass must be(classOf[TestSerializer])
|
2012-02-03 17:32:32 +01:00
|
|
|
}
|
|
|
|
|
|
2012-02-06 21:12:26 +01:00
|
|
|
"resolve serializer for message extending class with with binding" in {
|
|
|
|
|
ser.serializerFor(classOf[ExtendedPlainMessage]).getClass must be(classOf[TestSerializer])
|
2012-02-03 17:32:32 +01:00
|
|
|
}
|
|
|
|
|
|
2012-02-07 15:11:16 +01:00
|
|
|
"throw exception for message with several bindings" in {
|
|
|
|
|
intercept[java.io.NotSerializableException] {
|
|
|
|
|
ser.serializerFor(classOf[Both])
|
|
|
|
|
}
|
2012-02-03 17:32:32 +01:00
|
|
|
}
|
|
|
|
|
|
2012-02-06 21:12:26 +01:00
|
|
|
"resolve serializer in the order of most specific binding first" in {
|
|
|
|
|
ser.serializerFor(classOf[A]).getClass must be(classOf[JavaSerializer])
|
|
|
|
|
ser.serializerFor(classOf[D]).getClass must be(classOf[TestSerializer])
|
|
|
|
|
ser.serializerFor(classOf[E]).getClass must be(classOf[TestSerializer])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"throw java.io.NotSerializableException when no binding" in {
|
|
|
|
|
intercept[java.io.NotSerializableException] {
|
|
|
|
|
ser.serializerFor(classOf[Actor])
|
|
|
|
|
}
|
2012-02-03 17:32:32 +01:00
|
|
|
}
|
|
|
|
|
|
2011-06-07 06:36:21 +05:30
|
|
|
}
|
|
|
|
|
}
|
2011-12-27 17:30:05 +01:00
|
|
|
|
|
|
|
|
object VerifySerializabilitySpec {
|
2012-02-06 21:12:26 +01:00
|
|
|
val conf = """
|
2011-12-27 17:30:05 +01:00
|
|
|
akka {
|
|
|
|
|
actor {
|
|
|
|
|
serialize-messages = on
|
|
|
|
|
serialize-creators = on
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-02-06 21:12:26 +01:00
|
|
|
"""
|
2011-12-27 17:30:05 +01:00
|
|
|
|
|
|
|
|
class FooActor extends Actor {
|
|
|
|
|
def receive = {
|
|
|
|
|
case s: String ⇒ sender ! s
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class NonSerializableActor(system: ActorSystem) extends Actor {
|
|
|
|
|
def receive = {
|
|
|
|
|
case s: String ⇒ sender ! s
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-06 21:12:26 +01:00
|
|
|
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
2011-12-27 17:30:05 +01:00
|
|
|
class VerifySerializabilitySpec extends AkkaSpec(VerifySerializabilitySpec.conf) {
|
|
|
|
|
import VerifySerializabilitySpec._
|
2011-12-27 20:07:21 +01:00
|
|
|
implicit val timeout = Timeout(5 seconds)
|
2011-12-27 17:30:05 +01:00
|
|
|
|
2011-12-27 20:07:21 +01:00
|
|
|
"verify config" in {
|
2011-12-27 17:30:05 +01:00
|
|
|
system.settings.SerializeAllCreators must be(true)
|
|
|
|
|
system.settings.SerializeAllMessages must be(true)
|
2011-12-27 20:07:21 +01:00
|
|
|
}
|
2011-12-27 17:30:05 +01:00
|
|
|
|
2011-12-27 20:07:21 +01:00
|
|
|
"verify creators" in {
|
2011-12-27 17:30:05 +01:00
|
|
|
val a = system.actorOf(Props[FooActor])
|
|
|
|
|
intercept[NotSerializableException] {
|
|
|
|
|
Await.result(a ? new AnyRef, timeout.duration)
|
|
|
|
|
}
|
2011-12-27 20:07:21 +01:00
|
|
|
system stop a
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"verify messages" in {
|
|
|
|
|
val a = system.actorOf(Props[FooActor])
|
|
|
|
|
Await.result(a ? "pigdog", timeout.duration) must be("pigdog")
|
2011-12-27 17:30:05 +01:00
|
|
|
intercept[java.io.NotSerializableException] {
|
|
|
|
|
val b = system.actorOf(Props(new NonSerializableActor(system)))
|
|
|
|
|
}
|
2011-12-27 20:07:21 +01:00
|
|
|
system stop a
|
2011-12-27 17:30:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
2012-02-03 17:32:32 +01:00
|
|
|
|
|
|
|
|
trait TestSerializble
|
|
|
|
|
|
|
|
|
|
class TestSerializer extends Serializer {
|
|
|
|
|
def includeManifest: Boolean = false
|
|
|
|
|
|
|
|
|
|
def identifier = 9999
|
|
|
|
|
|
|
|
|
|
def toBinary(o: AnyRef): Array[Byte] = {
|
|
|
|
|
Array.empty[Byte]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None,
|
|
|
|
|
classLoader: Option[ClassLoader] = None): AnyRef = {
|
|
|
|
|
null
|
|
|
|
|
}
|
|
|
|
|
}
|