[JRuby] simulating a java exception in a spec

JRuby 1.6.2
rspec-core (2.6.4)
rspec-expectations (2.6.0)
rspec-mocks (2.6.0)
rspec-rails (2.6.1)

I’m sure this has more to do with the way JRuby wraps Java exceptions
but I figured I’d post here in case anyone here has any insight or
pointers. In the context of writing a spec for a model like thing that
wraps legacy Java code, I found myself attempting to stub a method on a
Java Exception rescued in the implementation.

eg.

describe ‘#valid?’ do

it ‘adds validation exceptions raised by service to #errors’ do
ve = ValidationException #a java exception
ve.stub(:localized_message).and_return(‘a bunch of errors’)

  service.stub(:validateTaskForSave).and_raise(ve)

  subject.valid?

  subject.errors.should == ['a bunch of errors']

end

the above example fails because the :localize_message stub is ignored
and instead the real implementation receives the message. I know this
typically screams typo but not in this case. Here is a more boiled down
version:

specify ‘rescued exception message should be “bar” because I stubbed it’
do
begin
e = Java::java.lang.NullPointerException.new(‘foo’)
e.stub(:message).and_return(‘bar’)
raise e
rescue Java::java.lang.NullPointerException => e
e.message.should == ‘bar’
end
end

Failure/Error: e.message.should == ‘bar’
expected: “bar”
got: “foo” (using ==)

That seemed odd to me but maybe moot anyway since in reality I would be
need to rescue a NativeException masquerading as my target exception.

e.g. This code

def valid?
begin
service.validateTaskForSave(task)
rescue ValidationException => e
puts “rescued exception: #{e.class.name}”

prints “rescued exception: NativeException” when hit through the
console.

So how would one simulate a NativeException if needed (i.e. you want to
stub methods on it)?

-lenny

it ‘adds validation exceptions raised by service to #errors’ do
ve = ValidationException #a java exception
ve.stub(:localized_message).and_return(‘a bunch of errors’)

Just clarifying, but did you mean
ve = ValidationException.new

I tried replicating your spec but with java.lang.RuntimeException
instead of ValidationException and I got
exception class/object expected

because raise expects an instance of the exception, not the exception
class. Am I missing something?

Best,
Sidu.
http://c42.in

Please ignore my previous question - I just realised you’re doing
Java::java.lang.NullPointerException.new in your second example. I’m
seeing the same behaviour and can’t think of any way around it off the
top of my head.

You could try redefining Java::JavaLang::NullPointerException to be a
Ruby RuntimeError within the scope of your spec but I’m not sure how
this will work (if at all) when Java::JavaLang::NullPointerException
is raised from native code.

Best,
Sidu.
http://c42.in

 subject.valid?

 subject.errors.should == ['a bunch of errors']

end

I tried replicating your spec but with java.lang.RuntimeException
instead of ValidationException and I got
exception class/object expected

because raise expects an instance of the exception, not the exception
class. Am I missing something?

Best,
Sidu.
http://c42.in
http://blog.sidu.in

You have to raise an exception instance, not the class of the exception
as is typical with Ruby exceptions. Check out the “boiled down” example
below to reproduce.

 end

def valid?
begin
service.validateTaskForSave(task)
rescue ValidationException => e
puts “rescued exception: #{e.class.name}”

prints “rescued exception: NativeException” when hit through the console.

The more I think about this, the more I wish it was different(more
explicit) in JRuby. IMO, the above is very unintuitive (i.e. if I rescue
a specific exception class then I would expect the exception instance to
be an instance of that class). Any attempt to reference a custom method
on a rescued java exception results in “undefined method”.

rescue MyJavaException => e

e.some_method “undefined method”

e.cause.some_method # need to unwrap
end

AFAICT, the JRuby wiki makes no mention of this behavior (
CallingJavaFromJRuby · jruby/jruby Wiki · GitHub ). Of course
that’s more suited for the JRuby mailing list, but if it is just a
matter of filling in the docs then there should still be an easy way to
simulate such an exception with #and_raise such that custom methods on
the exception can be stubbed. No??

-lenny