是否可以为 akka 编写一个 upickle Serializer

Is it possible to write a upickle Serializer for akka

我想使用 upickle 实现一个 akka Serializer,但我不确定它是否可行。为此,我需要实现如下所示的序列化程序:

import akka.serialization.Serializer
import upickle.default._

class UpickleSerializer extends Serializer {

    def includeManifest: Boolean = true
    def identifier = 1234567

    def toBinary(obj: AnyRef): Array[Byte] = {
        writeBinary(obj) // ???
    }

    def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
        readBinary(bytes) // ???
    }
}

问题是如果没有相关的 Writer/Reader,我无法调用 writeBinary/readBinary。有什么方法可以根据对象 class?

查找这些内容

看看下面的文件,你应该会有一些想法!

CborAkkaSerializer.scala

LocationAkkaSerializer.scala

注意:这些序列化程序使用的是 cbor

我找到了一种使用反射的方法。我的解决方案基于以下假设:任何需要序列化的对象都应该在其伴随对象中定义了一个 ReadWriter:

class UpickleSerializer extends Serializer {

private var map = Map[Class[_], ReadWriter[AnyRef]]()

def includeManifest: Boolean = true
def identifier = 1234567

def toBinary(obj: AnyRef): Array[Byte] = {
    implicit val rw = getReadWriter(obj.getClass)
    writeBinary(obj)
}

def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
    implicit val rw = lookup(clazz.get)
    readBinary[AnyRef](bytes)
}

private def getReadWriter(clazz: Class[_]) = map.get(clazz) match {
    case Some(rw) => rw
    case None =>
        val rw = lookup(clazz)
        map += clazz -> rw
        rw
}

private def lookup(clazz: Class[_]) = {
    import scala.reflect.runtime._
    val rootMirror = universe.runtimeMirror(clazz.getClassLoader)
    val classSymbol = rootMirror.classSymbol(clazz)
    val moduleSymbol = classSymbol.companion.asModule
    val moduleMirror = rootMirror.reflectModule(moduleSymbol)
    val instanceMirror = rootMirror.reflect(moduleMirror.instance)
    val members = instanceMirror.symbol.typeSignature.members
    members.find(_.typeSignature <:< typeOf[ReadWriter[_]]) match {
        case Some(rw) =>
            instanceMirror.reflectField(rw.asTerm).get.asInstanceOf[ReadWriter[AnyRef]]
        case None =>
            throw new RuntimeException("Not found")
    }
}

}