pekko/akka-actor/src/main/scala/akka/serialization/Serializer.scala

438 lines
16 KiB
Scala
Raw Normal View History

/*
* Copyright (C) 2018 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.serialization
/**
2018-01-04 17:26:29 +00:00
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
*/
import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, NotSerializableException, ObjectOutputStream }
import java.nio.ByteBuffer
import java.util.concurrent.Callable
import akka.util.ClassLoaderObjectInputStream
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
import akka.actor.ExtendedActorSystem
import akka.annotation.InternalApi
import akka.event.{ LogMarker, Logging }
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
import scala.util.DynamicVariable
import scala.util.control.NoStackTrace
2011-07-19 19:28:17 +02:00
/**
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
* A Serializer represents a bimap between an object and an array of bytes representing that object.
*
* Serializers are loaded using reflection during [[akka.actor.ActorSystem]]
* start-up, where two constructors are tried in order:
*
* <ul>
* <li>taking exactly one argument of type [[akka.actor.ExtendedActorSystem]];
* this should be the preferred one because all reflective loading of classes
* during deserialization should use ExtendedActorSystem.dynamicAccess (see
* [[akka.actor.DynamicAccess]]), and</li>
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
* <li>without arguments, which is only an option if the serializer does not
* load classes using reflection.</li>
* </ul>
*
2016-03-10 10:10:44 +01:00
* <b>Be sure to always use the </b>[[akka.actor.DynamicAccess]]<b> for loading classes!</b> This is necessary to
2012-02-09 19:26:02 +01:00
* avoid strange match errors and inequalities which arise from different class loaders loading
* the same class.
2011-07-19 19:28:17 +02:00
*/
trait Serializer {
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
/**
* Completely unique value to identify this implementation of Serializer, used to optimize network traffic.
* Values from 0 to 40 are reserved for Akka internal usage.
*/
def identifier: Int
2011-07-19 19:28:17 +02:00
/**
* Serializes the given object into an Array of Byte
*/
def toBinary(o: AnyRef): Array[Byte]
2011-07-19 19:28:17 +02:00
2011-12-29 16:11:56 +01:00
/**
* Returns whether this serializer needs a manifest in the fromBinary method
*/
def includeManifest: Boolean
/**
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
* Produces an object from an array of bytes, with an optional type-hint;
* the class should be loaded using ActorSystem.dynamicAccess.
2011-07-19 19:28:17 +02:00
*/
@throws(classOf[NotSerializableException])
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef
/**
* Java API: deserialize without type hint
*/
final def fromBinary(bytes: Array[Byte]): AnyRef = fromBinary(bytes, None)
/**
* Java API: deserialize with type hint
*/
@throws(classOf[NotSerializableException])
final def fromBinary(bytes: Array[Byte], clazz: Class[_]): AnyRef = fromBinary(bytes, Option(clazz))
}
object Serializers {
// NOTE!!! If you change this method it is likely that DaemonMsgCreateSerializer.serialize needs the changes too.
def manifestFor(s: Serializer, message: AnyRef): String = s match {
case s2: SerializerWithStringManifest s2.manifest(message)
case _ if (s.includeManifest) message.getClass.getName else ""
}
}
/**
* A Serializer represents a bimap between an object and an array of bytes representing that object.
*
* For serialization of data that need to evolve over time the `SerializerWithStringManifest` is recommended instead
* of [[Serializer]] because the manifest (type hint) is a `String` instead of a `Class`. That means
* that the class can be moved/removed and the serializer can still deserialize old data by matching
* on the `String`. This is especially useful for Akka Persistence.
*
2016-03-10 10:10:44 +01:00
* The manifest string can also encode a version number that can be used in `fromBinary` to
* deserialize in different ways to migrate old data to new domain objects.
*
* If the data was originally serialized with [[Serializer]] and in a later version of the
* system you change to `SerializerWithStringManifest` the manifest string will be the full class name if
* you used `includeManifest=true`, otherwise it will be the empty string.
*
* Serializers are loaded using reflection during [[akka.actor.ActorSystem]]
* start-up, where two constructors are tried in order:
*
* <ul>
* <li>taking exactly one argument of type [[akka.actor.ExtendedActorSystem]];
* this should be the preferred one because all reflective loading of classes
* during deserialization should use ExtendedActorSystem.dynamicAccess (see
* [[akka.actor.DynamicAccess]]), and</li>
* <li>without arguments, which is only an option if the serializer does not
* load classes using reflection.</li>
* </ul>
*
2016-03-10 10:10:44 +01:00
* <b>Be sure to always use the </b>[[akka.actor.DynamicAccess]]<b> for loading classes!</b> This is necessary to
* avoid strange match errors and inequalities which arise from different class loaders loading
* the same class.
*/
abstract class SerializerWithStringManifest extends Serializer {
/**
* Completely unique value to identify this implementation of Serializer, used to optimize network traffic.
* Values from 0 to 40 are reserved for Akka internal usage.
*/
def identifier: Int
final override def includeManifest: Boolean = true
/**
* Return the manifest (type hint) that will be provided in the fromBinary method.
* Use `""` if manifest is not needed.
*/
def manifest(o: AnyRef): String
/**
* Serializes the given object into an Array of Byte
*/
def toBinary(o: AnyRef): Array[Byte]
/**
* Produces an object from an array of bytes, with an optional type-hint;
* the class should be loaded using ActorSystem.dynamicAccess.
*
* It's recommended to throw `java.io.NotSerializableException` in `fromBinary`
* if the manifest is unknown. This makes it possible to introduce new message
* types and send them to nodes that don't know about them. This is typically
* needed when performing rolling upgrades, i.e. running a cluster with mixed
* versions for while. `NotSerializableException` is treated as a transient
* problem in the TCP based remoting layer. The problem will be logged
* and message is dropped. Other exceptions will tear down the TCP connection
* because it can be an indication of corrupt bytes from the underlying transport.
*/
@throws(classOf[NotSerializableException])
def fromBinary(bytes: Array[Byte], manifest: String): AnyRef
final def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef = {
val manifestString = manifest match {
case Some(c) c.getName
case None ""
}
fromBinary(bytes, manifestString)
}
}
/**
* Serializer between an object and a `ByteBuffer` representing that object.
*
* Implementations should typically extend [[SerializerWithStringManifest]] and
* in addition to the `ByteBuffer` based `toBinary` and `fromBinary` methods also
* implement the array based `toBinary` and `fromBinary` methods. The array based
* methods will be used when `ByteBuffer` is not used, e.g. in Akka Persistence.
*
* Note that the array based methods can for example be implemented by delegation
* like this:
* {{{
* // you need to know the maximum size in bytes of the serialized messages
* val pool = new akka.io.DirectByteBufferPool(defaultBufferSize = 1024 * 1024, maxPoolEntries = 10)
*
*
* // Implement this method for compatibility with `SerializerWithStringManifest`.
* override def toBinary(o: AnyRef): Array[Byte] = {
* val buf = pool.acquire()
* try {
* toBinary(o, buf)
* buf.flip()
* val bytes = new Array[Byte](buf.remaining)
* buf.get(bytes)
* bytes
* } finally {
* pool.release(buf)
* }
* }
*
* // Implement this method for compatibility with `SerializerWithStringManifest`.
* override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
* fromBinary(ByteBuffer.wrap(bytes), manifest)
*
* }}}
*/
//#ByteBufferSerializer
trait ByteBufferSerializer {
/**
* Serializes the given object into the `ByteBuffer`.
*/
def toBinary(o: AnyRef, buf: ByteBuffer): Unit
/**
* Produces an object from a `ByteBuffer`, with an optional type-hint;
* the class should be loaded using ActorSystem.dynamicAccess.
*/
@throws(classOf[NotSerializableException])
def fromBinary(buf: ByteBuffer, manifest: String): AnyRef
}
//#ByteBufferSerializer
/**
* Base serializer trait with serialization identifiers configuration contract,
* when globally unique serialization identifier is configured in the `reference.conf`.
*/
trait BaseSerializer extends Serializer {
/**
* Actor system which is required by most serializer implementations.
*/
def system: ExtendedActorSystem
2016-03-10 10:10:44 +01:00
/**
* Configuration namespace of serialization identifiers in the `reference.conf`.
*
* Each serializer implementation must have an entry in the following format:
* `akka.actor.serialization-identifiers."FQCN" = ID`
* where `FQCN` is fully qualified class name of the serializer implementation
* and `ID` is globally unique serializer identifier number.
*/
final val SerializationIdentifiers = BaseSerializer.SerializationIdentifiers
2016-03-10 10:10:44 +01:00
/**
* Globally unique serialization identifier configured in the `reference.conf`.
*
2016-03-10 10:10:44 +01:00
* See [[Serializer#identifier]].
*/
override val identifier: Int = identifierFromConfig
/**
* INTERNAL API
*/
@InternalApi
private[akka] def identifierFromConfig: Int =
BaseSerializer.identifierFromConfig(getClass, system)
}
object BaseSerializer {
/**
* Configuration namespace of serialization identifiers in the `reference.conf`.
*
* Each serializer implementation must have an entry in the following format:
* `akka.actor.serialization-identifiers."FQCN" = ID`
* where `FQCN` is fully qualified class name of the serializer implementation
* and `ID` is globally unique serializer identifier number.
*/
final val SerializationIdentifiers = "akka.actor.serialization-identifiers"
/** INTERNAL API */
@InternalApi
private[akka] def identifierFromConfig(clazz: Class[_], system: ExtendedActorSystem): Int =
system.settings.config.getInt(s"""${SerializationIdentifiers}."${clazz.getName}"""")
}
/**
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
* Java API for creating a Serializer: make sure to include a constructor which
* takes exactly one argument of type [[akka.actor.ExtendedActorSystem]], because
* that is the preferred constructor which will be invoked when reflectively instantiating
* the JSerializer (also possible with empty constructor).
*/
abstract class JSerializer extends Serializer {
@throws(classOf[NotSerializableException])
final def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef =
fromBinaryJava(bytes, manifest.orNull)
/**
* This method must be implemented, manifest may be null.
*/
protected def fromBinaryJava(bytes: Array[Byte], manifest: Class[_]): AnyRef
}
object NullSerializer extends NullSerializer
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
object JavaSerializer {
/**
* This holds a reference to the current ActorSystem (the surrounding context)
* during serialization and deserialization.
*
* If you are using Serializers yourself, outside of SerializationExtension,
* you'll need to surround the serialization/deserialization with:
*
* currentSystem.withValue(system) {
* ...code...
* }
*
* or
*
* currentSystem.withValue(system, callable)
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
*/
val currentSystem = new CurrentSystem
final class CurrentSystem extends DynamicVariable[ExtendedActorSystem](null) {
/**
* Java API: invoke the callable with the current system being set to the given value for this thread.
*
* @param value - the current value under the call to callable.call()
* @param callable - the operation to be performed
* @return the result of callable.call()
*/
def withValue[S](value: ExtendedActorSystem, callable: Callable[S]): S = super.withValue[S](value)(callable.call)
}
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
}
/**
* This Serializer uses standard Java Serialization
*/
class JavaSerializer(val system: ExtendedActorSystem) extends BaseSerializer {
if (!system.settings.AllowJavaSerialization)
throw new DisabledJavaSerializer.JavaSerializationException("Attempted creation of `JavaSerializer` while `akka.actor.allow-java-serialization = off` was set!")
2011-12-29 16:11:56 +01:00
def includeManifest: Boolean = false
def toBinary(o: AnyRef): Array[Byte] = {
val bos = new ByteArrayOutputStream
val out = new ObjectOutputStream(bos)
JavaSerializer.currentSystem.withValue(system) { out.writeObject(o) }
out.close()
bos.toByteArray
}
@throws(classOf[NotSerializableException])
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
val in = new ClassLoaderObjectInputStream(system.dynamicAccess.classLoader, new ByteArrayInputStream(bytes))
val obj = JavaSerializer.currentSystem.withValue(system) { in.readObject }
in.close()
obj
}
}
/**
* This Serializer is used when `akka.actor.java-serialization = off`
*/
final case class DisabledJavaSerializer(system: ExtendedActorSystem) extends Serializer with ByteBufferSerializer {
import DisabledJavaSerializer._
// use same identifier as JavaSerializer, since it's a replacement
override val identifier: Int = BaseSerializer.identifierFromConfig(classOf[JavaSerializer], system)
private[this] val empty = Array.empty[Byte]
private[this] val log = Logging.withMarker(system, getClass)
def includeManifest: Boolean = false
override def toBinary(o: AnyRef, buf: ByteBuffer): Unit = {
log.warning(LogMarker.Security, "Outgoing message attempted to use Java Serialization even though `akka.actor.allow-java-serialization = off` was set! " +
"Message type was: [{}]", o.getClass)
throw IllegalSerialization
}
@throws(classOf[NotSerializableException])
override def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
log.warning(LogMarker.Security, "Incoming message attempted to use Java Serialization even though `akka.actor.allow-java-serialization = off` was set!")
throw IllegalDeserialization
}
@throws(classOf[NotSerializableException])
override def fromBinary(buf: ByteBuffer, manifest: String): AnyRef = {
// we don't capture the manifest or mention it in the log as the default setting for includeManifest is set to false.
log.warning(LogMarker.Security, "Incoming message attempted to use Java Serialization even though `akka.actor.allow-java-serialization = off` was set!")
throw IllegalDeserialization
}
override def toBinary(o: AnyRef): Array[Byte] = {
toBinary(o, null)
empty // won't return, toBinary throws
}
}
object DisabledJavaSerializer {
final class JavaSerializationException(msg: String) extends RuntimeException(msg) with NoStackTrace
final val IllegalSerialization = new JavaSerializationException("Attempted to serialize message using Java serialization while `akka.actor.allow-java-serialization` was disabled. Check WARNING logs for more details.")
final val IllegalDeserialization = new JavaSerializationException("Attempted to deserialize message using Java serialization while `akka.actor.allow-java-serialization` was disabled. Check WARNING logs for more details.")
}
/**
* This is a special Serializer that Serializes and deserializes nulls only
*/
class NullSerializer extends Serializer {
val nullAsBytes = Array[Byte]()
2011-12-29 16:11:56 +01:00
def includeManifest: Boolean = false
def identifier = 0
def toBinary(o: AnyRef): Array[Byte] = nullAsBytes
@throws(classOf[NotSerializableException])
Bye-bye ReflectiveAccess, introducing PropertyMaster, see #1750 - PropertyMaster is the only place in Akka which calls ClassLoader.getClass (apart from kernel, which might be special) - all PropertyMaster methods (there are only three) take a ClassManifest of what is to be constructed, and they verify that the obtained object is actually compatible with the required type Other stuff: - noticed that I had forgotten to change to ExtendedActorSystem when constructing Extensions by ExtensionKey (damn you, reflection!) - moved Serializer.currentSystem into JavaSerializer, because that’s the only one needing it (it’s only used in readResolve() methods) - Serializers are constructed now with one-arg constructor taking ExtendedActorSystem (if that exists, otherwise no-arg as before), to allow JavaSerializer to do its magic; possibly necessary for others as well - Removed all Option[ClassLoader] signatures - made it so that the ActorSystem will try context class loader, then the class loader which loaded the class actually calling into ActorSystem.apply, then the loader which loaded ActorSystemImpl - for the second of the above I added a (reflectively accessed hopefully safe) facility for getting caller Class[_] objects by using sun.reflect.Reflection; this is optional an defaults to None, e.g. on Android, which means that getting the caller’s classloader is done on a best effort basis (there’s nothing we can do because a StackTrace does not contain actual Class[_] objects). - refactored DurableMailbox to contain the owner val and use that instead of declaring that in all subclasses
2012-02-09 11:56:43 +01:00
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = null
}
/**
* This is a special Serializer that Serializes and deserializes byte arrays only,
* (just returns the byte array unchanged/uncopied)
*/
class ByteArraySerializer(val system: ExtendedActorSystem) extends BaseSerializer with ByteBufferSerializer {
def includeManifest: Boolean = false
def toBinary(o: AnyRef): Array[Byte] = o match {
case null null
case o: Array[Byte] o
case other throw new IllegalArgumentException(
s"${getClass.getName} only serializes byte arrays, not [${other.getClass.getName}]")
}
@throws(classOf[NotSerializableException])
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = bytes
override def toBinary(o: AnyRef, buf: ByteBuffer): Unit =
o match {
case null
case bytes: Array[Byte] buf.put(bytes)
case other throw new IllegalArgumentException(
s"${getClass.getName} only serializes byte arrays, not [${other.getClass.getName}]")
}
@throws(classOf[NotSerializableException])
override def fromBinary(buf: ByteBuffer, manifest: String): AnyRef = {
val bytes = new Array[Byte](buf.remaining())
buf.get(bytes)
bytes
}
}