I'm working on a project that makes really heavy use of the javax.script.* packages. I have a situation where I would like to create JavaScript objects that extend an Abstract Java Class, much like you can use Invocable.getInterface to make JavaScript objects that implement Java interfaces. Is this possible? And, if so, how do you do it?
2 Answers
Yes, you can; previous poster is wrong. See the documentation for JavaAdapter.
4 Comments
Jeremy Privett
Unfortunately, I'm using the built-in stuff in the javax.script namespace which doesn't expose all of the underlying Rhino objects. My question was pretty specific to that situation, but this is still a somewhat useful answer.
Michael Deardeuff
Actually, this is exposed in the javascript side and should still work with javax.script
Coderer
Important note: the "documentation" for JavaAdapter is a joke -- there's a paragraph on the linked page, and a few sites around the net have generated JavaDoc with literally no commentary at all. :( Also, as Michael points out, you can do this -- in your Javascript code, you have to pass out
new JavaAdapter(MyJavaClass, {myOverloadedFunc: function(a,b){return a+b;}), which you can cast to a MyJavaClass using Context.jsToJava (that one actually has docs).walter
The JavaAdapter object provided by default in JRE6+'s javax.script package won't let you implement abstract classes in javascript. Only interfaces can be implemented using JavaAdapter. See Java Scripting. Not sure I agree with this statement from Oracle... > The uses of JavaAdapter to extend a Java class or to implement > multiple interfaces are very rare. ... extending Abstract classes is rare?
Unless you want to go the route of generating bytecode at runtime (using BCEL as below) then no. You can do it with interfaces using proxy classes but there is no equivalent for abstract classes.
If you really want to try BCEL, your best strategy is to do this:
- Write a method that uses BCEL to generate a
byte[]of bytecode for a new class that extends the abstract class and delegates every abstract method to JavaScript. - Define a naming convention that relates abstract classes to the wrapper, e.g.
foo.MyAbstractClasscorresponds tofoo.MyAbstractClassDynamicLangWrapper. - Roll a
ClassLoaderthat implements findClass to recognize that naming convention and to generate the class bytes and calls defineClass - Make sure your scripting language uses your custom classloader to resolve class names in scripts. I think in Rhino you use setApplicationClassLoader but I'm not sure.
4 Comments
Jeremy Privett
That sounds nasty. I think I'll come up with another solution, if that's the case.
9me
@Mike Samuel What about java to typescript. i mean vise versa. I am working on a project which is implementing some java native functions. What is the best way to do this ?
Mike Samuel
@9me, are you running javascript compiled from typescript in Rhino?
9me
No. I have a package written in java, and using some inner java classes ie java.util.stream. And now I am re-writing that package in typescript. I am able to implement my package logic, but what about
java.util.stream I can not implement now java class stream class at all. So my question was in my case what is the best way to do that ? I am trying to implementing few functions, but that is not enough. Thank you