草庐IT

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

coder 2024-03-05 原文

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

目标是传递一个匿名类的对象作为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 - 是否可以在没有外部类的情况下序列化匿名类?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  3. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  6. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  7. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  8. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  9. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  10. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

随机推荐