2

在 Java 11 下运行的旧版 JRuby 应用程序 (1.6.8) 上工作时,我在测试用例中发现了一个特殊错误:"require 'java'; puts java::util::regex::Pattern.class"errors ArgumentError: wrong number of arguments (0 for 1)。对于其他内置 JRE 类,这似乎工作正常(见下文)。

这会导致 JRuby 本身有时会失败,在https://github.com/jruby/jruby/blob/1.6.8/lib/ruby/site_ruby/shared/builtin/javasupport/core_ext/object.rb#L10中的这一行:

if self.class.superclass.instance_method(:method_added) != method(:java_package_method_added)

为了让应用程序正常工作,我必须在 JRuby 源代码中注释掉该行。

我对造成这种情况的原因或如何适当地解决它感到困惑。谷歌展示了几个人们在尝试加载特定应用程序时遇到该错误的实例,但没有人弄清楚原因(所有解决方案都说“尝试不同版本的应用程序)。

为什么 JRuby 不能执行.class?它期待什么论据

完整的跟踪如下:

$ java -version
java version "11.0.1" 2018-10-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)

$ ./jruby -v
jruby 1.6.8 (ruby-1.8.7-p357) (2012-09-18 1772b40) (Java HotSpot(TM) 64-Bit Server VM 11.0.1) [linux-amd64-java]

$ ./jruby -e "require 'java'; puts java::util::regex::Matcher.class"
WARNING: An illegal reflective access operation has occurred
...
Class

$ ./jruby -e "require 'java'; puts java::lang::String.class"
WARNING: An illegal reflective access operation has occurred
...
Class

$ ./jruby -e "require 'java'; puts java::util::regex::Pattern.class"
WARNING: An illegal reflective access operation has occurred
....
ArgumentError: wrong number of arguments (0 for 1)
  (root) at -e:1

Java 行为

Java本身似乎没有问题:

jshell> int.class
$6 ==> int

jshell> String.class
$7 ==> class java.lang.String

jshell> Pattern.class
$8 ==> class java.util.regex.Pattern

jshell> Pattern.class.getClass()
$12 ==> class java.lang.Class

jshell> String.class.getClass()
$13 ==> class java.lang.Class

部分解决方案?

我可以通过注释掉if上面引用的语句来修复 JRuby 中的这个错误。但是,在这个遗留应用程序中,JRuby 位于已编译的 jar 中,因此我无法编辑其源代码。有没有办法在不更改二进制 jar 的情况下向 JRuby 添加猴子补丁来修复失败的if语句?

获取 JRuby

JRuby 1.6.8 可在http://central.maven.org/maven2/org/jruby/jruby-dist/1.6.8/ 获得

4

1 回答 1

4

认为jruby 正在尝试读取 Pattern 类的成员之一:

private static int getClass(int c) {
    return sun.text.Normalizer.getCombiningClass(c);
}

因为它看起来有点像 getter 但有额外的参数。

您可以通过创建自己的类来确认这一点:

class MyClass {
    private static int getClass(int c) {
        return 4;
    }
}

然后尝试在 JRuby 中从中获取类。

它适用于 java 8,因为这种方法是非静态的,并且就像 Holger 所说的,jruby 似乎更喜欢使用现有的静态方法,即使它们与签名不匹配,并在最后检查特殊的“.class”属性。(因为在javaSomething.class中不是一个属性,而只是一个关键字)

最好的选择是对匹配调用的方法(0个需要的参数)具有更高的优先级,也许对于公共方法。此外,只有当它们确实是 getter 时,getter 才可能仅通过属性名称匹配 - 所以它们没有任何参数。

下载此版本的 jruby 对我不起作用,所以我无法对此进行测试:https ://www.jruby.org/files/downloads/1.6.8/index.html

于 2019-01-09T09:16:44.543 回答