Java 如何在Scala中序列化函数?
我正在研究akka持久性,遇到了对象序列化的典型问题。我的对象(如下所示)具有基本类型和功能。我读了,但是没有人帮我把下面的内容序列化 测试工具Java 如何在Scala中序列化函数?,java,scala,serialization,akka-persistence,Java,Scala,Serialization,Akka Persistence,我正在研究akka持久性,遇到了对象序列化的典型问题。我的对象(如下所示)具有基本类型和功能。我读了,但是没有人帮我把下面的内容序列化 测试工具 object SerializationUtil { def write(obj: Any): String = { val temp = Files.createTempFile(null, null).toFile val out = new ObjectOutputStream(new FileOutputStream(tem
object SerializationUtil {
def write(obj: Any): String = {
val temp = Files.createTempFile(null, null).toFile
val out = new ObjectOutputStream(new FileOutputStream(temp))
out.writeObject(obj)
out.close()
temp.deleteOnExit()
temp.getAbsolutePath
}
def read[T](file: String) = {
val in = new ObjectInputStream(new FileInputStream(new File(file)))
val obj = in.readObject().asInstanceOf[T]
in.close()
obj
}
}
统计数据
case class Stats(
app: String,
unit: ChronoUnit,
private var _startupDurations: List[Long]
) {
def startupDurations = _startupDurations.sorted
def startupDurations_=(durations: List[Long]) = _startupDurations = durations
@transient lazy val summary: LongSummaryStatistics = {
_startupDurations.asJava.stream()
.collect(summarizingLong(identity[Long]))
}
}
Stats
序列化很好
"SerializationUtil" should "(de)serialize Stats" in {
val file = SerializationUtil.write(newStats())
val state = SerializationUtil.read[Stats](file)
verifyStats(state)
}
但事实并非如此:case类GetStatsForOneRequest(app:String,callback:Stats=>Unit)
还尝试:
trait SerializableRunnable[T] extends scala.Serializable with ((T) => Unit)
将回调实现为SerializableRunnable
的实例,但运气不好
想法
编辑:
也许我应该澄清这个问题的实际用例,以提供更多的上下文。该函数是来自Akka HTTP的回调,如下所示:
path("stats") {
logRequest("/stats") {
completeWith(instanceOf[List[Stats]]) { callback =>
requestHandler ! GetStatsRequest(callback)
}
}
}
参与者持续请求,直到得到响应。构造最终输出可能需要多个响应
我做了一些挖掘,看来回调实现是一个很好的例子。也许您没有完全理解链接的文章。函数序列化的问题是,闭包中捕获的任何内容都必须是可序列化的。你需要的是。这里解释了一切,但要点如下: 什么是结束? Scala中的Lambda函数可以引用外部作用域中的变量,而无需显式地将它们列为参数。执行此操作的函数称为闭包,并捕获它引用的外部变量。例如,
foo
在传递到下面的map
的闭包中被捕获:
val foo = 42
List(1,2,3).map(_ + foo)
为什么序列化会有问题?
查看上面的示例,其中foo
是一个基本值,您不会认为这是一个问题。但是当存在一个封闭类时会发生什么呢
class C {
val myDBconn = ...
val foo = 42
List(1,2,3).map(_ + foo)
}
现在(对许多程序员来说出乎意料的是),闭包捕获了非序列化封闭类的整个this
,包括myDBconn
,因为foo
引用了getter方法this.foo
解决办法是什么?
解决方案是在闭包中不捕获此
。例如,为需要捕获的任何值创建本地val
,可以使函数再次序列化:
class C {
val myDBconn = ...
val foo = 42
{
val localFoo = foo
List(1,2,3).map(_ + localFoo)
}
}
当然,手动执行此操作很乏味,因此。可能您没有完全理解链接的文章。函数序列化的问题是,闭包中捕获的任何内容都必须是可序列化的。你需要的是。这里解释了一切,但要点如下: 什么是结束? Scala中的Lambda函数可以引用外部作用域中的变量,而无需显式地将它们列为参数。执行此操作的函数称为闭包,并捕获它引用的外部变量。例如,
foo
在传递到下面的map
的闭包中被捕获:
val foo = 42
List(1,2,3).map(_ + foo)
为什么序列化会有问题?
查看上面的示例,其中foo
是一个基本值,您不会认为这是一个问题。但是当存在一个封闭类时会发生什么呢
class C {
val myDBconn = ...
val foo = 42
List(1,2,3).map(_ + foo)
}
现在(对许多程序员来说出乎意料的是),闭包捕获了非序列化封闭类的整个this
,包括myDBconn
,因为foo
引用了getter方法this.foo
解决办法是什么?
解决方案是在闭包中不捕获此
。例如,为需要捕获的任何值创建本地val
,可以使函数再次序列化:
class C {
val myDBconn = ...
val foo = 42
{
val localFoo = foo
List(1,2,3).map(_ + localFoo)
}
}
当然,手动执行此操作非常繁琐,因此。当您通过GetStatsForOneRequest时,newStats()的实现是什么?它似乎适用于GetStatsForOneRequest(“应用程序”,单位)。@igorpcholkin只是一个带有虚拟值的
Stats
。问题是回调函数,我真正想看到的是如何构造在SerializationUtil.write调用中使用的GetStatsForOneRequest(包括回调)。当传递GetStatsForOneRequest时,newStats()的实现是什么?它似乎适用于GetStatsForOneRequest(“应用程序”,单位)。@igorpcholkin只是一个带有虚拟值的Stats
。问题是回调函数,我真正想看到的是如何构造您在SerializationUtil.write调用中使用的GetStatsForOneRequest(包括回调)。在我的问题中,我在哪里捕获此?我明白了<代码>回调超出了您的控制范围,因此您无法知道它捕获了什么。但是如果您转到,您将看到它捕获了一个不可序列化的承诺。顺便说一句,callback
这里有一个continuation函数,您必须在退出块之前调用它,而不是序列化。实际上,要完成块,必须调用callback。我当前的实现将它保存在一个映射中,这是可行的。但我知道序列化是一个不同的游戏,在我的问题中,我是否捕捉到了这个
?好的,我明白了<代码>回调超出了您的控制范围,因此您无法知道它捕获了什么。但是如果您转到,您将看到它捕获了一个不可序列化的承诺。顺便说一句,callback
这里有一个continuation函数,您必须在退出块之前调用它,而不是序列化。实际上,要完成块,必须调用callback。我当前的实现将它保存在一个映射中,这是可行的。但我知道序列化是另一种游戏