Java 如何在Scala中序列化函数?

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

我正在研究akka持久性,遇到了对象序列化的典型问题。我的对象(如下所示)具有基本类型和功能。我读了,但是没有人帮我把下面的内容序列化

测试工具

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。我当前的实现将它保存在一个映射中,这是可行的。但我知道序列化是另一种游戏