java.lang.Object.equals и java.lang.Object.hashCode имеют проблемы с объектом jruby после сериализации - PullRequest
0 голосов
/ 12 января 2012

У меня проблемы с использованием объектов jruby в java

сторона Java

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

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

Результат первого прохода:

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

Кто-нибудь может это объяснить?

1 Ответ

2 голосов
/ 29 января 2012

Я не знаю всех подробностей о том, почему это происходит, как это происходит, но у меня есть решение / обходной путь для вас.(Я видел похожее поведение при передаче объектов, созданных на стороне ruby, на сторону Java.)

Насколько я могу судить, JRuby должен уже "увидеть" экземпляр класса, которым он являетсяпопытка разархивировать, прежде чем он сможет правильно понять сторону наследования Java.Как будто создание объекта в JRuby имеет недокументированный побочный эффект, который регистрирует необходимую иерархию наследования.Если это не очень хорошо сформулировано, то это потому, что я сам не понимаю этого!

Так что обходной путь - просто создать экземпляр OneClass и TwoClass перед выполнением демаршала.Если я изменю метод 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

Второйpass

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

Согласно этому сообщению об ошибке это исправлено в JRuby 1.7.Стоит отметить, что, хотя в комментариях к отчету говорится, что обходной путь заключается в вызове метода с передачей экземпляра объекта, похоже, что предварительного создания объекта достаточно.

...