java.lang.Object.equals 和 java.lang.Object.hashCode 在序列化后处理 jruby 对象时遇到问题

发布于 2024-12-26 13:28:11 字数 2365 浏览 1 评论 0原文

我在使用 jruby 对象到 java

java side

package com.pp;

public interface ZeroI {

    boolean equals(Object o);    
    int hashCode();    
    int hash();
}


package com.pp;

public class Tester {

    public Object[] compare(ZeroI one, ZeroI two) {
        return new Object[] {one.hashCode(), two.hashCode(), one.equals(two), one == two};
    }
}

jruby side

include Java

import com.pp.Tester
import com.pp.ZeroI

module MMM

    module Zero

        def hash= value
            @hash = value
        end

        def hash
            @hash
        end

        def hashCode
            @hash
        end

        def equals other
            false
        end

        def == other
            true
        end

    end

    class OneClass
        include ZeroI
        include Zero
    end

    class TwoClass
        include ZeroI
        include Zero
    end

    def self.create clazz
        begin
            dump = IO.readlines("C:/#{clazz.to_s.rpartition('::')[2]}.txt", '').to_s
            instance = Marshal.load dump
        rescue => err
            puts err.message
            instance = clazz.new
            dump = Marshal.dump instance
            File.open("C:/#{clazz.to_s.rpartition('::')[2]}.txt", 'w') { |f| f.write dump }
        end
        instance
    end

    tester = Tester.new
    one = create OneClass
    two = create TwoClass

    puts one
    puts two

    one.hash = 22
    two.hash = 22

    puts one.hashCode
    puts two.hashCode
    puts one.equals two
    puts one == two

    tester.compare(one, two).each { |value| puts value }
end

First pass result:

No such file or directory - C:/OneClass.txt

No such file or directory - C:/TwoClass.txt
#<MMM::OneClass:0x1971eb3>
#<MMM::TwoClass:0x1408a75>
22    
22    
false    
true    
22    
22    
true
false

true # 没关系,因为 JAVA.equals 与 JRUBY.==

false # 没关系,因为 org.pp.ZeroI 无法声明 == 方法和 JAVA .== 使用

第二遍结果(带有反序列化对象)

#<MMM::OneClass:0xd510e8>
#<MMM::TwoClass:0x490342>
22    
22    
false    
true    
13046738 # but what is it?    
31877484 # but what is it?    
false # but what is it?    
false

有人能解释一下吗?

I have some trouble using jruby objects into java

java side

package com.pp;

public interface ZeroI {

    boolean equals(Object o);    
    int hashCode();    
    int hash();
}


package com.pp;

public class Tester {

    public Object[] compare(ZeroI one, ZeroI two) {
        return new Object[] {one.hashCode(), two.hashCode(), one.equals(two), one == two};
    }
}

jruby side

include Java

import com.pp.Tester
import com.pp.ZeroI

module MMM

    module Zero

        def hash= value
            @hash = value
        end

        def hash
            @hash
        end

        def hashCode
            @hash
        end

        def equals other
            false
        end

        def == other
            true
        end

    end

    class OneClass
        include ZeroI
        include Zero
    end

    class TwoClass
        include ZeroI
        include Zero
    end

    def self.create clazz
        begin
            dump = IO.readlines("C:/#{clazz.to_s.rpartition('::')[2]}.txt", '').to_s
            instance = Marshal.load dump
        rescue => err
            puts err.message
            instance = clazz.new
            dump = Marshal.dump instance
            File.open("C:/#{clazz.to_s.rpartition('::')[2]}.txt", 'w') { |f| f.write dump }
        end
        instance
    end

    tester = Tester.new
    one = create OneClass
    two = create TwoClass

    puts one
    puts two

    one.hash = 22
    two.hash = 22

    puts one.hashCode
    puts two.hashCode
    puts one.equals two
    puts one == two

    tester.compare(one, two).each { |value| puts value }
end

First pass result:

No such file or directory - C:/OneClass.txt

No such file or directory - C:/TwoClass.txt
#<MMM::OneClass:0x1971eb3>
#<MMM::TwoClass:0x1408a75>
22    
22    
false    
true    
22    
22    
true
false

true # it's OK because JAVA.equals works with JRUBY.==

false # it's OK because org.pp.ZeroI can't declare == method and JAVA.== is used

Second pass result (with deserialized objects)

#<MMM::OneClass:0xd510e8>
#<MMM::TwoClass:0x490342>
22    
22    
false    
true    
13046738 # but what is it?    
31877484 # but what is it?    
false # but what is it?    
false

Can anybody explain it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

玩套路吗 2025-01-02 13:28:11

我不知道为什么会发生这种情况的所有细节,但我为您提供了一个解决方案/解决方法。 (当将 ruby​​ 端创建的对象传递到 Java 端时,我看到了类似的行为。)

据我所知,JRuby 需要已经“看到”它正在尝试解组的类的实例,然后才能进行解组。正确处理 Java 继承方面的问题。就好像在 JRuby 中创建一个对象有一个未记录的副作用,它会注册所需的继承层次结构。如果说得不好,那是因为我自己也不明白!

因此,解决方法是在进行解组之前简单地创建 OneClassTwoClass 的实例。如果我将 self.create 方法更改为以下内容:

def self.create clazz
    begin
        clazz.new # <<< just create an instance and throw it away!
        dump = IO.readlines("C:/#{clazz.to_s.rpartition('::')[2]}.txt", '').to_s
        instance = Marshal.load dump
    rescue => err
        puts err.message
        instance = clazz.new
        dump = Marshal.dump instance
        File.open("C:/#{clazz.to_s.rpartition('::')[2]}.txt", 'w') { |f| f.write dump }
    end
    instance
end

那么两遍的输出如下:

第一遍

No such file or directory - C:/OneClass.txt
No such file or directory - C:/TwoClass.txt
#<MMM::OneClass:0x4de6f0ef>
#<MMM::TwoClass:0x4526ba64>
22
22
false
true
22
22
true
false

第二遍

#<MMM::OneClass:0x4858cca9>
#<MMM::TwoClass:0x3de4905a>
22
22
false
true
22
22
true
false

根据 此错误报告 计划在 JRuby 1.7 中修复。值得注意的是,虽然报告中的评论说解决方法是调用一个方法,传入一个对象实例,但似乎预先创建对象就足够了。

I don't know all the details about why this happens like it happens but I have a solution/workaround for you. (I've seen similar behaviour when passing objects that are created on the ruby side to the Java side.)

As far as I can tell JRuby needs to have already "seen" an instance of the class it is trying to unmarshal before it can get the Java-inheritance side of things right. It's almost as if creating an object within JRuby has an undocumented side-effect that registers the required inheritance hierarchy. If that isn't well worded it's because I don't understand it myself!

So the workaround is to simply create an instance of OneClass and TwoClass before doing the unmarshal. If I change the self.create method to the following:

def self.create clazz
    begin
        clazz.new # <<< just create an instance and throw it away!
        dump = IO.readlines("C:/#{clazz.to_s.rpartition('::')[2]}.txt", '').to_s
        instance = Marshal.load dump
    rescue => err
        puts err.message
        instance = clazz.new
        dump = Marshal.dump instance
        File.open("C:/#{clazz.to_s.rpartition('::')[2]}.txt", 'w') { |f| f.write dump }
    end
    instance
end

Then the output of the two passes are as follows:

First pass

No such file or directory - C:/OneClass.txt
No such file or directory - C:/TwoClass.txt
#<MMM::OneClass:0x4de6f0ef>
#<MMM::TwoClass:0x4526ba64>
22
22
false
true
22
22
true
false

Second pass

#<MMM::OneClass:0x4858cca9>
#<MMM::TwoClass:0x3de4905a>
22
22
false
true
22
22
true
false

According to this bug report this is scheduled to be fixed in JRuby 1.7. It's worth noting that while the comments in the report say that the workaround is to call a method, passing an object instance in, it seems to be that the prior creation of the object is enough.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文