Forum: JRuby instance_eval in initialize - JRuby sub-class of Java class

6ff4f60ceb95eb94677b152e6f18ca4a?d=identicon&s=25 Ashwin Jayaprakash (Guest)
on 2013-06-04 20:28
(Received via mailing list)
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)
6ff4f60ceb95eb94677b152e6f18ca4a?d=identicon&s=25 Ashwin Jayaprakash (Guest)
on 2013-06-04 20:31
(Received via mailing list)
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);
    }
}
F1d37642fdaa1662ff46e4c65731e9ab?d=identicon&s=25 Charles Nutter (headius)
on 2013-06-07 01:36
(Received via mailing list)
On Tue, Jun 4, 2013 at 1:23 PM, Ashwin Jayaprakash
<ashwin.jayaprakash@gmail.com> 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
6ff4f60ceb95eb94677b152e6f18ca4a?d=identicon&s=25 Ashwin Jayaprakash (Guest)
on 2013-06-07 05:07
(Received via mailing list)
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 Nutter
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.