From a Javascript point of few, there are no generics, no interfaces, not even classes. In Javascript you have Objects with functions that may be created from prototypes.
To "implement" a Java interface in Javascript only means, to provide some Javascript object, that has the same function names as the interfaces method names, and these functions have the same number of arguments as the corresponding interface methods.
So to implement the generic example interface you provided, you can write something like this:
myGenericInterfaceImpl = new Object();
// Generic type is supposed to be <String> int calcStuff(String)
myGenericInterfaceImpl.calcStuff = function(input) {
println("--- calcStuff called ---");
println("input" + input);
println("typeof(input):" + typeof(input));
// do something with the String input
println(input.charAt(0));
return input.length();
}
Here it is assumed, that the intended generic class is of type String
.
Now lets say, you have a Java class, that accepts this interface with a generic String
type:
public static class MyClass {
public static void callMyInterface(IMyInterface<String> myInterface){
System.out.println(myInterface.calcStuff("some Input"));
}
}
You can then call this method from Javascript like so:
// do some Java thing with the generic String type interface
Packages.myPackage.MyClass.callMyInterface(new Packages.myPackage.IMyInterface(myInterfaceImpl)));
Some background information on the topic
If you are interested in what goes on behind the scenes in Rhino, when implementing a Java interface in Javascript, I recommend to have a look at the following Rhino classes:
- https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/jdk13/VMBridge_jdk13.java
- https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/InterfaceAdapter.java
Essentially the static method InterfaceAdapter#create()
will call VMBridge#newInterfaceProxy()
, which returns a Java Proxy
for the interface, that uses an instance of InterfaceAdapter
to handle method invocations on your interface. This proxy will map any Java method call on the interface to the corresponding Javascript functions.
**
* Make glue object implementing interface cl that will
* call the supplied JS function when called.
* Only interfaces were all methods have the same signature is supported.
*
* @return The glue object or null if <tt>cl</tt> is not interface or
* has methods with different signatures.
*/
static Object create(Context cx, Class<?> cl, ScriptableObject object)
When I first worked with generic interfaces in both Java and Javascript, it also helped me quite a lot to understand what is going on, by step debugging my invocations on the created Rhino proxies (but you will of course need the Rhino source to do that, and setting it up can be a little cumbersome).
Also note, that the default Rhino implementation used by the Java Scripting API does not allow to implement multiple Java interfaces or to extend Java classes. From the Java Scripting Programmer's Guide:
Rhino's JavaAdapter has been overridden. JavaAdapter is the feature by which Java class can be extended by JavaScript and Java interfaces may be implemented by JavaScript. We have replaced Rhino's JavaAdapter with our own implementation of JavaAdapter. In our implementation, only single Java interface may be implemented by a JavaScript object.
So if you need these features, you will need to install the original Rhino implementation anyway (which makes it easier to set up the source code).