Javet icon indicating copy to clipboard operation
Javet copied to clipboard

How to set Java Function interface with JavetCallBackContext

Open itschits opened this issue 10 months ago • 7 comments

Hi,

I am migrating from Nashhorn to Javet and I found a bit of issue when setting Java object which is implementing the Function Interface.

By default Nashhorn calls the apply method but in order to use JavetCallBackContext how I can set that to the v8 Global object. Your suggestion would be appreciated.

Thanks

public class Main {
   // a Function implementation
   private static class MyFunc implements Function<String, Void> {
       @Override
       public Void apply(String msg) {
           System.out.println(msg);
           return null;
       }
   }

   public static void main(String[] args) throws Exception {
       ScriptEngineManager m = new ScriptEngineManager();
       ScriptEngine e = m.getEngineByName("nashorn");

       // expose functional interface object as a global var
       e.put("dump", new MyFunc());

       // invoke functional interface object like a function!
       e.eval("dump('hello')");
   }
}

itschits avatar Feb 23 '25 05:02 itschits

Please check this doc out.

caoccao avatar Feb 23 '25 05:02 caoccao

Thanks for quick response. Well this doc says where we are creating a new customized callback receiver, but unfortunately in my requirement the jars are externally maintained and we just use them like as it is .In the example I have given above can we use as like below or is there any workaround?

Object.setFunction("dump", MyfunObj::apply)

A small code snippet will be much helpful for the above example

itschits avatar Feb 23 '25 06:02 itschits

Please follow the doc and use MyfunObj.class.getMethod("apply") instead.

caoccao avatar Feb 23 '25 14:02 caoccao

Thanks a lot for the reply. Your suggestion worked like a charm. However I am facing an issue when that apply method is returning any pojo the V8CallBackFuntion is basically converting the returning object into V8Value and inside that conversion method which is PrimitiveConverter making it undefined as the returning object is not of any of primitive type like String or Long etc.

Is there a way we can assign the returning object as it is to the JavaScript variable.

E.g

var x = demo(arg1,arg2); -> demo is returning a Employee object contains name, age, dept. var y = x.employee.name ; x-> is undefined here

I have followed the doc and test cases you have provided in GitHub but I didn’t find any solution.

itschits avatar Feb 25 '25 06:02 itschits

Please check this tutorial out.

caoccao avatar Feb 25 '25 08:02 caoccao

Thanks again for the help. With proxy converter it worked fine. But there is another issue which I am facing now is the auto conversion of the method parameter. If we pass any object into JavaScript function but that method signature is having string as parameter in Java our binding is not converting it obj.toString(). Hence I am getting casting error where the bind (Java) method is expecting a String as parameter and inside JavaScript we are passing an object to that method.

Can you please suggest how can we handle this. This is working fine in Nashhorn

Further more how can I attach overloaded methods of Java to the global object. If I pass the same name will it not overwrite the method signature ?

itschits avatar Feb 28 '25 05:02 itschits

  1. Implement your own converter which inherits the proxy converter. You may do whatever you want to do.
  2. The easiest way is to write a dispatching JS function.
globalThis.a = () => {
    if (arguments.length == 1) {
        a1(...arguments);
    }
    if (arguments.length == 2) {
        a2(...arguments);
    }
    // ...
}

caoccao avatar Feb 28 '25 06:02 caoccao