Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: JRuby 1.1.4
-
Fix Version/s: JRuby 1.2
-
Component/s: Java Integration
-
Labels:None
-
Environment:JDK5 on MacOS X
-
Testcase included:yes
Description
I have a class:
package com.some.pkg; public class Foo { boolean bar; Foo() { bar = true; } }
$ jirb irb(main):001:0> require 'dist/some-pkg.jar' => true irb(main):002:0> x = com.some.pkg.Foo.new => #<Java::ComSomePkg::Foo:0x1be20c @java_object=java.lang.Object@2342ed> irb(main):003:0> x.class => Java::ComSomePkg::Foo irb(main):004:0> x.inspect => "#<Java::ComSomePkg::Foo:0x1be20c @java_object=java.lang.Object@2342ed>"
As you can see above, the internal @java_object is of a type Object, instead of com.some.pkg.Foo. This means that even though JRuby returned some object when I called Foo.new, this object is not a valid instance of com.some.pkg.Foo class.
This also results in odd errors when I call methods of the corrupted instance:
irb(main):006:0> x.bar TypeError: invokee not instance of method's class (gotjava.lang.Object wanted com.some.pkg.Foo) from (irb):7:in `binding' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:150:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:259:in `signal_status' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:147:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:146:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:70:in `start' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `catch' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `start' from /usr/local/jruby/current/bin/jirb:19 irb(main):007:0> x.getBar TypeError: invokee not instance of method's class (gotjava.lang.Object wanted com.some.pkg.Foo) from (irb):8:in `binding' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:150:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:259:in `signal_status' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:147:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:146:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:70:in `start' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `catch' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `start' from /usr/local/jruby/current/bin/jirb:19 irb(main):005:0> x.get_bar TypeError: invokee not instance of method's class (gotjava.lang.Object wanted com.some.pkg.Foo) from (irb):6:in `binding' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:150:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:259:in `signal_status' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:147:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:146:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:70:in `start' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `catch' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `start' from /usr/local/jruby/current/bin/jirb:19
Another problem that might or might not be related is that when a class with a non-public constructor with parameters is created which suppresses the implicit parameterless constructor, JRuby tries to instantiate this class using the parameterless constructor:
package com.some.pkg; public class Foo { boolean bar; Foo(boolean requiredParam) { bar = requiredParam; } public boolean getBar() { return bar; } }
$ jirb require 'irb(main):001:0> require 'dist/some-pkg.jar' => true irb(main):002:0> x = com.some.pkg.Foo.new(true) ArgumentError: wrong # of arguments(1 for 0) from (irb):4:in `binding' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:150:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:259:in `signal_status' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:147:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:146:in `eval_input' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:70:in `start' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `catch' from /usr/local/jruby/jruby-1.1.4/lib/ruby/1.8/irb.rb:69:in `start' from /usr/local/jruby/current/bin/jirb:19 irb(main):003:0> x = com.some.pkg.Foo.new => #<Java::ComSomePkg::Foo:0x1be20c @java_object=java.lang.Object@2342ed>
I'm not entirely sure if JRuby can instantiate classes via non-public constructors, if that was not possible, an exception should be raised instead of returning corrupted objects.
Ok, so here's the deal. The example you gave is actually a package-visible constructor, which can't be called unless the subclass is also in the same package. We don't do that because it can often break cases where the original package has been signed, and it's hard to detect that. So I did not modify the behavior that causes constructing through a package-visible constructor to fail. What I did do, however, was make the error message actually reflect the original Java exception's error message, which should generally be enough to indicate that the method is not visible.
Public and protected superclass constructors should do work fine. I added specs for public/protected working and private/package failing. All committed in r9079.