Java 思考:在 JRuby 中确定 java.util.regex.Pattern 的 class
Java Reflection: Determining class of java.util.regex.Pattern in JRuby
在 Java 11 下处理遗留 JRuby 应用程序 (1.6.8) 运行,我在测试用例中发现了一个特殊错误:"require 'java'; puts java::util::regex::Pattern.class"
错误 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 源代码中注释掉该行。
我对造成这种情况的原因或如何正确解决它感到困惑。 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
==> int
jshell> String.class
==> class java.lang.String
jshell> Pattern.class
==> class java.util.regex.Pattern
jshell> Pattern.class.getClass()
==> class java.lang.Class
jshell> String.class.getClass()
==> 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 正在尝试读取模式 class:
的成员之一
private static int getClass(int c) {
return sun.text.Normalizer.getCombiningClass(c);
}
因为它看起来有点像 getter 但有那个额外的参数。
您可以通过创建自己的 class 来确认:
class MyClass {
private static int getClass(int c) {
return 4;
}
}
然后尝试在 JRuby 中从中获取 class。
它适用于 java 8,因为这个方法是非静态的,就像 Holger 所说的那样,jruby 似乎更喜欢使用现有的静态方法,即使它们与签名不匹配,并检查特殊的“.class" 属性 最后完成。 (如 java Something.class
不是 属性,而只是一个关键字)
最好的选择是为匹配调用的方法(需要 0 个参数)以及 public 方法设置更高的优先级。另外 getters 应该只匹配 属性 的名字,只有当它们真的是 getters - 所以他们没有任何参数。
我无法下载此版本的 jruby,因此无法测试:https://www.jruby.org/files/downloads/1.6.8/index.html
在 Java 11 下处理遗留 JRuby 应用程序 (1.6.8) 运行,我在测试用例中发现了一个特殊错误:"require 'java'; puts java::util::regex::Pattern.class"
错误 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 源代码中注释掉该行。
我对造成这种情况的原因或如何正确解决它感到困惑。 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
==> int
jshell> String.class
==> class java.lang.String
jshell> Pattern.class
==> class java.util.regex.Pattern
jshell> Pattern.class.getClass()
==> class java.lang.Class
jshell> String.class.getClass()
==> 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 正在尝试读取模式 class:
的成员之一private static int getClass(int c) {
return sun.text.Normalizer.getCombiningClass(c);
}
因为它看起来有点像 getter 但有那个额外的参数。
您可以通过创建自己的 class 来确认:
class MyClass {
private static int getClass(int c) {
return 4;
}
}
然后尝试在 JRuby 中从中获取 class。
它适用于 java 8,因为这个方法是非静态的,就像 Holger 所说的那样,jruby 似乎更喜欢使用现有的静态方法,即使它们与签名不匹配,并检查特殊的“.class" 属性 最后完成。 (如 java Something.class
不是 属性,而只是一个关键字)
最好的选择是为匹配调用的方法(需要 0 个参数)以及 public 方法设置更高的优先级。另外 getters 应该只匹配 属性 的名字,只有当它们真的是 getters - 所以他们没有任何参数。
我无法下载此版本的 jruby,因此无法测试:https://www.jruby.org/files/downloads/1.6.8/index.html