Implementing Java Interface on a per Instance Basis?

Hi,

Ideally I would like to have a Ruby script which creates an instance
which when returned from the script implements a particular interface.
Example

final ScriptingContainer sc = new

ScriptingContainer(LocalContextScope.SINGLETON,

LocalVariableBehavior.TRANSIENT);
final Object r = sc.runScriptlet(“m=Object.new;class <<m;p
self;java_implements java.lang.Runnable;java_signature ‘void
run()’\ndef run() puts ‘done’ end end;m”);
sc.callMethod(r, “run”); // works
((Runnable) r).run(); // fails at the cast

I searched around but only found

http://www.ruby-forum.com/topic/214760#932016
http://tommy.chheng.com/index.php/2010/06/call-a-jruby-method-from-java/

But these only explain how to make a class implement a Java interface.

Is it possible at all to make a singleton class implement an interface
and make that accessible directly from Java? The only way I found so
far is by using a Proxy

final InvocationHandler ih = new InvocationHandler() {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {
return args == null ? sc.callMethod(r, method.getName()) :
sc.callMethod(r,

      method.getName(),

      args);
  }
};

final Runnable r2 = (Runnable)

Proxy.newProxyInstance(r.getClass().getClassLoader(),
new
Class<?>[] { Runnable.class },
ih);
r2.run();

But then I don’t need the implements stuff in Ruby code. Is there any
other way?

Btw, I found this but am unsure in how far this is related:

http://jruby.org/apidocs/org/jruby/javasupport/proxy/JavaProxyClass.html#newProxyInstance(org.jruby.Ruby,%20java.lang.Class,%20java.lang.Class[],%20java.lang.Class[],%20java.lang.Object[],%20org.jruby.javasupport.proxy.JavaProxyInvocationHandler)

Kind regards

robert


remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Hello,

On Mon, Mar 14, 2011 at 11:17 AM, Robert K.
[email protected] wrote:

final Object r = sc.runScriptlet(“m=Object.new;class <<m;p
self;java_implements java.lang.Runnable;java_signature ‘void
run()’\ndef run() puts ‘done’ end end;m”);
sc.callMethod(r, “run”); // works
((Runnable) r).run(); // fails at the cast

Do you really want Ruby’s singleton class that implements Java
interface? That would be tricky. For Ruby, “java.lang.Runnable” is a
mixed-in module, so the kind_of? methods of the receiver returns true.
But, I’m not sure how casting to the mixed-in module of a singleton
class works in a simple way.

But, if you want just an instance that implements Java interface, below
works:

String script =
“require ‘java’\n” +
“class Foo\n” +
" include java.lang.Runnable\n" +
" def run\n" +
" puts "self: #{self}"\n" +
" end\n" +
“end\n” +
“Foo.new”;
ScriptingContainer sc = new ScriptingContainer();
Object receiver = sc.runScriptlet(script);
System.out.println(receiver instanceof Runnable);
new Thread((Runnable) receiver).start();

This snippet prints:

true
self: #Foo:0x69e94001

-Yoko

On Mon, Mar 14, 2011 at 9:56 PM, Yoko H. [email protected] wrote:

Hello,

Hi,

thanks for replying - I hope you and your family are safe.

LocalVariableBehavior.TRANSIENT);
final Object r = sc.runScriptlet(“m=Object.new;class <<m;p
self;java_implements java.lang.Runnable;java_signature ‘void
run()’\ndef run() puts ‘done’ end end;m”);
sc.callMethod(r, “run”); // works
((Runnable) r).run(); // fails at the cast

Do you really want Ruby’s singleton class that implements Java
interface?

Yes, that’s exactly what I want. Reason is that I need to create a
new implementation from time to time but want GC take care of those
implementations which are no longer referenced somewhere.

That would be tricky. For Ruby, “java.lang.Runnable” is a
mixed-in module, so the kind_of? methods of the receiver returns true.
But, I’m not sure how casting to the mixed-in module of a singleton
class works in a simple way.

Well, maybe I should rather solve it in Java land and go down the
proxy path. We could also add the code in the attached file as
instance methods to ScriptingContainer - but that is probably rather
something for the dev list.

 "Foo.new";

ScriptingContainer sc = new ScriptingContainer();
Object receiver = sc.runScriptlet(script);
System.out.println(receiver instanceof Runnable);
new Thread((Runnable) receiver).start();

Yep. But this is exactly what I tried to avoid. Do you know the GC
effects of doing this with an anonymous class, will the code go away
after I released the instance? Because this works and would be a
solution:

final Object rr = sc.runScriptlet("require 'java'\nx = Class.new

do\ninclude java.lang.Runnable\ndef run;p self;end;end;x.new");
System.out.println(rr instanceof Runnable);
((Runnable) rr).run();

Kind regards

robert

On Tue, Mar 15, 2011 at 4:24 AM, Robert K.
[email protected] wrote:

On Mon, Mar 14, 2011 at 9:56 PM, Yoko H. [email protected] wrote:

Hello,

Hi,

thanks for replying - I hope you and your family are safe.

Thank you. I’m totally safe since I live in the U.S. :slight_smile: My family is
safe except power outage so far.

ScriptingContainer(LocalContextScope.SINGLETON,

proxy path. We could also add the code in the attached file as

 "  puts \"self: #{self}\"\n" +

after I released the instance? Because this works and would be a
solution:

Have you tried ScriptingContainer#terminate using master branch? The
terminate() method clears everything including gems in 1.6.0. This
might be what you want.

-Yoko

On Tue, Mar 15, 2011 at 3:01 PM, Yoko H. [email protected] wrote:

On Tue, Mar 15, 2011 at 4:24 AM, Robert K.
[email protected] wrote:

On Mon, Mar 14, 2011 at 9:56 PM, Yoko H. [email protected] wrote:

thanks for replying - I hope you and your family are safe.

Thank you. I’m totally safe since I live in the U.S. :slight_smile: My family is
safe except power outage so far.

Good!

Have you tried ScriptingContainer#terminate using master branch? The
terminate() method clears everything including gems in 1.6.0. This
might be what you want.

No, I don’t think this is what I need because I need to selectively
get rid of versions. In short, the implementation is derived from
other state. Whenever that state changes in particular ways I need to
create a new version but retain all old ones as long as they are
referenced somewhere. After the last reference goes out of business
GC should carry the implementation away with it.

At the moment I have these working options:

  1. Use an anonymous class, i.e. one per instance:

final Object rr = sc.runScriptlet(“require ‘java’\nx = Class.new
do\ninclude java.lang.Runnable\ndef run;p self;end;end;x.new”);
System.out.println(rr instanceof Runnable);
((Runnable) rr).run();

  1. Wrap the object in Java land with a Proxy (sample code was attached
    to my last mail).

Thanks again!

robert


remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/