如何安全地序列化lambda? [英] How to safely serialize a lambda?

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

问题描述

尽管可以在Java 8中序列化lambda ,但它是对内部类进行序列化.给出的原因是,lambda可能无法在另一个JRE上正确反序列化.但是,这是否意味着存在 一种安全地序列化lambda的方法?

Although it is possible to serialize a lambda in Java 8, it is strongly discouraged; even serializing inner classes is discouraged. The reason given is that lambdas may not deserialize properly on another JRE. However, doesn't this mean that there is a way to safely serialize a lambda?

例如,假设我将一个类定义为类似这样的内容:

For example, say I define a class to be something like this:

public class MyClass {
    private String value;
    private Predicate<String> validateValue;

    public MyClass(String value, Predicate<String> validate) {
        this.value = value;
        this.validateValue = validate;
    }

    public void setValue(String value) {
        if (!validateValue(value)) throw new IllegalArgumentException();
        this.value = value;
    }

    public void setValidation(Predicate<String> validate) {
        this.validateValue = validate;
    }
}

如果我这样声明了该类的实例,则不应序列化它:

If I declared an instance of the class like this, I should not serialize it:

MyClass obj = new MyClass("some value", (s) -> !s.isEmpty());

但是如果我像这样创建一个类的实例怎么办?

But what if I made an instance of the class like this:

// Could even be a static nested class
public class IsNonEmpty implements Predicate<String>, Serializable {
    @Override
    public boolean test(String s) {
        return !s.isEmpty();
    }
}

MyClass isThisSafeToSerialize = new MyClass("some string", new IsNonEmpty());

现在可以安全地序列化吗?我的直觉说是的,应该安全,因为没有理由将java.util.function中的接口与任何其他随机接口区别对待.但是我还是很警惕.

Would this now be safe to serialize? My instinct says that yes, it should be safe, since there's no reason that interfaces in java.util.function should be treated any differently from any other random interface. But I'm still wary.

推荐答案

这取决于您想要哪种安全性.并非无法在不同的JRE之间共享序列化的lambda.它们具有定义明确的持久性表示形式, SerializedLambda .在研究它的工作原理时,您会发现它依赖于定义类的存在,该类将具有一种特殊的方法来重构lambda.

It depends on which kind of safety you want. It’s not the case that serialized lambdas cannot be shared between different JREs. They have a well defined persistent representation, the SerializedLambda. When you study, how it works, you’ll find that it relies on the presence of the defining class, which will have a special method that reconstructs the lambda.

使其不可靠的原因是依赖于编译器特定的工件,例如合成目标方法具有一些生成的名称,因此简单的更改(例如插入另一个lambda表达式或使用其他编译器重新编译该类)可能会破坏与现有序列化lambda表达式的兼容性.

What makes it unreliable is the dependency to compiler specific artifacts, e.g. the synthetic target method, which has some generated name, so simple changes like the insertion of another lambda expression or recompiling the class with a different compiler can break the compatibility to existing serialized lambda expression.

但是,使用手动编写的类不能幸免.如果没有显式声明的serialVersionUID,则默认算法将通过散列类工件(包括private和合成对象)并添加类似的编译器依赖关系来计算ID.因此,如果要使用可靠的持久性形式,要做的最小工作就是声明一个显式的serialVersionUID.

However, using manually written classes isn’t immune to this. Without an explicitly declared serialVersionUID, the default algorithm will calculate an id by hashing class artifacts, including private and synthetic ones, adding a similar compiler dependency. So the minimum to do, if you want reliable persistent forms, is to declare an explicit serialVersionUID.

或者您转向最可靠的形式:

Or you turn to the most robust form possible:

public enum IsNonEmpty implements Predicate<String> {
    INSTANCE;

    @Override
    public boolean test(String s) {
        return !s.isEmpty();
    }
}

序列化此常量除了其类名(当然,它是一个enum)和对该常量名的引用之外,不存储实际实现的任何属性.反序列化后,将使用该名称的实际唯一实例.

Serializing this constant does not store any properties of the actual implementation, besides its class name (and the fact that it is an enum, of course) and a reference to the name of the constant. Upon deserialization, the actual unique instance of that name will be used.

请注意,可序列化的lambda表达式可能会造成安全问题,因为它们为获取允许调用目标方法的对象提供了另一种方法.但是,这适用于所有可序列化的类,因为问题中显示的所有变体和此答案都允许故意反序列化对象,从而调用封装的操作.但是,使用显式可序列化的类,作者通常会更清楚这一事实.

Note that serializable lambda expressions may create security issues because they open an alternative way of getting hands on an object that allows to invoke the target methods. However, this applies to all serializable classes, as all variant shown in your question and this answer allow to deliberately deserialize an object allowing to invoke the encapsulated operation. But with explicit serializable classes, the author is usually more aware of this fact.

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

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