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
This commit is contained in:
parent
15fa414d46
commit
2ce47d6bb5
35 changed files with 322 additions and 300 deletions
|
|
@ -6,11 +6,29 @@ package akka.serialization
|
|||
|
||||
import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream }
|
||||
import akka.util.ClassLoaderObjectInputStream
|
||||
import akka.actor.PropertyMaster
|
||||
import akka.actor.ExtendedActorSystem
|
||||
import scala.util.DynamicVariable
|
||||
|
||||
/**
|
||||
* A Serializer represents a bimap between an object and an array of bytes representing that object
|
||||
* 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.propertyMaster (see
|
||||
* [[akka.actor.PropertyMaster]]), and</li>
|
||||
* <li>without arguments, which is only an option if the serializer does not
|
||||
* load classes using reflection.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <b>Be sure to always use the PropertyManager for loading classes!</b>
|
||||
*/
|
||||
trait Serializer extends scala.Serializable {
|
||||
|
||||
/**
|
||||
* Completely unique value to identify this implementation of Serializer, used to optimize network traffic
|
||||
* Values from 0 to 16 is reserved for Akka internal usage
|
||||
|
|
@ -28,42 +46,52 @@ trait Serializer extends scala.Serializable {
|
|||
def includeManifest: Boolean
|
||||
|
||||
/**
|
||||
* Deserializes the given Array of Bytes into an AnyRef
|
||||
* Produces an object from an array of bytes, with an optional type-hint;
|
||||
* the class should be loaded using ActorSystem.propertyMaster.
|
||||
*/
|
||||
def fromBinary(bytes: Array[Byte]): AnyRef = fromBinary(bytes, None, None)
|
||||
|
||||
/**
|
||||
* Deserializes the given Array of Bytes into an AnyRef with an optional type hint
|
||||
*/
|
||||
def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef = fromBinary(bytes, manifest, None)
|
||||
|
||||
/**
|
||||
* Produces an object from an array of bytes, with an optional type-hint and a classloader to load the class into
|
||||
*/
|
||||
def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]], classLoader: Option[ClassLoader]): AnyRef
|
||||
def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef
|
||||
}
|
||||
|
||||
/**
|
||||
* Java API for creating a Serializer
|
||||
* 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 {
|
||||
def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]] = None, classLoader: Option[ClassLoader] = None): AnyRef =
|
||||
fromBinary(bytes, manifest.orNull, classLoader.orNull)
|
||||
def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef =
|
||||
fromBinary(bytes, manifest.orNull)
|
||||
|
||||
/**
|
||||
* This method should be overridden,
|
||||
* manifest and classLoader may be null.
|
||||
*/
|
||||
def fromBinary(bytes: Array[Byte], manifest: Class[_], classLoader: ClassLoader): AnyRef
|
||||
def fromBinary(bytes: Array[Byte], manifest: Class[_]): AnyRef
|
||||
}
|
||||
|
||||
object JavaSerializer extends JavaSerializer
|
||||
object NullSerializer extends NullSerializer
|
||||
|
||||
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...
|
||||
* }
|
||||
*/
|
||||
val currentSystem = new DynamicVariable[ExtendedActorSystem](null)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This Serializer uses standard Java Serialization
|
||||
*/
|
||||
class JavaSerializer extends Serializer {
|
||||
class JavaSerializer(val system: ExtendedActorSystem) extends Serializer {
|
||||
|
||||
def includeManifest: Boolean = false
|
||||
|
||||
|
|
@ -77,12 +105,11 @@ class JavaSerializer extends Serializer {
|
|||
bos.toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None,
|
||||
classLoader: Option[ClassLoader] = None): AnyRef = {
|
||||
val in =
|
||||
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) else
|
||||
new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
val obj = in.readObject
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
||||
val in = new ClassLoaderObjectInputStream(system.propertyMaster.classLoader, new ByteArrayInputStream(bytes))
|
||||
val obj = JavaSerializer.currentSystem.withValue(system) {
|
||||
in.readObject
|
||||
}
|
||||
in.close()
|
||||
obj
|
||||
}
|
||||
|
|
@ -96,5 +123,5 @@ class NullSerializer extends Serializer {
|
|||
def includeManifest: Boolean = false
|
||||
def identifier = 0
|
||||
def toBinary(o: AnyRef) = nullAsBytes
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None, classLoader: Option[ClassLoader] = None): AnyRef = null
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = null
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue