Instance_eval in initialize - JRuby sub-class of Java class

Hi, I was trying out ways to create a micro-DSL using JRuby.

*A) *I wanted to do instance_eval on a Java class. On my first attempt
I
got this warning message: “warning: singleton on non-persistent Java
type
Java::JrDemo::Car (http://wiki.jruby.org/Persistence)

require ‘java’

def configure(&block)
car = Java::jr.demo.Car.new
car.instance_eval &block
car
end

@car = configure do |car|
car.model = ‘S2000’
car.make = ‘Honda’
car.year = 2002
car.price = 19000
end

return @car

Car is a simple Java Bean:
public class Car {
String model;
String make;
int year;
double price;

public Car() {
}

public String getModel() {
    return model;
}

public void setModel(String model) {
    this.model = model;
}

… … more getters and setters
}

*B) After reading the instructions on that Persistence page, I tried
sub-classing the Java class inside JRuby. I also wanted to do the *
instance_eval
inside the initialize method. When I ran the code, it
barfed with this exception - “Java wrapper with no contents:
#Class:0x5584d9c6

require ‘java’

class JCar < Java::jr.demo.Car
def initialize(&block)
instance_eval &block
end
end

@car = JCar.new do |car|
car.model = ‘S2000’
car.make = ‘Honda’
car.year = 2002
car.price = 19000
end

return @car

*C) *To make sure that I wasn’t doing something stupid, I did the
instance_eval in a non-initialize method and it worked:

require ‘java’

class JCar2 < Java::jr.demo.Car
def configure(&block)
instance_eval &block
end
end

@car2 = JCar2.new

@car2.configure do |car|
car.model = ‘S2000’
car.make = ‘Honda’
car.year = 2002
car.price = 19000
end

return @car2

*D) *Just to be sure if it was a JRuby peculiarity or a Ruby thing, I
tried
a pure Ruby class and everything worked!

class RCar
attr_accessor :model, :make, :year, :price

def initialize(&block)
    instance_eval &block
end

def to_s
    "{#{self.class.name}: #{@model}, #{@make}, #{@year}, #{@price}}"
end

end

@rcar = RCar.new do |car|
car.model = ‘S2000’
car.make = ‘Honda’
car.year = 2002
car.price = 19000
end

return @rcar

What do you guys think? Am I doing something wrong or is the JRuby doc
missing this information?

Thanks,
Ashwin Jayaprakash (http://ashwinjayaprakash.com)

Oh, here’s the driver class:

public class CarJRubyTest {
public static void main(String[] args) {
InputStream is =
CarJRubyTest.class.getResourceAsStream("/car_test_1.jruby");

    ScriptingContainer sc = new ScriptingContainer();
    Car car = (Car) sc.runScriptlet(is, "CarJRubyTest1");

    System.out.println("Script 1 returned:\n" + car);

    //--------------

    System.out.println();

    is = 

CarJRubyTest.class.getResourceAsStream("/car_test_2.jruby");

    sc = new ScriptingContainer();
    Object o = sc.runScriptlet(is, "CarJRubyTest2");

    System.out.println("Script 2 returned:\n" + o);

    //--------------

    System.out.println();

    try {
        is =

CarJRubyTest.class.getResourceAsStream("/car_test_3.jruby");

        sc = new ScriptingContainer();
        sc.runScriptlet(is, "CarJRubyTest3");
    }
    catch (Exception e) {
        System.out.println("Script 3 throws an exception");
        e.printStackTrace(System.out);
    }

    //--------------

    System.out.println();

    is = 

CarJRubyTest.class.getResourceAsStream("/car_test_4.jruby");

    sc = new ScriptingContainer();
    o = sc.runScriptlet(is, "CarJRubyTest4");

    System.out.println("Script 4 returned:\n" + o);

    //--------------

    System.out.println();

    is = CarJRubyTest.class.getResourceAsStream("/car_test_5.rb");

    sc = new ScriptingContainer();
    o = sc.runScriptlet(is, "CarRubyTest5");

    System.out.println("Script 5 returned:\n" + o);
}

}

On Tue, Jun 4, 2013 at 1:23 PM, Ashwin Jayaprakash
[email protected] wrote:

Hi, I was trying out ways to create a micro-DSL using JRuby.

A) I wanted to do instance_eval on a Java class. On my first attempt I got
this warning message: “warning: singleton on non-persistent Java type
Java::JrDemo::Car (http://wiki.jruby.org/Persistence)”

instance_eval causes an object to create a singleton class, which
needs to be kept attached to the object from then on. Because we can’t
attach our own objects to arbitrary Java objects, singletonizing Java
objects is deprecated and will probably go away in the future. That’s
why you’re getting this warning for this case.

The warning it self basically means that the Java object in question
will not necessarily have the same Ruby object wrapper every time you
see it, so singleton classes, instance variables, and so on may not
always accompany it. You can set the class to be “persistent” by
calling:

Java::jr.demo.Car.persistent = true

It will cost more to work with the object (since we have to maintain
the same wrapper everywhere) but the wrapper will always be the same,
singletons and instance variables will accompany it, and you won’t get
the warning anymore.

B) After reading the instructions on that Persistence page, I tried
sub-classing the Java class inside JRuby. I also wanted to do the
instance_eval inside the initialize method. When I ran the code, it barfed
with this exception - “Java wrapper with no contents: #Class:0x5584d9c6

When extending a Java class, you need to call super to create the Java
half of the object (initialize handles the Ruby half). We have tried
to add better error messages for this, but I think in this case our
normal error message isn’t reached because you try to instance_eval
before the Java object is created.

C) To make sure that I wasn’t doing something stupid, I did the
instance_eval in a non-initialize method and it worked:

In this case, the Java object is created fine, and since we’re already
tying the Java object and a Ruby wrapper together permanently (via the
extension logic), persistent behaviors like singletons and instance
variables work without warning.

D) Just to be sure if it was a JRuby peculiarity or a Ruby thing, I tried a
pure Ruby class and everything worked!

Ruby objects are just Ruby objects, and we can attach a singleton
class to them at any time…so instance_eval works.

What do you guys think? Am I doing something wrong or is the JRuby doc
missing this information?

It certainly could be a documentation gap. Obviously the page on
persistence didn’t tell you what you needed to know, eh?

  • Charlie

Thanks. I understood the content of the Persistence page. I did not
realize
that I had to call super(). Otherwise it worked as expected.

On Thu, Jun 6, 2013 at 4:33 PM, Charles Oliver N.