Merge pull request #309 from jboner/wip-1789-ser2-patriknw

Configure serializer with class as key. See #1789
This commit is contained in:
patriknw 2012-02-07 04:54:32 -08:00
commit 50d107e150
9 changed files with 204 additions and 242 deletions

View file

@ -5,7 +5,6 @@
package akka.serialization package akka.serialization
import akka.testkit.AkkaSpec import akka.testkit.AkkaSpec
import com.typesafe.config.ConfigFactory
import akka.actor._ import akka.actor._
import java.io._ import java.io._
import akka.dispatch.Await import akka.dispatch.Await
@ -17,21 +16,25 @@ import akka.pattern.ask
object SerializeSpec { object SerializeSpec {
val serializationConf = ConfigFactory.parseString(""" val config = """
akka { akka {
actor { actor {
serializers { serializers {
java = "akka.serialization.JavaSerializer"
test = "akka.serialization.TestSerializer" test = "akka.serialization.TestSerializer"
} }
serialization-bindings { serialization-bindings {
java = ["akka.serialization.SerializeSpec$Person", "akka.serialization.SerializeSpec$Address", "akka.serialization.MyJavaSerializableActor", "akka.serialization.MyStatelessActorWithMessagesInMailbox", "akka.serialization.MyActorWithProtobufMessagesInMailbox"] "akka.serialization.SerializeSpec$Person" = java
test = ["akka.serialization.TestSerializble", "akka.serialization.SerializeSpec$PlainMessage"] "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
} }
} }
} }
""") """
@BeanInfo @BeanInfo
case class Address(no: String, street: String, city: String, zip: String) { def this() = this("", "", "", "") } case class Address(no: String, street: String, city: String, zip: String) { def this() = this("", "", "", "") }
@ -54,10 +57,18 @@ object SerializeSpec {
class ExtendedPlainMessage extends PlainMessage class ExtendedPlainMessage extends PlainMessage
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
} }
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) { class SerializeSpec extends AkkaSpec(SerializeSpec.config) {
import SerializeSpec._ import SerializeSpec._
val ser = SerializationExtension(system) val ser = SerializationExtension(system)
@ -69,8 +80,8 @@ class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) {
"Serialization" must { "Serialization" must {
"have correct bindings" in { "have correct bindings" in {
ser.bindings(addr.getClass.getName) must be("java") ser.bindings.collectFirst { case (c, s) if c == addr.getClass s.getClass } must be(Some(classOf[JavaSerializer]))
ser.bindings(classOf[PlainMessage].getName) must be("test") ser.bindings.collectFirst { case (c, s) if c == classOf[PlainMessage] s.getClass } must be(Some(classOf[TestSerializer]))
} }
"serialize Address" in { "serialize Address" in {
@ -144,58 +155,64 @@ class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) {
} }
} }
"resove serializer by direct interface" in { "resolve serializer by direct interface" in {
val msg = new SimpleMessage("foo") ser.serializerFor(classOf[SimpleMessage]).getClass must be(classOf[TestSerializer])
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
} }
"resove serializer by interface implemented by super class" in { "resolve serializer by interface implemented by super class" in {
val msg = new ExtendedSimpleMessage("foo", 17) ser.serializerFor(classOf[ExtendedSimpleMessage]).getClass must be(classOf[TestSerializer])
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
} }
"resove serializer by indirect interface" in { "resolve serializer by indirect interface" in {
val msg = new AnotherMessage ser.serializerFor(classOf[AnotherMessage]).getClass must be(classOf[TestSerializer])
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
} }
"resove serializer by indirect interface implemented by super class" in { "resolve serializer by indirect interface implemented by super class" in {
val msg = new ExtendedAnotherMessage ser.serializerFor(classOf[ExtendedAnotherMessage]).getClass must be(classOf[TestSerializer])
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
} }
"resove serializer for message with binding" in { "resolve serializer for message with binding" in {
val msg = new PlainMessage ser.serializerFor(classOf[PlainMessage]).getClass must be(classOf[TestSerializer])
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
} }
"resove serializer for message extending class with with binding" in { "resolve serializer for message extending class with with binding" in {
val msg = new ExtendedPlainMessage ser.serializerFor(classOf[ExtendedPlainMessage]).getClass must be(classOf[TestSerializer])
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer]) }
"resolve serializer for message with several bindings" in {
ser.serializerFor(classOf[Both]).getClass must be(classOf[TestSerializer])
}
"resolve serializer in the order of the bindings" in {
ser.serializerFor(classOf[A]).getClass must be(classOf[JavaSerializer])
ser.serializerFor(classOf[B]).getClass must be(classOf[TestSerializer])
ser.serializerFor(classOf[C]).getClass must be(classOf[JavaSerializer])
}
"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])
}
} }
} }
} }
object VerifySerializabilitySpec { object VerifySerializabilitySpec {
val conf = ConfigFactory.parseString(""" val conf = """
akka { akka {
actor { actor {
serialize-messages = on serialize-messages = on
serialize-creators = on serialize-creators = on
serializers {
java = "akka.serialization.JavaSerializer"
default = "akka.serialization.JavaSerializer"
}
serialization-bindings {
java = ["akka.serialization.SerializeSpec$Address", "akka.serialization.MyJavaSerializableActor", "akka.serialization.MyStatelessActorWithMessagesInMailbox", "akka.serialization.MyActorWithProtobufMessagesInMailbox"]
}
} }
} }
""") """
class FooActor extends Actor { class FooActor extends Actor {
def receive = { def receive = {
@ -210,6 +227,7 @@ object VerifySerializabilitySpec {
} }
} }
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class VerifySerializabilitySpec extends AkkaSpec(VerifySerializabilitySpec.conf) { class VerifySerializabilitySpec extends AkkaSpec(VerifySerializabilitySpec.conf) {
import VerifySerializabilitySpec._ import VerifySerializabilitySpec._
implicit val timeout = Timeout(5 seconds) implicit val timeout = Timeout(5 seconds)

View file

@ -266,23 +266,19 @@ akka {
event-stream = off event-stream = off
} }
# Entries for pluggable serializers and their bindings. If a binding for a specific # Entries for pluggable serializers and their bindings.
# class is not found, then the default serializer (Java serialization) is used.
serializers { serializers {
# java = "akka.serialization.JavaSerializer" java = "akka.serialization.JavaSerializer"
# proto = "akka.serialization.ProtobufSerializer" # proto = "akka.serialization.ProtobufSerializer"
default = "akka.serialization.JavaSerializer"
} }
# serialization-bindings { # Class to Serializer binding. You only need to specify the name of an interface
# java = ["akka.serialization.SerializeSpec$Address", # or abstract base class of the messages. In case of ambiguity it is primarily
# "akka.serialization.MyJavaSerializableActor", # using the most specific configured class, and secondly the entry configured first.
# "akka.serialization.MyStatelessActorWithMessagesInMailbox", serialization-bindings {
# "akka.serialization.MyActorWithProtobufMessagesInMailbox"] "java.io.Serializable" = java
# proto = ["com.google.protobuf.Message", #"com.google.protobuf.Message" = proto
# "akka.actor.ProtobufProtocol$MyMessage"] }
# }
} }
# Used to set the behavior of the scheduler. # Used to set the behavior of the scheduler.

View file

@ -8,14 +8,21 @@ import akka.AkkaException
import akka.util.ReflectiveAccess import akka.util.ReflectiveAccess
import scala.util.DynamicVariable import scala.util.DynamicVariable
import com.typesafe.config.Config import com.typesafe.config.Config
import akka.config.ConfigurationException
import akka.actor.{ Extension, ActorSystem, ExtendedActorSystem, Address } import akka.actor.{ Extension, ActorSystem, ExtendedActorSystem, Address }
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import akka.event.Logging import akka.event.Logging
import scala.collection.mutable.ArrayBuffer
import java.io.NotSerializableException
case class NoSerializerFoundException(m: String) extends AkkaException(m) case class NoSerializerFoundException(m: String) extends AkkaException(m)
object Serialization { object Serialization {
/**
* Tuple that represents mapping from Class to Serializer
*/
type ClassSerializer = (Class[_], Serializer)
/** /**
* This holds a reference to the current ActorSystem (the surrounding context) * This holds a reference to the current ActorSystem (the surrounding context)
* during serialization and deserialization. * during serialization and deserialization.
@ -40,28 +47,19 @@ object Serialization {
import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
import config._ import config._
val Serializers: Map[String, String] = val Serializers: Map[String, String] = configToMap(getConfig("akka.actor.serializers"))
getConfig("akka.actor.serializers").root.unwrapped.asScala.toMap.map { case (k, v) (k, v.toString) }
val SerializationBindings: Map[String, Seq[String]] = { val SerializationBindings: Map[String, String] = configToMap(getConfig("akka.actor.serialization-bindings"))
val configPath = "akka.actor.serialization-bindings"
hasPath(configPath) match { private def configToMap(cfg: Config): Map[String, String] =
case false Map() cfg.root.unwrapped.asScala.toMap.map { case (k, v) (k, v.toString) }
case true
val serializationBindings: Map[String, Seq[String]] = getConfig(configPath).root.unwrapped.asScala.toMap.map {
case (k: String, v: java.util.Collection[_]) (k -> v.asScala.toSeq.asInstanceOf[Seq[String]])
case invalid throw new ConfigurationException("Invalid serialization-bindings [%s]".format(invalid))
}
serializationBindings
}
}
} }
} }
/** /**
* Serialization module. Contains methods for serialization and deserialization as well as * Serialization module. Contains methods for serialization and deserialization as well as
* locating a Serializer for a particular class as defined in the mapping in the 'akka.conf' file. * locating a Serializer for a particular class as defined in the mapping in the configuration.
*/ */
class Serialization(val system: ExtendedActorSystem) extends Extension { class Serialization(val system: ExtendedActorSystem) extends Extension {
import Serialization._ import Serialization._
@ -105,8 +103,10 @@ class Serialization(val system: ExtendedActorSystem) extends Extension {
} catch { case e: Exception Left(e) } } catch { case e: Exception Left(e) }
/** /**
* Returns the Serializer configured for the given object, returns the NullSerializer if it's null, * Returns the Serializer configured for the given object, returns the NullSerializer if it's null.
* falls back to the Serializer named "default" *
* @throws akka.config.ConfigurationException if no `serialization-bindings` is configured for the
* class of the object
*/ */
def findSerializerFor(o: AnyRef): Serializer = o match { def findSerializerFor(o: AnyRef): Serializer = o match {
case null NullSerializer case null NullSerializer
@ -114,82 +114,86 @@ class Serialization(val system: ExtendedActorSystem) extends Extension {
} }
/** /**
* Returns the configured Serializer for the given Class, falls back to the Serializer named "default". * Returns the configured Serializer for the given Class. The configured Serializer
* It traverses interfaces and super classes to find any configured Serializer that match * is used if the configured class `isAssignableFrom` from the `clazz`, i.e.
* the class name. * the configured class is a super class or implemented interface. In case of
* ambiguity it is primarily using the most specific configured class,
* and secondly the entry configured first.
*
* @throws java.io.NotSerializableException if no `serialization-bindings` is configured for the class
*/ */
def serializerFor(clazz: Class[_]): Serializer = def serializerFor(clazz: Class[_]): Serializer =
if (bindings.isEmpty) { serializerMap.get(clazz) match {
// quick path to default when no bindings are registered case null
serializers("default") val ser = bindings.collectFirst {
} else { case (c, s) if c.isAssignableFrom(clazz) s
} getOrElse (throw new NotSerializableException(
"No configured serialization-bindings for class [%s]" format clazz.getName))
def resolve(c: Class[_]): Option[Serializer] = // memorize for performance
serializerMap.get(c.getName) match { serializerMap.putIfAbsent(clazz, ser) match {
case null case null
val classes = c.getInterfaces ++ Option(c.getSuperclass) log.debug("Using serializer[{}] for message [{}]", ser.getClass.getName, clazz.getName)
classes.view map resolve collectFirst { case Some(x) x } ser
case x Some(x) case some some
} }
case ser ser
serializerMap.get(clazz.getName) match {
case null
val ser = resolve(clazz).getOrElse(serializers("default"))
// memorize the lookups for performance
serializerMap.putIfAbsent(clazz.getName, ser) match {
case null
log.debug("Using serializer[{}] for message [{}]", ser.getClass.getName, clazz.getName)
ser
case some some
}
case ser ser
}
} }
/** /**
* Tries to load the specified Serializer by the FQN * Tries to instantiate the specified Serializer by the FQN
*/ */
def serializerOf(serializerFQN: String): Either[Exception, Serializer] = def serializerOf(serializerFQN: String): Either[Exception, Serializer] =
ReflectiveAccess.createInstance(serializerFQN, ReflectiveAccess.noParams, ReflectiveAccess.noArgs, system.internalClassLoader) ReflectiveAccess.createInstance(serializerFQN, ReflectiveAccess.noParams, ReflectiveAccess.noArgs, system.internalClassLoader)
/** /**
* A Map of serializer from alias to implementation (class implementing akka.serialization.Serializer) * A Map of serializer from alias to implementation (class implementing akka.serialization.Serializer)
* By default always contains the following mapping: "default" -> akka.serialization.JavaSerializer * By default always contains the following mapping: "java" -> akka.serialization.JavaSerializer
* But "default" can be overridden in config
*/ */
lazy val serializers: Map[String, Serializer] = { private val serializers: Map[String, Serializer] = {
val serializersConf = settings.Serializers for ((k: String, v: String) settings.Serializers)
for ((k: String, v: String) serializersConf)
yield k -> serializerOf(v).fold(throw _, identity) yield k -> serializerOf(v).fold(throw _, identity)
} }
/** /**
* bindings is a Map whose keys = FQN of class that is serializable and values = the alias of the serializer to be used * bindings is a Seq of tuple representing the mapping from Class to Serializer.
* It is primarily ordered by the most specific classes first, and secondly in the configured order.
*/ */
lazy val bindings: Map[String, String] = { private[akka] val bindings: Seq[ClassSerializer] = {
settings.SerializationBindings.foldLeft(Map[String, String]()) { val configuredBindings = for ((k: String, v: String) settings.SerializationBindings) yield {
//All keys which are lists, take the Strings from them and Map them val c = ReflectiveAccess.getClassFor(k, system.internalClassLoader).fold(throw _, identity[Class[_]])
case (result, (k: String, vs: Seq[_])) result ++ (vs collect { case v: String (v, k) }) (c, serializers(v))
//For any other values, just skip them
case (result, _) result
} }
sort(configuredBindings)
} }
/** /**
* serializerMap is a Map whose keys = FQN of class that is serializable and values is the serializer to be used for that class * Sort so that subtypes always precede their supertypes, but without
* obeying any order between unrelated subtypes (insert sort).
*/ */
private lazy val serializerMap: ConcurrentHashMap[String, Serializer] = { private def sort(in: Iterable[ClassSerializer]): Seq[ClassSerializer] =
val serializerMap = new ConcurrentHashMap[String, Serializer] (new ArrayBuffer[ClassSerializer](in.size) /: in) { (buf, ca)
for ((k, v) bindings) { buf.indexWhere(_._1 isAssignableFrom ca._1) match {
serializerMap.put(k, serializers(v)) case -1 buf append ca
case x buf insert (x, ca)
}
buf
} }
/**
* serializerMap is a Map whose keys is the class that is serializable and values is the serializer
* to be used for that class.
*/
private val serializerMap: ConcurrentHashMap[Class[_], Serializer] = {
val serializerMap = new ConcurrentHashMap[Class[_], Serializer]
for ((c, s) bindings) serializerMap.put(c, s)
serializerMap serializerMap
} }
/** /**
* Maps from a Serializer Identity (Int) to a Serializer instance (optimization) * Maps from a Serializer Identity (Int) to a Serializer instance (optimization)
*/ */
lazy val serializerByIdentity: Map[Int, Serializer] = val serializerByIdentity: Map[Int, Serializer] =
Map(NullSerializer.identifier -> NullSerializer) ++ serializers map { case (_, v) (v.identifier, v) } Map(NullSerializer.identifier -> NullSerializer) ++ serializers map { case (_, v) (v.identifier, v) }
} }

View file

@ -54,61 +54,7 @@ public class SerializationDocTestBase {
} }
} }
//#my-own-serializer //#my-own-serializer
@Test public void haveExamples() {
/*
//#serialize-messages-config
akka {
actor {
serialize-messages = on
}
}
//#serialize-messages-config
//#serialize-creators-config
akka {
actor {
serialize-creators = on
}
}
//#serialize-creators-config
//#serialize-serializers-config
akka {
actor {
serializers {
default = "akka.serialization.JavaSerializer"
myown = "akka.docs.serialization.MyOwnSerializer"
}
}
}
//#serialize-serializers-config
//#serialization-bindings-config
akka {
actor {
serializers {
default = "akka.serialization.JavaSerializer"
java = "akka.serialization.JavaSerializer"
proto = "akka.serialization.ProtobufSerializer"
myown = "akka.docs.serialization.MyOwnSerializer"
}
serialization-bindings {
java = ["java.lang.String",
"app.my.Customer"]
proto = ["com.google.protobuf.Message"]
myown = ["my.own.BusinessObject",
"something.equally.Awesome",
"akka.docs.serialization.MyOwnSerializable"
"java.lang.Boolean"]
}
}
}
//#serialization-bindings-config
*/
}
@Test public void demonstrateTheProgrammaticAPI() { @Test public void demonstrateTheProgrammaticAPI() {
//#programmatic //#programmatic

View file

@ -25,47 +25,28 @@ For Akka to know which ``Serializer`` to use for what, you need edit your :ref:`
in the "akka.actor.serializers"-section you bind names to implementations of the ``akka.serialization.Serializer`` in the "akka.actor.serializers"-section you bind names to implementations of the ``akka.serialization.Serializer``
you wish to use, like this: you wish to use, like this:
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java#serialize-serializers-config .. includecode:: ../scala/code/akka/docs/serialization/SerializationDocSpec.scala#serialize-serializers-config
.. note::
The name ``default`` is special in the sense that the ``Serializer``
mapped to it will be used as default.
After you've bound names to different implementations of ``Serializer`` you need to wire which classes After you've bound names to different implementations of ``Serializer`` you need to wire which classes
should be serialized using which ``Serializer``, this is done in the "akka.actor.serialization-bindings"-section: should be serialized using which ``Serializer``, this is done in the "akka.actor.serialization-bindings"-section:
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java#serialization-bindings-config .. includecode:: ../scala/code/akka/docs/serialization/SerializationDocSpec.scala#serialization-bindings-config
.. note:: You only need to specify the name of an interface or abstract base class of the messages. In case of ambiguity,
i.e. the message implements several of the configured classes, it is primarily using the most specific
configured class, and secondly the entry configured first.
You only need to specify the name of an interface or abstract base class if the messages implements Akka provides serializers for ``java.io.Serializable`` and `protobuf <http://code.google.com/p/protobuf/>`_
that. E.g. ``com.google.protobuf.Message`` for protobuf serialization. ``com.google.protobuf.Message`` by default, so normally you don't need to add configuration for that, but
it can be done to force a specific serializer in case messages implements both ``java.io.Serializable``
Protobuf and ``com.google.protobuf.Message``.
--------
Akka provides a ``Serializer`` for `protobuf <http://code.google.com/p/protobuf/>`_ messages.
To use that you need to add the following to the configuration::
akka {
actor {
serializers {
proto = "akka.serialization.ProtobufSerializer"
}
serialization-bindings {
proto = ["com.google.protobuf.Message"]
}
}
}
Verification Verification
------------ ------------
If you want to verify that your messages are serializable you can enable the following config option: If you want to verify that your messages are serializable you can enable the following config option:
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java#serialize-messages-config .. includecode:: ../scala/code/akka/docs/serialization/SerializationDocSpec.scala#serialize-messages-config
.. warning:: .. warning::
@ -74,7 +55,7 @@ If you want to verify that your messages are serializable you can enable the fol
If you want to verify that your ``Props`` are serializable you can enable the following config option: If you want to verify that your ``Props`` are serializable you can enable the following config option:
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java#serialize-creators-config .. includecode:: ../scala/code/akka/docs/serialization/SerializationDocSpec.scala#serialize-creators-config
.. warning:: .. warning::

View file

@ -45,6 +45,9 @@ class MyOwnSerializer extends Serializer {
} }
//#my-own-serializer //#my-own-serializer
trait MyOwnSerializable
case class Customer(name: String) extends MyOwnSerializable
class SerializationDocSpec extends AkkaSpec { class SerializationDocSpec extends AkkaSpec {
"demonstrate configuration of serialize messages" in { "demonstrate configuration of serialize messages" in {
//#serialize-messages-config //#serialize-messages-config
@ -82,8 +85,8 @@ class SerializationDocSpec extends AkkaSpec {
akka { akka {
actor { actor {
serializers { serializers {
default = "akka.serialization.JavaSerializer" java = "akka.serialization.JavaSerializer"
proto = "akka.serialization.ProtobufSerializer"
myown = "akka.docs.serialization.MyOwnSerializer" myown = "akka.docs.serialization.MyOwnSerializer"
} }
} }
@ -91,8 +94,6 @@ class SerializationDocSpec extends AkkaSpec {
""") """)
//#serialize-serializers-config //#serialize-serializers-config
val a = ActorSystem("system", config) val a = ActorSystem("system", config)
SerializationExtension(a).serializers("default").getClass.getName must equal("akka.serialization.JavaSerializer")
SerializationExtension(a).serializers("myown").getClass.getName must equal("akka.docs.serialization.MyOwnSerializer")
a.shutdown() a.shutdown()
} }
@ -102,31 +103,26 @@ class SerializationDocSpec extends AkkaSpec {
akka { akka {
actor { actor {
serializers { serializers {
default = "akka.serialization.JavaSerializer"
java = "akka.serialization.JavaSerializer" java = "akka.serialization.JavaSerializer"
proto = "akka.serialization.ProtobufSerializer" proto = "akka.serialization.ProtobufSerializer"
myown = "akka.docs.serialization.MyOwnSerializer" myown = "akka.docs.serialization.MyOwnSerializer"
} }
serialization-bindings { serialization-bindings {
java = ["java.lang.String", "java.lang.String" = java
"app.my.Customer"] "akka.docs.serialization.Customer" = java
proto = ["com.google.protobuf.Message"] "com.google.protobuf.Message" = proto
myown = ["my.own.BusinessObject", "akka.docs.serialization.MyOwnSerializable" = myown
"something.equally.Awesome", "java.lang.Boolean" = myown
"akka.docs.serialization.MyOwnSerializable" }
"java.lang.Boolean"]
}
} }
} }
""") """)
//#serialization-bindings-config //#serialization-bindings-config
val a = ActorSystem("system", config) val a = ActorSystem("system", config)
SerializationExtension(a).serializers("default").getClass.getName must equal("akka.serialization.JavaSerializer") SerializationExtension(a).serializerFor(classOf[String]).getClass must equal(classOf[JavaSerializer])
SerializationExtension(a).serializers("java").getClass.getName must equal("akka.serialization.JavaSerializer") SerializationExtension(a).serializerFor(classOf[Customer]).getClass must equal(classOf[JavaSerializer])
SerializationExtension(a).serializers("myown").getClass.getName must equal("akka.docs.serialization.MyOwnSerializer") SerializationExtension(a).serializerFor(classOf[java.lang.Boolean]).getClass must equal(classOf[MyOwnSerializer])
SerializationExtension(a).serializerFor(classOf[String]).getClass.getName must equal("akka.serialization.JavaSerializer")
SerializationExtension(a).serializerFor(classOf[java.lang.Boolean]).getClass.getName must equal("akka.docs.serialization.MyOwnSerializer")
a.shutdown() a.shutdown()
} }

View file

@ -27,38 +27,19 @@ you wish to use, like this:
.. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala#serialize-serializers-config .. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala#serialize-serializers-config
.. note::
The name ``default`` is special in the sense that the ``Serializer``
mapped to it will be used as default.
After you've bound names to different implementations of ``Serializer`` you need to wire which classes After you've bound names to different implementations of ``Serializer`` you need to wire which classes
should be serialized using which ``Serializer``, this is done in the "akka.actor.serialization-bindings"-section: should be serialized using which ``Serializer``, this is done in the "akka.actor.serialization-bindings"-section:
.. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala#serialization-bindings-config .. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala#serialization-bindings-config
.. note:: You only need to specify the name of an interface or abstract base class of the messages. In case of ambiguity,
i.e. the message implements several of the configured classes, it is primarily using the most specific
configured class, and secondly the entry configured first.
You only need to specify the name of an interface or abstract base class if the messages implements Akka provides serializers for ``java.io.Serializable`` and `protobuf <http://code.google.com/p/protobuf/>`_
that. E.g. ``com.google.protobuf.Message`` for protobuf serialization. ``com.google.protobuf.Message`` by default, so normally you don't need to add configuration for that, but
it can be done to force a specific serializer in case messages implements both ``java.io.Serializable``
Protobuf and ``com.google.protobuf.Message``.
--------
Akka provides a ``Serializer`` for `protobuf <http://code.google.com/p/protobuf/>`_ messages.
To use that you need to add the following to the configuration::
akka {
actor {
serializers {
proto = "akka.serialization.ProtobufSerializer"
}
serialization-bindings {
proto = ["com.google.protobuf.Message"]
}
}
}
Verification Verification
------------ ------------

View file

@ -9,6 +9,21 @@ akka {
actor { actor {
# Entries for pluggable serializers and their bindings.
serializers {
java = "akka.serialization.JavaSerializer"
proto = "akka.serialization.ProtobufSerializer"
}
# Class to Serializer binding. You only need to specify the name of an interface
# or abstract base class of the messages. In case of ambiguity it is primarily
# using the most specific configured class, and secondly the entry configured first.
serialization-bindings {
"com.google.protobuf.Message" = proto
"java.io.Serializable" = java
}
deployment { deployment {
default { default {

View file

@ -0,0 +1,25 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.serialization
import akka.testkit.AkkaSpec
import akka.remote.RemoteProtocol.MessageProtocol
import akka.actor.ProtobufProtocol.MyMessage
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class ProtobufSerializerSpec extends AkkaSpec {
val ser = SerializationExtension(system)
"Serialization" must {
"resolve protobuf serializer" in {
ser.serializerFor(classOf[MessageProtocol]).getClass must be(classOf[ProtobufSerializer])
ser.serializerFor(classOf[MyMessage]).getClass must be(classOf[ProtobufSerializer])
}
}
}