无法反序列化 lambda [英] Unable to deserialize lambda

查看:37
本文介绍了无法反序列化 lambda的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Just as a small project, I've been trying to make a wee thing that reads serialized lambdas (locally or from an FTP) and invokes their run functions as part of a test to experiment with file associations in Windows (i.e. opening certain file types opens them with a certain program) and whatnot, but no matter what I try, it never seems to properly deserialize.

lambda 是这样声明的

The lambda was declared like so

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

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

and serialized using a FileOutputStream wrapped by a[n optional] BufferedOutputStream wrapped by an ObjectOutputStream without issue. However, when deserialized [in a different project], it fails, saying that it could not find the enclosing class that contained the code for serializing it. I've tried various things like wrapping them in a serializable class (w/serialVersionUID = 0L for testing purposes) or defining a an interface that extends Runnable and Serializable, but to no avail.

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

Yes, I am aware that serializing lambdas isn't really good practice (or so we're told), but I'm not sure how to go about turning functions and subroutines into something I can store as a file or in an FTP. If this isn't even the right way at all, do tell.

哦,我使用的是最新版本的 Eclipse Luna.

Oh, I'm using Eclipse Luna of whatever the latest version is.

像这样反序列化

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();

推荐答案

如果没有定义对象的类,就不能反序列化它.这在 lambda 表达式中没有改变.

You can’t deserialize an object without the class defining it. This hasn’t changed with lambda expressions.

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

Lambda expressions are a bit more complex as their generated runtime class is not the class which defined it but their defining class is the one holding the code of the lambda’s body and, in case of serializable lambdas, a deserialization support method which is called for validating and re- instantiating the lambda instance.

参见SerializedLambda:

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

Implementors of serializable lambdas, such as compilers or language runtime libraries, are expected to ensure that instances deserialize properly. One means to do so is to ensure that the writeReplace method returns an instance of SerializedLambda, rather than allowing default serialization to proceed.

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

SerializedLambda has a readResolve method that looks for a (possibly private) static method called $deserializeLambda$(SerializedLambda) in the capturing class, invokes that with itself as the first argument, and returns the result. Lambda classes implementing $deserializeLambda$ are responsible for validating that the properties of the SerializedLambda are consistent with a lambda actually captured by that class.

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

So even if your instance was not referring to a synthetic method inside the defining class (e.g. in the case of a method reference to a method outside this class), deserialization still requires the $deserializeLambda$ for validating the correctness of the instance, intentionally.

关于序列化 lambda 的良好实践",请记住,lambda 表达式封装了行为,而不是状态.存储行为总是意味着只存储某种类型的引用,并且需要打算恢复它的代码来实现相关的行为.如果您只是通过符号名称或仅存储来引用预期的行为,那也会起作用,例如关联的 enum 值.

Regarding the "good practice" of serializing lambdas, keep in mind that lambda expressions encapsulate behavior, not state. Storing behavior always implies storing just some kind of reference and requiring the code intended to restore it, to have implemented the associated behavior. That would work as well if you just referred to the intended behavior by a symbolic name or just stored, e.g. associated enum values.

这个问题中解释了有关具有可序列化 lambda 的含义的更多信息.

More about the implications of having serializable lambdas is explained in this question.

这篇关于无法反序列化 lambda的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆