我在网上做了一个小调查,并查看了该网站上的相关主题,但答案是矛盾的:有人说不可能,有人说可能,但很危险。
目标是传递一个匿名类的对象作为RMI方法的参数。由于 RMI 要求,此类必须是可序列化的。没问题,很容易使类可序列化。
但我们知道内部类的实例持有对外部类的引用(匿名类是内部类)。因此,当我们序列化内部类的实例时,外部类的实例和字段一起被序列化。这是问题出现的地方:外部类不可序列化,更重要的是 - 我不想序列化它。我想做的只是发送匿名类的实例。
简单示例 - 这是一个 RMI 服务,其方法接受 Runnable:
public interface RPCService {
Object call(SerializableRunnable runnable);
}
下面是我想调用方法的方式
void call() {
myRpcService.call(new SerializableRunnable() {
@Override
public Object run {
System.out.println("It worked!");
}
}
}
如您所见,我想做的是向另一端发送一个“ Action ”——系统 A 描述了应该在系统 B 上运行的代码。这就像用 Java 发送脚本一样。
如果可能的话,我可以很容易地看到一些危险的后果:例如,如果我们从 Runnable 访问一个字段或捕获外部类的最终变量——我们会遇到麻烦,因为调用者实例不存在。另一方面,如果我在我的 Runnable 中使用安全代码(编译器可以检查它),那么我看不到禁止此操作的理由。
因此,如果有人知道,如何在匿名类中正确覆盖 writeObject()
和 readObject()
方法,或者如何引用外部类 transient
或者解释为什么它在 java 中是不可能的,这将非常有帮助。
UPD
另一个需要考虑的重要事项:外部类不存在于将执行该方法的环境(系统 B)中,这就是为什么应该完全排除有关它的信息以避免 NoClassDefFoundError
。
最佳答案
您可以尝试将 Caller.call()
设为 static
方法。
但是,匿名类仍然需要在反序列化序列化实例的上下文中可用。这是不可避免的。
(很难想象匿名类可用但封闭类不可用的情况。)
So, if someone can show, how I can properly override writeObject and readObject methods in my anonymous class ...
如果您将 Caller.call()
设置为静态,那么我认为您会像命名类一样执行此操作。 (我相信您可以自己找到这方面的例子。)
确实,(模数匿名类可用性问题)它有效。在这里,static main
方法替代了 static Classer.call()
方法。程序编译运行,表明在静态方法中声明的匿名类可以序列化和反序列化。
import java.io.*;
public class Bar {
private interface Foo extends Runnable, Serializable {}
public static void main (String[] args)
throws InterruptedException, IOException, ClassNotFoundException {
Runnable foo = new Foo() {
@Override
public void run() {
System.out.println("Lala");
}
};
Thread t = new Thread(foo);
t.start();
t.join();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(foo);
oos.close();
Foo foofoo = (Foo) new ObjectInputStream(
new ByteArrayInputStream(baos.toByteArray())).readObject();
t = new Thread(foofoo);
t.start();
t.join();
}
}
Another important thing to remember about: the
Caller
class is not present in the environment, that executes the method, so I'd like to exclude all information about it during serialization to avoidNoClassDefFoundError
.
没有办法避免这种情况。远程 JVM 中的反序列化提示的原因是类描述符包含对外部类的引用。反序列化端需要解析该引用,即使您设法破坏引用,即使您从未在反序列化对象中显式或隐式使用合成变量。
问题是远程 JVM 的类加载器在加载内部类的类文件时需要知道外部类的类型。验证需要它。它需要反射(reflection)。垃圾收集器需要它。
没有解决方法。
(我不确定这是否也适用于 static
内部类......但我怀疑它适用。)
Attempting to serialize anonymous Runnable instance without outer class refers not only to a serialization problem, but to a possibility of arbitrary code execution in another environment. It would be nice to see a JLS reference, describing this question.
对此没有 JLS 引用。 JLS 中未指定序列化和类加载器。 (类初始化是......但这是一个不同的问题。)
可以通过 RMI 在远程系统上运行任意代码。但是,您需要实现 RMI 动态类加载才能实现这一点。这是一个引用:
请注意,将远程类的动态类加载添加到 RMI 会引入重大的安全问题。而且您必须考虑类加载器泄漏等问题。
关于java - 是否可以在没有外部类的情况下序列化匿名类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26422665/