diff --git a/akka-actor/src/main/scala/akka/actor/TypedActor.scala b/akka-actor/src/main/scala/akka/actor/TypedActor.scala index ffd7184e6d..1511419184 100644 --- a/akka-actor/src/main/scala/akka/actor/TypedActor.scala +++ b/akka-actor/src/main/scala/akka/actor/TypedActor.scala @@ -10,6 +10,8 @@ import akka.dispatch.{ MessageDispatcher, Dispatchers, Future, FutureTimeoutExce import java.lang.reflect.{ InvocationTargetException, Method, InvocationHandler, Proxy } import akka.util.{ Duration } import java.util.concurrent.atomic.{ AtomicReference ⇒ AtomVar } +import akka.serialization.Serialization +import com.sun.xml.internal.ws.developer.MemberSubmissionAddressing.Validation //TODO Document this class, not only in Scaladoc, but also in a dedicated typed-actor.rst, for both java and scala /** @@ -87,16 +89,35 @@ object TypedActor { } } catch { case i: InvocationTargetException ⇒ throw i.getTargetException } - private def writeReplace(): AnyRef = new SerializedMethodCall(method.getDeclaringClass, method.getName, method.getParameterTypes, parameters) + private def writeReplace(): AnyRef = { + val serializedParameters: Array[(Array[Byte],String)] = parameters match { + case null => null + case a if a.length == 0 => Array[(Array[Byte],String)]() + case a => a.map( { + case null => null + case value => Serialization.serializerFor(value.getClass).fold(throw _, s => (s.toBinary(value), s.getClass.getName)) + }) + } + new SerializedMethodCall(method.getDeclaringClass, method.getName, method.getParameterTypes, serializedParameters) + } } /** * Represents the serialized form of a MethodCall, uses readResolve and writeReplace to marshall the call */ - case class SerializedMethodCall(ownerType: Class[_], methodName: String, parameterTypes: Array[Class[_]], parameterValues: Array[AnyRef]) { + case class SerializedMethodCall(ownerType: Class[_], methodName: String, parameterTypes: Array[Class[_]], serializedParameters: Array[(Array[Byte],String)]) { //TODO implement writeObject and readObject to serialize //TODO Possible optimization is to special encode the parameter-types to conserve space - private def readResolve(): AnyRef = MethodCall(ownerType.getDeclaredMethod(methodName, parameterTypes: _*), parameterValues) + private def readResolve(): AnyRef = { + MethodCall(ownerType.getDeclaredMethod(methodName, parameterTypes: _*), serializedParameters match { + case null => null + case a if a.length == 0 => Array[AnyRef]() + case a => a.map( { + case null => null + case (bytes, serializerFQN) => Serialization.serializerOf(serializerFQN).fold(throw _, _.fromBinary(bytes)) + }) + }) + } } /** diff --git a/akka-actor/src/main/scala/akka/serialization/Serialization.scala b/akka-actor/src/main/scala/akka/serialization/Serialization.scala index 8581a9abba..49dd527be6 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serialization.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serialization.scala @@ -9,6 +9,7 @@ import akka.config.Config import akka.config.Config._ import akka.actor.{ ActorRef, Actor } import akka.AkkaException +import akka.util.ReflectiveAccess case class NoSerializerFoundException(m: String) extends AkkaException(m) @@ -40,6 +41,12 @@ object Serialization { case Left(e) => Left(e) } + /** + * Tries to load the specified Serializer by the FQN + */ + def serializerOf(serializerFQN: String): Either[Exception, Serializer] = + createInstance(serializerFQN, ReflectiveAccess.emptyParams, ReflectiveAccess.emptyArguments) + private def serializerForBestMatchClass(cl: Class[_]): Either[Exception, Serializer] = { if (bindings.isEmpty) Left(NoSerializerFoundException("No mapping serializer found for " + cl)) @@ -51,11 +58,7 @@ object Serialization { case _ ⇒ false } } map { - case (_, ser) ⇒ - getClassFor(ser) match { - case Right(s) ⇒ Right(s.newInstance.asInstanceOf[Serializer]) - case _ ⇒ Left(new Exception("Error instantiating " + ser)) - } + case (_, ser) ⇒ serializerOf(ser) } getOrElse Left(NoSerializerFoundException("No mapping serializer found for " + cl)) } } diff --git a/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala b/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala index 9d439a8876..3f0f33f01c 100644 --- a/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala +++ b/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala @@ -23,6 +23,8 @@ import java.net.InetSocketAddress object ReflectiveAccess { val loader = getClass.getClassLoader + val emptyParams: Array[Class[_]] = Array() + val emptyArguments: Array[AnyRef] = Array() /** * Reflective access to the Cluster module.