Configure serializer with class as key. See #1789
This commit is contained in:
parent
d7435547ff
commit
1dbce49359
9 changed files with 207 additions and 245 deletions
|
|
@ -5,7 +5,6 @@
|
|||
package akka.serialization
|
||||
|
||||
import akka.testkit.AkkaSpec
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import akka.actor._
|
||||
import java.io._
|
||||
import akka.dispatch.Await
|
||||
|
|
@ -17,21 +16,25 @@ import akka.pattern.ask
|
|||
|
||||
object SerializeSpec {
|
||||
|
||||
val serializationConf = ConfigFactory.parseString("""
|
||||
val config = """
|
||||
akka {
|
||||
actor {
|
||||
serializers {
|
||||
java = "akka.serialization.JavaSerializer"
|
||||
test = "akka.serialization.TestSerializer"
|
||||
}
|
||||
|
||||
serialization-bindings {
|
||||
java = ["akka.serialization.SerializeSpec$Person", "akka.serialization.SerializeSpec$Address", "akka.serialization.MyJavaSerializableActor", "akka.serialization.MyStatelessActorWithMessagesInMailbox", "akka.serialization.MyActorWithProtobufMessagesInMailbox"]
|
||||
test = ["akka.serialization.TestSerializble", "akka.serialization.SerializeSpec$PlainMessage"]
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
""")
|
||||
"""
|
||||
|
||||
@BeanInfo
|
||||
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 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])
|
||||
class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) {
|
||||
class SerializeSpec extends AkkaSpec(SerializeSpec.config) {
|
||||
import SerializeSpec._
|
||||
|
||||
val ser = SerializationExtension(system)
|
||||
|
|
@ -69,8 +80,8 @@ class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) {
|
|||
"Serialization" must {
|
||||
|
||||
"have correct bindings" in {
|
||||
ser.bindings(addr.getClass.getName) must be("java")
|
||||
ser.bindings(classOf[PlainMessage].getName) must be("test")
|
||||
ser.bindings.find(_._1 == addr.getClass).map(_._2.getClass) must be(Some(classOf[JavaSerializer]))
|
||||
ser.bindings.find(_._1 == classOf[PlainMessage]).map(_._2.getClass) must be(Some(classOf[TestSerializer]))
|
||||
}
|
||||
|
||||
"serialize Address" in {
|
||||
|
|
@ -144,58 +155,64 @@ class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) {
|
|||
}
|
||||
}
|
||||
|
||||
"resove serializer by direct interface" in {
|
||||
val msg = new SimpleMessage("foo")
|
||||
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
|
||||
"resolve serializer by direct interface" in {
|
||||
ser.serializerFor(classOf[SimpleMessage]).getClass must be(classOf[TestSerializer])
|
||||
}
|
||||
|
||||
"resove serializer by interface implemented by super class" in {
|
||||
val msg = new ExtendedSimpleMessage("foo", 17)
|
||||
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
|
||||
"resolve serializer by interface implemented by super class" in {
|
||||
ser.serializerFor(classOf[ExtendedSimpleMessage]).getClass must be(classOf[TestSerializer])
|
||||
}
|
||||
|
||||
"resove serializer by indirect interface" in {
|
||||
val msg = new AnotherMessage
|
||||
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
|
||||
"resolve serializer by indirect interface" in {
|
||||
ser.serializerFor(classOf[AnotherMessage]).getClass must be(classOf[TestSerializer])
|
||||
}
|
||||
|
||||
"resove serializer by indirect interface implemented by super class" in {
|
||||
val msg = new ExtendedAnotherMessage
|
||||
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
|
||||
"resolve serializer by indirect interface implemented by super class" in {
|
||||
ser.serializerFor(classOf[ExtendedAnotherMessage]).getClass must be(classOf[TestSerializer])
|
||||
}
|
||||
|
||||
"resove serializer for message with binding" in {
|
||||
val msg = new PlainMessage
|
||||
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
|
||||
"resolve serializer for message with binding" in {
|
||||
ser.serializerFor(classOf[PlainMessage]).getClass must be(classOf[TestSerializer])
|
||||
}
|
||||
|
||||
"resove serializer for message extending class with with binding" in {
|
||||
val msg = new ExtendedPlainMessage
|
||||
ser.serializerFor(msg.getClass).getClass must be(classOf[TestSerializer])
|
||||
"resolve serializer for message extending class with with binding" in {
|
||||
ser.serializerFor(classOf[ExtendedPlainMessage]).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 {
|
||||
val conf = ConfigFactory.parseString("""
|
||||
val conf = """
|
||||
akka {
|
||||
actor {
|
||||
serialize-messages = 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 {
|
||||
def receive = {
|
||||
|
|
@ -210,6 +227,7 @@ object VerifySerializabilitySpec {
|
|||
}
|
||||
}
|
||||
|
||||
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
||||
class VerifySerializabilitySpec extends AkkaSpec(VerifySerializabilitySpec.conf) {
|
||||
import VerifySerializabilitySpec._
|
||||
implicit val timeout = Timeout(5 seconds)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ akka {
|
|||
paths = []
|
||||
}
|
||||
|
||||
# Routers with dynamically resizable number of routees; this feature is enabled
|
||||
# Routers with dynamically resizable number of routees; this feature is enabled
|
||||
# by including (parts of) this section in the deployment
|
||||
resizer {
|
||||
|
||||
|
|
@ -262,23 +262,19 @@ akka {
|
|||
event-stream = off
|
||||
}
|
||||
|
||||
# Entries for pluggable serializers and their bindings. If a binding for a specific
|
||||
# class is not found, then the default serializer (Java serialization) is used.
|
||||
# Entries for pluggable serializers and their bindings.
|
||||
serializers {
|
||||
# java = "akka.serialization.JavaSerializer"
|
||||
java = "akka.serialization.JavaSerializer"
|
||||
# proto = "akka.serialization.ProtobufSerializer"
|
||||
|
||||
default = "akka.serialization.JavaSerializer"
|
||||
}
|
||||
|
||||
# serialization-bindings {
|
||||
# java = ["akka.serialization.SerializeSpec$Address",
|
||||
# "akka.serialization.MyJavaSerializableActor",
|
||||
# "akka.serialization.MyStatelessActorWithMessagesInMailbox",
|
||||
# "akka.serialization.MyActorWithProtobufMessagesInMailbox"]
|
||||
# proto = ["com.google.protobuf.Message",
|
||||
# "akka.actor.ProtobufProtocol$MyMessage"]
|
||||
# }
|
||||
# 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 {
|
||||
"java.io.Serializable" = java
|
||||
#"com.google.protobuf.Message" = proto
|
||||
}
|
||||
}
|
||||
|
||||
# Used to set the behavior of the scheduler.
|
||||
|
|
|
|||
|
|
@ -8,14 +8,21 @@ import akka.AkkaException
|
|||
import akka.util.ReflectiveAccess
|
||||
import scala.util.DynamicVariable
|
||||
import com.typesafe.config.Config
|
||||
import akka.config.ConfigurationException
|
||||
import akka.actor.{ Extension, ActorSystem, ExtendedActorSystem, Address }
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import akka.event.Logging
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import java.io.NotSerializableException
|
||||
|
||||
case class NoSerializerFoundException(m: String) extends AkkaException(m)
|
||||
|
||||
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)
|
||||
* during serialization and deserialization.
|
||||
|
|
@ -40,28 +47,19 @@ object Serialization {
|
|||
import scala.collection.JavaConverters._
|
||||
import config._
|
||||
|
||||
val Serializers: Map[String, String] =
|
||||
getConfig("akka.actor.serializers").root.unwrapped.asScala.toMap.map { case (k, v) ⇒ (k, v.toString) }
|
||||
val Serializers: Map[String, String] = configToMap(getConfig("akka.actor.serializers"))
|
||||
|
||||
val SerializationBindings: Map[String, Seq[String]] = {
|
||||
val configPath = "akka.actor.serialization-bindings"
|
||||
hasPath(configPath) match {
|
||||
case false ⇒ Map()
|
||||
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
|
||||
val SerializationBindings: Map[String, String] = configToMap(getConfig("akka.actor.serialization-bindings"))
|
||||
|
||||
private def configToMap(cfg: Config): Map[String, String] =
|
||||
cfg.root.unwrapped.asScala.toMap.map { case (k, v) ⇒ (k, v.toString) }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
import Serialization._
|
||||
|
|
@ -105,8 +103,10 @@ class Serialization(val system: ExtendedActorSystem) extends Extension {
|
|||
} catch { case e: Exception ⇒ Left(e) }
|
||||
|
||||
/**
|
||||
* Returns the Serializer configured for the given object, returns the NullSerializer if it's null,
|
||||
* falls back to the Serializer named "default"
|
||||
* Returns the Serializer configured for the given object, returns the NullSerializer if it's null.
|
||||
*
|
||||
* @throws akka.config.ConfigurationException if no `serialization-bindings` is configured for the
|
||||
* class of the object
|
||||
*/
|
||||
def findSerializerFor(o: AnyRef): Serializer = o match {
|
||||
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".
|
||||
* It traverses interfaces and super classes to find any configured Serializer that match
|
||||
* the class name.
|
||||
* Returns the configured Serializer for the given Class. The configured Serializer
|
||||
* is used if the configured class `isAssignableFrom` from the `clazz`, i.e.
|
||||
* 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 =
|
||||
if (bindings.isEmpty) {
|
||||
// quick path to default when no bindings are registered
|
||||
serializers("default")
|
||||
} else {
|
||||
|
||||
def resolve(c: Class[_]): Option[Serializer] =
|
||||
serializerMap.get(c.getName) match {
|
||||
case null ⇒
|
||||
val classes = c.getInterfaces ++ Option(c.getSuperclass)
|
||||
classes.view map resolve collectFirst { case Some(x) ⇒ x }
|
||||
case x ⇒ Some(x)
|
||||
serializerMap.get(clazz) match {
|
||||
case null ⇒
|
||||
val ser = bindings.find { case (c, s) ⇒ c.isAssignableFrom(clazz) } match {
|
||||
case None ⇒ throw new NotSerializableException(
|
||||
"No configured serialization-bindings for class [%s]" format clazz.getName)
|
||||
case Some((c, s)) ⇒ s
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
// memorize for performance
|
||||
serializerMap.putIfAbsent(clazz, 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] =
|
||||
ReflectiveAccess.createInstance(serializerFQN, ReflectiveAccess.noParams, ReflectiveAccess.noArgs, system.internalClassLoader)
|
||||
|
||||
/**
|
||||
* A Map of serializer from alias to implementation (class implementing akka.serialization.Serializer)
|
||||
* By default always contains the following mapping: "default" -> akka.serialization.JavaSerializer
|
||||
* But "default" can be overridden in config
|
||||
* By default always contains the following mapping: "java" -> akka.serialization.JavaSerializer
|
||||
*/
|
||||
lazy val serializers: Map[String, Serializer] = {
|
||||
val serializersConf = settings.Serializers
|
||||
for ((k: String, v: String) ← serializersConf)
|
||||
private val serializers: Map[String, Serializer] = {
|
||||
for ((k: String, v: String) ← settings.Serializers)
|
||||
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] = {
|
||||
settings.SerializationBindings.foldLeft(Map[String, String]()) {
|
||||
//All keys which are lists, take the Strings from them and Map them
|
||||
case (result, (k: String, vs: Seq[_])) ⇒ result ++ (vs collect { case v: String ⇒ (v, k) })
|
||||
//For any other values, just skip them
|
||||
case (result, _) ⇒ result
|
||||
private[akka] val bindings: Seq[ClassSerializer] = {
|
||||
val configuredBindings = for ((k: String, v: String) ← settings.SerializationBindings) yield {
|
||||
val c = ReflectiveAccess.getClassFor(k, system.internalClassLoader).fold(throw _, (c: Class[_]) ⇒ c)
|
||||
(c, serializers(v))
|
||||
}
|
||||
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] = {
|
||||
val serializerMap = new ConcurrentHashMap[String, Serializer]
|
||||
for ((k, v) ← bindings) {
|
||||
serializerMap.put(k, serializers(v))
|
||||
private def sort(in: Iterable[ClassSerializer]): Seq[ClassSerializer] =
|
||||
(new ArrayBuffer[ClassSerializer](in.size) /: in) { (buf, ca) ⇒
|
||||
buf.indexWhere(_._1 isAssignableFrom ca._1) match {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,61 +54,7 @@ public class SerializationDocTestBase {
|
|||
}
|
||||
}
|
||||
//#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() {
|
||||
//#programmatic
|
||||
|
|
|
|||
|
|
@ -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``
|
||||
you wish to use, like this:
|
||||
|
||||
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java#serialize-serializers-config
|
||||
|
||||
.. note::
|
||||
|
||||
The name ``default`` is special in the sense that the ``Serializer``
|
||||
mapped to it will be used as default.
|
||||
.. includecode:: ../scala/code/akka/docs/serialization/SerializationDocSpec.scala#serialize-serializers-config
|
||||
|
||||
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:
|
||||
|
||||
.. 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
|
||||
that. E.g. ``com.google.protobuf.Message`` for protobuf serialization.
|
||||
|
||||
Protobuf
|
||||
--------
|
||||
|
||||
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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
Akka provides serializers for ``java.io.Serializable`` and `protobuf <http://code.google.com/p/protobuf/>`_
|
||||
``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``
|
||||
and ``com.google.protobuf.Message``.
|
||||
|
||||
Verification
|
||||
------------
|
||||
|
||||
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::
|
||||
|
||||
|
|
@ -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:
|
||||
|
||||
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java#serialize-creators-config
|
||||
.. includecode:: ../scala/code/akka/docs/serialization/SerializationDocSpec.scala#serialize-creators-config
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ class MyOwnSerializer extends Serializer {
|
|||
}
|
||||
//#my-own-serializer
|
||||
|
||||
trait MyOwnSerializable
|
||||
case class Customer(name: String) extends MyOwnSerializable
|
||||
|
||||
class SerializationDocSpec extends AkkaSpec {
|
||||
"demonstrate configuration of serialize messages" in {
|
||||
//#serialize-messages-config
|
||||
|
|
@ -82,8 +85,8 @@ class SerializationDocSpec extends AkkaSpec {
|
|||
akka {
|
||||
actor {
|
||||
serializers {
|
||||
default = "akka.serialization.JavaSerializer"
|
||||
|
||||
java = "akka.serialization.JavaSerializer"
|
||||
proto = "akka.serialization.ProtobufSerializer"
|
||||
myown = "akka.docs.serialization.MyOwnSerializer"
|
||||
}
|
||||
}
|
||||
|
|
@ -91,8 +94,6 @@ class SerializationDocSpec extends AkkaSpec {
|
|||
""")
|
||||
//#serialize-serializers-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()
|
||||
}
|
||||
|
||||
|
|
@ -102,31 +103,26 @@ class SerializationDocSpec extends AkkaSpec {
|
|||
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"]
|
||||
}
|
||||
"java.lang.String" = java
|
||||
"akka.docs.serialization.Customer" = java
|
||||
"com.google.protobuf.Message" = proto
|
||||
"akka.docs.serialization.MyOwnSerializable" = myown
|
||||
"java.lang.Boolean" = myown
|
||||
}
|
||||
}
|
||||
}
|
||||
""")
|
||||
//#serialization-bindings-config
|
||||
val a = ActorSystem("system", config)
|
||||
SerializationExtension(a).serializers("default").getClass.getName must equal("akka.serialization.JavaSerializer")
|
||||
SerializationExtension(a).serializers("java").getClass.getName must equal("akka.serialization.JavaSerializer")
|
||||
SerializationExtension(a).serializers("myown").getClass.getName must equal("akka.docs.serialization.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")
|
||||
SerializationExtension(a).serializerFor(classOf[String]).getClass must equal(classOf[JavaSerializer])
|
||||
SerializationExtension(a).serializerFor(classOf[Customer]).getClass must equal(classOf[JavaSerializer])
|
||||
SerializationExtension(a).serializerFor(classOf[java.lang.Boolean]).getClass must equal(classOf[MyOwnSerializer])
|
||||
a.shutdown()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,38 +27,19 @@ you wish to use, like this:
|
|||
|
||||
.. 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
|
||||
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
|
||||
|
||||
.. 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
|
||||
that. E.g. ``com.google.protobuf.Message`` for protobuf serialization.
|
||||
|
||||
Protobuf
|
||||
--------
|
||||
|
||||
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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
Akka provides serializers for ``java.io.Serializable`` and `protobuf <http://code.google.com/p/protobuf/>`_
|
||||
``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``
|
||||
and ``com.google.protobuf.Message``.
|
||||
|
||||
Verification
|
||||
------------
|
||||
|
|
|
|||
|
|
@ -9,6 +9,21 @@ akka {
|
|||
|
||||
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 {
|
||||
|
||||
default {
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue