diff --git a/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala b/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala
index df2170905e..8cf314e0d5 100644
--- a/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala
+++ b/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala
@@ -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)
diff --git a/akka-actor/src/main/resources/reference.conf b/akka-actor/src/main/resources/reference.conf
index cdab8e968e..ebeb7766ba 100644
--- a/akka-actor/src/main/resources/reference.conf
+++ b/akka-actor/src/main/resources/reference.conf
@@ -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.
diff --git a/akka-actor/src/main/scala/akka/serialization/Serialization.scala b/akka-actor/src/main/scala/akka/serialization/Serialization.scala
index 05612b9cca..2d313b05a0 100644
--- a/akka-actor/src/main/scala/akka/serialization/Serialization.scala
+++ b/akka-actor/src/main/scala/akka/serialization/Serialization.scala
@@ -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) }
}
diff --git a/akka-docs/java/code/akka/docs/serialization/SerializationDocTestBase.java b/akka-docs/java/code/akka/docs/serialization/SerializationDocTestBase.java
index b68f8f2e79..3db385ca1c 100644
--- a/akka-docs/java/code/akka/docs/serialization/SerializationDocTestBase.java
+++ b/akka-docs/java/code/akka/docs/serialization/SerializationDocTestBase.java
@@ -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
diff --git a/akka-docs/java/serialization.rst b/akka-docs/java/serialization.rst
index 2920538ded..b0721e82cc 100644
--- a/akka-docs/java/serialization.rst
+++ b/akka-docs/java/serialization.rst
@@ -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 `_ 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 `_
+``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::
diff --git a/akka-docs/scala/code/akka/docs/serialization/SerializationDocSpec.scala b/akka-docs/scala/code/akka/docs/serialization/SerializationDocSpec.scala
index 7f1553f75c..ce40adce3e 100644
--- a/akka-docs/scala/code/akka/docs/serialization/SerializationDocSpec.scala
+++ b/akka-docs/scala/code/akka/docs/serialization/SerializationDocSpec.scala
@@ -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()
}
diff --git a/akka-docs/scala/serialization.rst b/akka-docs/scala/serialization.rst
index 6a0867dea2..9cfaf909b9 100644
--- a/akka-docs/scala/serialization.rst
+++ b/akka-docs/scala/serialization.rst
@@ -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 `_ 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 `_
+``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
------------
diff --git a/akka-remote/src/main/resources/reference.conf b/akka-remote/src/main/resources/reference.conf
index 1158d12295..14269d305a 100644
--- a/akka-remote/src/main/resources/reference.conf
+++ b/akka-remote/src/main/resources/reference.conf
@@ -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 {
diff --git a/akka-remote/src/test/scala/akka/serialization/ProtobufSerializerSpec.scala b/akka-remote/src/test/scala/akka/serialization/ProtobufSerializerSpec.scala
new file mode 100644
index 0000000000..474ef485d7
--- /dev/null
+++ b/akka-remote/src/test/scala/akka/serialization/ProtobufSerializerSpec.scala
@@ -0,0 +1,25 @@
+/**
+ * Copyright (C) 2009-2012 Typesafe Inc.
+ */
+
+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])
+ }
+
+ }
+}
+