JRuby 中的 Java 反射 : Determining class of java. util.regex.Pattern

标签 java reflection jruby jruby-java-interop

在开发在 Java 11 下运行的旧版 JRuby 应用程序 (1.6.8) 时,我在测试用例中发现了一个特殊错误:"require 'java'; put java::util::regex::Pattern.class “ 错误 ArgumentError:参数数量错误(0 代表 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 源代码中注释掉该行。

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

为什么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/ 获取

最佳答案

认为 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”属性是在结尾。 (就像在java中Something.class不是一个属性,而只是一个关键字)

最好的选择是对匹配调用的方法(需要 0 个参数)以及公共(public)方法具有更高的优先级。此外,只有当 getter 确实是 getter 时,它们才应该与属性名称匹配 - 因此它们没有任何参数。

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

关于JRuby 中的 Java 反射 : Determining class of java. util.regex.Pattern,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54066494/

相关文章:

java - JRuby 调用了错误的方法

java - 使用 Java 发送 Outlook session 邀请

java - jboss-web.xml 验证错误

java - Class.getDeclaredConstructor 不检索兼容的参数父类(super class)型构造函数

java - 用java反射实例化私有(private)内部类

java - 在 JRuby 中使用现有的 Java 对象

java - Eclipse 中形式的辅助箭头

java - @ModelAttribute 像 Swagger 一样显示在 body 中

xml - 在运行时更改结构标记 (xml)

jruby on rails 调度选项