有没有办法在JRuby中为Java对象获得良好的`#inspect`输出?

时间:2018-04-27 03:02:01

标签: java ruby jruby

假设我们有一个相当简单的Java bean:

public class Test {
    private String thing;

    public void setThing(String thing) {
        this.thing = thing;
    }

    public String getThing() {
        return thing;
    }

    @Override
    public String toString() {
        return "Test{thing=" + thing + "}>";
    }
}

然后我们使用Ruby中的这个bean:

java_import 'Test'

t = Test.new
t.thing = 'blah'
p t

输出结果为:

#<Java::Default::Test:0x5fdba6f9>

但我认为我更喜欢的是

#<Test{thing=blah}>

或者甚至可能只是

Test{thing=blah}

我知道我可以在所有Java类中添加一个名为inspect()的方法,但似乎每个实现只会调用toString(),因为{{1}的意图在Java中,通常与Ruby中的toString()的意图相同(即,仅供开发人员看到的字符串)。

所以我想知道的是,在任何Java对象上调用#inspect时,有没有一种简单的方法可以告诉JRuby使用toString()

1 个答案:

答案 0 :(得分:1)

好吧,在任何其他ruby实现中,我们只会修补Object#inspect方法,但这对Java类来说是不可能的,因为它们的实现是本机的。但是你可以做这样的事情来让你的生活更轻松:

module JavaInspect
  alias_method :inspect_without_to_string, :inspect
  def inspect_with_string
    self.respond_to?(:toString) ? self.toString : self.inspect_without_to_string
  end
  alias_method :inspect, :inspect_with_string
end

java_import 'Test'
Test.include(JavaInspect)
t = Test.new
t.inspect => "Test{thing=null}>"
t.inspect_without_to_string => "#<Java::Default::Test:0x4efac082>"

您只需将模块包含在所需的类中即可。如果你真的喜欢它,你甚至可以在java_import周围创建一个包装器。

请注意,我不建议修补猴子Object,或者为生产代码创建这样的包装器,但是在开发中这可能非常有用,并且在某些情况下经过仔细考虑后可能会甚至可以用于生产。