change serialization to strictly rely on subtyping

- when encountering new message type, check all bindings which map apply
- if multiple are found, choose the most specific one if that exists or
  verify that all mappings yield the same serializer
- in case of remaining ambiguity, throw exception
- also add special handling for “none” serializer mapping: turn off a
  default
This commit is contained in:
Roland 2012-02-07 15:11:16 +01:00
parent 50d107e150
commit 8b9f1caf67
6 changed files with 72 additions and 44 deletions

View file

@ -125,17 +125,23 @@ class Serialization(val system: ExtendedActorSystem) extends Extension {
def serializerFor(clazz: Class[_]): Serializer =
serializerMap.get(clazz) match {
case null
val ser = bindings.collectFirst {
case (c, s) if c.isAssignableFrom(clazz) s
} getOrElse (throw new NotSerializableException(
"No configured serialization-bindings for class [%s]" format clazz.getName))
// bindings are ordered from most specific to least specific
def unique(cs: Seq[Class[_]], ser: Set[Serializer]): Boolean = (cs forall (_ isAssignableFrom cs(0))) || ser.size == 1
// 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
val possible = bindings filter { _._1 isAssignableFrom clazz }
possible.size match {
case 0
throw new NotSerializableException("No configured serialization-bindings for class [%s]" format clazz.getName)
case x if x == 1 || unique(possible map (_._1), possible.map(_._2)(scala.collection.breakOut))
val ser = possible(0)._2
serializerMap.putIfAbsent(clazz, ser) match {
case null
log.debug("Using serializer[{}] for message [{}]", ser.getClass.getName, clazz.getName)
ser
case some some
}
case _
throw new NotSerializableException("Multiple serializers found for " + clazz + ": " + possible)
}
case ser ser
}
@ -160,7 +166,7 @@ class Serialization(val system: ExtendedActorSystem) extends Extension {
* It is primarily ordered by the most specific classes first, and secondly in the configured order.
*/
private[akka] val bindings: Seq[ClassSerializer] = {
val configuredBindings = for ((k: String, v: String) settings.SerializationBindings) yield {
val configuredBindings = for ((k: String, v: String) settings.SerializationBindings if v != "none") yield {
val c = ReflectiveAccess.getClassFor(k, system.internalClassLoader).fold(throw _, identity[Class[_]])
(c, serializers(v))
}