Can I build a Rhino JavaAdapter in Java, using a ScriptableObject?
Asked Answered
C

1

1

I've found a few questions about shuffling class definitions between Javascript and Java using Mozilla's Rhino. I've gotten far enough that this works:

Javascript:

new JavaAdapter(MyClass, {foo: function(){return 'Hello!';}});

Java

String script = // the above stuff
Object o = context.evaluateString(scope, script, "UserScript", 1, null);
MyClass mc = (MyClass) Context.jsToJava(o, MyClass.class);
mc.foo(); // returns "Hello!"

That blew me away, but I'd like to move the JavaAdapter construction from the Javascript to the Java side. I'm writing a framework where users will define logic in Javascript, and the less boilerplate they have to paste in the happier they'll be.

Ideally, I could do this:

Javascript:

{foo: function(){return 'Hello!';}};

Java

String script = // the above stuff
Object o = context.evaluateString(scope, script, "UserScript", 1, null);
MyClass mc = new JavaAdapter(MyClass.class, o);
mc.foo(); // returns "Hello!"

but as far as I can tell the JavaAdapter constructor doesn't take any parameters, there's no documentation for the class anywhere (for example, it's not here), and I haven't found any static methods (e.g. on Context or ScriptableObject) that create such a class. I also tried Context.jsToJava(o, MyClass.class), but that threw an exception.

Czar answered 26/7, 2012 at 15:16 Comment(0)
D
2

I've been beating my head on this one also. I finally got this to work:

Change your JavaScript to:

var xyz = {foo: function() {return 'Hello!';}};

Now replace your single line of code creating the JavaAdapter with this:

String stub = "new JavaAdapter(Packages.MyClass, xyz);";
Object o = context.evaluateString(scope, stub, "stub", 1, null);
MyClass mc = (MyClass) Context.jsToJava(o, MyClass.class);

I'm not an expert in this but it does seem that you can't use JavaAdapter directly from Java code (unfortunate), but we can run a piece of stub code to invoke it from JavaScript.

Beware of typo's in my example, I'm translating it from my working code.

Calling into the MyClass mc instance seems to work correctly. Calling from JavaScript (i.e. calling Java from foo) to access MyClass's super methods and fields seems to always require the 'this' keyword. I'm still trying to figure that out. Methods and fields in MyClass also have to be public instead of protected (also unfortunate).

Doloroso answered 27/12, 2012 at 0:23 Comment(1)
I know this is an ancient question but I'm still kinda-sorta working on this. Of note: I found that my JavaInterface'd "subclass" can call a protected superclass method, but not access a protected superclass field / variable. I guess that's expected behavior? I just added stupid one-line getters and setters, but it seems like it shouldn't be necessary.Czar

© 2022 - 2024 — McMap. All rights reserved.