【问题标题】:Unable to deserialize lambda无法反序列化 lambda
【发布时间】:2015-01-22 00:16:00
【问题描述】:

作为一个小项目,我一直在尝试制作一个读取序列化 lambda(本地或从 FTP)并调用它们的运行函数作为测试的一部分,以在 Windows 中试验文件关联(即打开某些文件类型使用某个程序打开它们)等等,但无论我尝试什么,它似乎都无法正确反序列化。

lambda 是这样声明的

Runnable r = (Runnable & Serializable) () -> {
    // blah blah
    // made sure not to capture anything
};

并使用由 ObjectOutputStream 包装的 [n optional] BufferedOutputStream 包装的 FileOutputStream 进行序列化,没有问题。但是,当反序列化 [在不同的项目中] 时,它会失败,说它找不到包含序列化代码的封闭类。我尝试了各种方法,例如将它们包装在可序列化的类中(w/serialVersionUID = 0L 用于测试目的)或定义扩展可运行和可序列化的接口,但无济于事。

是的,我知道序列化 lambdas 并不是一个很好的做法(或者我们被告知),但我不确定如何将函数和子例程转换为可以存储为文件或存储在一个FTP。如果这根本不是正确的方法,请告诉。

哦,我正在使用最新版本的 Eclipse Luna。

编辑:

像这样反序列化

File f = new File(somePath);
FileInputStream fish = new FileInputStream(f);
BufferedInputStream bos = new BufferedInputStream(fish); // not really necessary
ObjectInputStream ois = new ObjectInputStream(bos);
Runnable r = (Runnable) ois.readObject();
ois.close();
r.run();

【问题讨论】:

  • 等待您尝试序列化方法吗?
  • 方法对象不可序列化。我说的是 Runnable lambda。
  • 你能告诉我们你的序列化/反序列化代码吗?
  • 对我来说看起来很可疑,但我会赞成,这个问题很有趣。
  • 您是否尝试过使用 Oracle JDK?

标签: java serialization lambda java-8


【解决方案1】:

如果没有定义它的类,你不能反序列化一个对象。 lambda 表达式并没有改变这一点。

Lambda 表达式有点复杂,因为它们生成的运行时类不是定义它的类,但它们的定义类是保存 lambda 主体代码的类,并且在可序列化 lambda 的情况下,反序列化支持方法是要求验证和重新实例化 lambda 实例。

SerializedLambda:

可序列化 lambda 的实现者(例如编译器或语言运行时库)应确保实例正确反序列化。这样做的一种方法是确保writeReplace 方法返回SerializedLambda 的实例,而不是允许继续进行默认序列化。

SerializedLambda 有一个readResolve 方法,该方法在捕获类中查找名为$deserializeLambda$(SerializedLambda) 的(可能是私有的)静态方法,将其自身作为第一个参数调用,并返回结果。实现 $deserializeLambda$ 的 Lambda 类负责验证 SerializedLambda 的属性是否与该类实际捕获的 lambda 一致。

因此,即使您的实例没有引用定义类内部的合成方法(例如,在方法引用此类外部方法的情况下),反序列化仍然需要$deserializeLambda$ 来验证实例的正确性,故意的。


关于序列化 lambda 的“良好实践”,请记住 lambda 表达式封装行为,而不是状态。存储行为总是意味着只存储某种引用并要求旨在恢复它的代码已经实现了相关的行为。如果您只是通过符号名称或只是存储来引用预期的行为,那么这也会起作用,例如关联enum 值。

this question 中解释了有关具有可序列化 lambda 的含义的更多信息。

【讨论】:

  • 存储与状态无关的子例程(如果有)而不是做我正在做的事情的“标准”方式可能是什么?
  • 没有标准的方法,因为通常你不会存储例程而是数据。如果要存储行为,则必须在恢复站点上提供定义类或真正存储代码,作为字节码或表达式String,必须对其进行解析。
  • 哪种方式不是不好的做法?此外,无论哪种方式更好,如何在运行时解析 Java 语句/表达式或存储直接字节码?我觉得这似乎不是很好的做法,只是想学习如何在程序之间、进程之间传递特定于 Java 的指令。
【解决方案2】:

当您反序列化一个对象时,执行反序列化的代码必须知道序列化对象的类。您不能序列化任意 lambda 并在另一个代码库中反序列化它。

或多或少,序列化和反序列化代码必须在同一个代码库中,或者至少必须共享对包含原始 lambda 的代码的依赖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    相关资源
    最近更新 更多