4

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?

Jeremy Privett
  • 4,369
  • 2
  • 29
  • 35

2 Answers2

2

Yes, you can; previous poster is wrong. See the documentation for JavaAdapter.

David P. Caldwell
  • 2,691
  • 16
  • 26
  • 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. – Jeremy Privett Jul 13 '11 at 05:45
  • Actually, this is exposed in the javascript side and should still work with javax.script – Michael Deardeuff Sep 07 '11 at 03:07
  • 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). – Coderer Jul 26 '12 at 14:58
  • 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](http://docs.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html#jsengine). 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? – walter Jan 29 '13 at 14:32
0

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:

  1. 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.
  2. Define a naming convention that relates abstract classes to the wrapper, e.g. foo.MyAbstractClass corresponds to foo.MyAbstractClassDynamicLangWrapper.
  3. Roll a ClassLoader that implements findClass to recognize that naming convention and to generate the class bytes and calls defineClass
  4. 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.
Mike Samuel
  • 109,453
  • 27
  • 204
  • 234
  • That sounds nasty. I think I'll come up with another solution, if that's the case. – Jeremy Privett Jun 28 '11 at 07:00
  • @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 ? – 9me Aug 26 '19 at 13:18
  • @9me, are you running javascript compiled from typescript in Rhino? – Mike Samuel Aug 26 '19 at 15:07
  • 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 – 9me Aug 27 '19 at 06:49