lambda用于接口实现时,“无效的lambda反序列化”

Mic*_*hal 1 lambda wicket java-8

我有一个带有lambda表达式的检票口项目。在用户单击后退按钮的一页上,我的应用程序崩溃:

java.lang.IllegalArgumentException: Invalid lambda deserialization
at x.y.z.MyPage$3.$deserializeLambda$(MyPage.java:1)
Run Code Online (Sandbox Code Playgroud)

在页面类(我返回的地方)中,我使用lambda表达式实现此接口:

public interface Localizator extends Serializable {
    String getLocalizedString(String key);
}
Run Code Online (Sandbox Code Playgroud)

和lambda:

protected void someMethod() {
    localize((String key) -> getString(key));
}
Run Code Online (Sandbox Code Playgroud)

当我将lambda更改为匿名类时,一切正常。在这种情况下应如何使用lambda?

信封:Java 1.8.0_25,Netbeans 8.0.2,Wicket 6.17.0。

编辑:这是带有lambda的真实(但简化)方法:

@Override
protected DataLoader createDataLoader() {

    return new DataLoader(){

        @Override
        public List loadData() {
            ...
        }

        @Override
        public List convertToTableRows(List data) {
            return Converter.asRowList(
                data, 
                (Record record) -> {...}, // this lambda is OK
                (String key) -> getString(key)); // this lambda is crashing
        }

        @Override
        public List filterTableRow() {
            ...
        }

    };
}
Run Code Online (Sandbox Code Playgroud)

转换器类别:

public class Converter implements Serializable { 
    public static ArrayList asRowList(List data, OtherLoader loader, Localizator localizator){...}
Run Code Online (Sandbox Code Playgroud)

DataLoader还扩展了Serializable。

Hol*_*ger 6

为了获得Serialization支持,进行interface扩展Serializable就足够了。然后,无需执行其他强制转换。您的代码可以序列化lambda表达式实例这一事实表明了这一点。反序列化时失败,这表明类不兼容,因此,如果插入强制转换,很有可能是副作用,因为插入包含lambda表达式的类的强制强制重新编译。


如果要继续使用序列化的lambda,则应了解其工作原理,如以下文档中所述SerializedLambda

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

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

因此,当$deserializeLambda$拒绝异常时拒绝反序列化时,则意味着序列化lambda的属性与在类内部定义的已知可序列化lambda的属性不匹配。这些属性可能非常脆弱。

它们包括功能接口,捕获的参数和目标方法。对于lambda表达式(而不是方法引用),目标方法是定义类内部的合成方法,具有编译器选择的未指定名称,甚至可能依赖同一类中的其他 lambda表达式,而插入另一个表达式可能由于编号方案而导致名称更改。

与普通类不同,在普通类中插入a serialVersionUID可能会告诉序列化框架它不应该在意明显的不一致,而您不能告诉lambda表达式显示出更高的鲁棒性。换句话说,一旦序列化了应保留的lambda实例,就不得更改其定义类。另请参阅此答案