java - 是否可以在没有外部类的情况下序列化匿名类?

标签 java serialization rmi anonymous-class

我在网上做了一个小调查,并查看了该网站上的相关主题,但答案是矛盾的:有人说不可能,有人说可能,但很危险。

目标是传递一个匿名类的对象作为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 avoid NoClassDefFoundError.

没有办法避免这种情况。远程 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/

相关文章:

java - 在这种情况下,将创建 UserHandler 类的多少个实例?

java - RMI 安全管理器

amazon-ec2 - 对 Amazon EC2 上的 Weblogic 10gR3 RMI 服务器的负载均衡请求

java - 无法执行 jar 文件 : "no main manifest attribute"

c# - 如何在 Xml 中序列化派生类?

c# - 如何反序列化未知类型,不是普通情况

Java 从另一个类的数组列表中调用详细信息

java - 禁用手机横向但允许平板电脑

Java 耦合 - 我应该跨不同模块依赖服务层还是存储库层?

java - 如何跟踪我的内部框架?