Injecting a full Java instance into the V8 Context
See original GitHub issueSo I am trying to expose Java functionality to the V8 context and for this and I would need to be able to inject instances of objects (not necessarily POJOS) into the V8 context. And while this is already possible, the process itself is a bit painful and hard to mantain ( unless I’m doing something wrong). I created a very small basic sample of what I mean.
Let’s imagine this is the class of the instance I want to inject:
public class FileUtils {
private String prefix;
public FileUtils(String prefix) {
this.prefix = prefix;
}
public void doA() {
System.out.println(prefix+ "A");
}
public void doB() {
System.out.println(prefix+"B");
}
public void add(Integer v1, Integer v2) {
System.out.println(v1 + v2);
}
}
Let’s imagine this class belongs to an external library and has many many more methods with all sorts of diferent signatures. When I create a new instance of FileUtils, I would like to be able to inject that instance directly into the V8 context along with all those methods inside it, which, when called from javascript would trigger the java code inside them as shown above. So this is how I’m doing this at the moment:
I created a JavetObject converter and created a callback for every method inside the FileUtils class:
@SuppressWarnings("unchecked")
public class EntityConverter extends JavetObjectConverter {
@Override
public V8Value toV8Value(V8Runtime v8, Object object) throws JavetException {
V8Value v8Value = null;
V8ValueObject v8ValueObject = null;
v8Value = super.toV8Value(v8, object);
if (v8Value != null && !(v8Value.isUndefined())) {
return v8Value;
}
Class objectClass = object.getClass();
v8ValueObject = v8.createV8ValueObject();
for (Method method : objectClass.getMethods()) {
String methodName = method.getName();
try {
FileUtilsCallbacks call = new FileUtilsCallbacks(v8, (FileUtils) object);
JavetCallbackContext callback = new JavetCallbackContext(call, call.getMethod(methodName, method.getParameterTypes()));
v8ValueObject.setFunction(methodName, callback);
} catch (NoSuchMethodException ex) {
Logger.getLogger(EntityConverter.class.getName()).log(Level.SEVERE, null, ex);
}
}
v8Value = v8ValueObject;
return v8.decorateV8Value(v8Value);
}
}
And I created a JavetCallbackReceiver:
public class FileUtilsCallbacks extends JavetCallbackReceiver implements IJavetCallbackReceiver {
private FileUtils myInstance;
public FileUtilsCallbacks(V8Runtime v8Runtime, FileUtils myInstance) {
super(v8Runtime);
this.myInstance = myInstance;
}
//delegate the calls to the original instance 1 by 1
public void doA() {
this.myInstance.doA();
}
public void doB() {
this.myInstance.doB();
}
public void add(Integer v1, Integer v2) {
this.myInstance.add(v1, v2);
}
}
And finally putting it all together:
public static void main(String[] args) throws JavetException {
V8Runtime v8 = V8Host.getNodeInstance().createV8Runtime();
FileUtils fileUtils = new FileUtils("Hello ");
//create converter
EntityConverter converter = new EntityConverter();
//convert the fileUtils instance to a V8ValueObject
V8ValueObject val = (V8ValueObject) converter.toV8Value(v8, fileUtils);
v8.getGlobalObject().set("fileUtils", val); //inject it into the V8 context
//call the methods inside the fileUtils instance from javascript
v8.getExecutor("fileUtils.doA(); fileUtils.doB(); fileUtils.add(1,1);").execute();
}
All of the above is working perfectly without any issues. So what is the problem? Well, my issue here is with the JavetCallbackReceiver (FileUtilsCallbacks ), I had to duplicate every function inside the FileUtils class to put it inside the JavetCallbackReceiver (FileUtilsCallbacks ). For classes with many many methods, it’s painful to have to duplicate each and every method. Is there a better way to achieve this without duplicating code and making sure it applies to all methods inside the classes?
Issue Analytics
- State:
- Created 2 years ago
- Comments:9 (6 by maintainers)
Top GitHub Comments
Thanks! I tested it and I can confirm its working.
So far that’s by design. There’s a note at https://github.com/caoccao/Javet/blob/main/docs/tutorial/manipulate_v8_function.rst.
I guess I was lazy while designing the core algorithm. Javet may handle this automatically, of course, the performance will be slightly impacted. I’ll think it over.