alicorn-systems / v8-adapter Goto Github PK
View Code? Open in Web Editor NEWAdapter for sharing Java classes and objects with a V8 runtime.
License: BSD 3-Clause Clear License
Adapter for sharing Java classes and objects with a V8 runtime.
License: BSD 3-Clause Clear License
When using this adapter with multiple threads, and therefore multiple V8 instances, there are two problems I see with the design.
Seems like we need a way to release things from this cache either automatically or manually when releasing the V8 object.
Any hope to get this working on android?
There is a NodeJS class in J2V8 lib. I could use this class to Create a complete NodeJS env, including 'require' function and using any other NodeJS modules.
How could I do it in 'v8-adapter' scripting engine?
Hello.
I want to use indexed/key access on Java objects which are not maps, lists or arrays. In Rhino it could be done by overriding public Object get(int index); public Object get(String key);
on wrapper objects. Is there any way to achieve same with your library? Sorry if it mentioned somewhere, but I could not find an answer.
Thank you.
here is an expected error message
undefined:1: Wrong number of arguments; expected 2*, got 0
*any number for a method with more params than 0.
the cause is at line 45 of V8JavaStaticMethodProxy with the following statement.
return V8JavaObjectUtils.translateJavaArgumentToJavascript(coercedMethod.invoke(coercedArguments), V8JavaObjectUtils.getRuntimeSarcastically(receiver), cache);
to be specific, coercedMethod.invoke(coercedArguments)
is improper call for a static method.
the following coercedMethod.invoke(null,coercedArguments)
I suspect will have the desired effect for static methods with parameters.
with Method.invoke, the first parameter is a live (non static) object of a class, if it is null, it will default to a static methods only of said class. the second parameter(or v varargs if you rather call it) is all the passed variables for the method.
On some conditions Java compiler (as well as Kotlin compiler) generates bridge and synthetic methods.
Such methods are needed to provide either backward compatibility (methods with covariant return types are java 1.5+ only) or provide behaviour defined by specification, but not possible with JVM directly (accessing private members of parent class in inner or nested classes).
These methods are not defined in the source code directly and should not be exported to the JS.
Apologies for opening this issue as I've noticed this has been talked before (#11) but I'm a little confused. Is this possible to do somehow with a V8JavaClassInterceptor right now? Or is this a planned feature for the new restructure? If this is possible to achieve with the current version, could you provide an example of how to do it?
I have a class which I am injecting as an object in to the runtime
public class JavaManager {
private V8 runtime;
public InjectJava(V8 runtime) {
this.runtime = runtime;
}
public void importClass(String className) {
try {
V8JavaAdapter.injectClass(Class.forName(className), runtime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
so I can inject classes using Java.injectClass('class')
in a script, similar to how import and require work, but instead with Java classes. However, when loading the script with J2V8 I get a java.lang.Error: Runtime disposed error
error? Any ideas of how to solve this, or am I just missing something?
I'm trying to V8JavaAdapter.injectObject with an object that has this method signature:
public void alert(String title, String msg, final V8Function onOk)
and getting this error:
No signature exists for alert with parameters [title, message, function () {
console.log("pressed");
}, ].
Any idea why?
Details are in the eclipsesource/J2V8#372
Initial implementation is done in the 4de3f26
This issue is added for tracking.
This project looks really great and provides nice way for sharing Java classes in JS runtime.
The only problem for me was - it is very hard to discover it.
Few ideas, which, as for me, might help other people to find, benefit and contribute to this project:
P.S. I have found this project when I was checking issues of J2V8 and thus found your comments about v8-adapter in the different issues. So, this is really helpful as well.
Are enums supported? Tried to inject one with .injectClass but always turned out null. If they're not supported, are there plans to support it in the future? Would be really handy for some of my use cases.
We have been working on the V8 adapter for the past year now, adding new features and fixing bugs where they show up. Because this project never had a formal structure or goals, it has grown wildly and seen many new features, etc. Unfortunately, the base project - J2V8 - has also grown quite wildly and has not received any new commits in the past six months.
Knowing this, I would like to propose a new work effort to do the following with this project, in this order:
Split up the unit test suite into separate test files for related functionality. Having one giant test is hard to maintain.
Remove all static fields and instead wrap V8
objects in a new V8Runtime
object which contains its own V8 instance and injection API. Class caches can be per-runtime or shared.
Cull all annotations and options that do not directly relate to injecting Objects, Classes, and Methods as they are.
Introduce a formalized API for decorating classes or groups classes with additional features like those found in #1 and #11 by third-party applications. We may provide built-in implementations for marshaling getters and setters, as a convenience. This API could also include a ByteBuffer-based messaging system so that the host (Java) may communicate with the guest (JavaScript) without a single JNI call, thus dramatically improving performance.
Merge in the J2V8 project by taking only the V8-to-Java components (no Node.js support).
Formalizing the build process so that all major platforms can be built for from the same system for the same V8 version at the same time.
This is a lot of steps to perform - and they will definitely cause breaking changes - so I would like to hear from other contributors, particularly @AlexTrotsenko. Thank you all so much for your time and interest!
I was looking at the source and it seems to me that the method to translate a java object to a javascript V8Value is creating a new global object on the global scope of the V8 runtime with a random UUID. Is my understanding correct about this?
If this is the case, I have to say this worries me a bit. I noticed there is a cache in place that checks if the object already exists to avoid creating it again, but in my use case that will be a very rare scenario. My application is a long running server that will be up for months without restarting, it will be receiving events quite frequently. Java methods with several arguments are triggered when these events happen, I'm then using the translateJavaArgumentToJavascript method to convert those arguments to javascript V8Values
and calling javascript functions using v8.executeJSFunction and passing those arguments to those javascript functions. That said, I only want those objects that I'm passing as arguments to exist inside that javascript function scope and not in the global scope, because if not, after a few months running my application, I will have a few hundred maybe thousand global objects on the global scope, and I'm concerned this is just not very memory effecient.
Is there a better way to handle this? Do java objects absolutely have to be injected into the global scope to convert them to V8 values?
Currently it's possible to provide Java functional interface for the cases where JS function is passed from JS to Java.
It's implemented using Proxy and V8FunctionInvocationHandler.
Currently .release() of native j2v8 objects is implemented:
.finalize()
method, which called during the GC.V8JavaObjectUtils.releaseV8Resources()
: Underlying V8Function
function is stored in the v8Resources
and thus released.Issue: while 2nd option working well and tested in the unit tests, the 1st option is leaking j2v8 native objections (v8 function and v8 receiver).
It's hard to test 1st case as it involves GC, which runs at not determined period of time. Also following comment in the source code highlight possible problem as well:
// TODO: How do we release if this gets executed on a different thread?
I have tested it and indeed GC is run on the separate thread. E.g. on Nexus 5/Android 6 it's running on FinalizerDaemon
. But all J2V8 objects requires .release()
to be called on the same "v8 thread".
As result the Proxy object is released, but native j2v8 object are leaking.
Possible solution:
V8Function
could be released right after it's invoked.@JsListener
. I could be present either on java interface declaration or when 3rd party interface is used as method argument.V8JavaObjectUtils.releaseV8Resources()
as mentioned above..finalize()
is invoked - this executor can run .release()
of underlying V8Function
on the proper v8 thread.Implementing listeners as 3.1 will result in retaining all V8Function
listeners in memory until V8 is released.
Implementing listeners as 3.2 would require passing V8 executor, which leads to additional requirements of end users of v8-adapter lib.
Also different behaviour could be implement if V8 executor is present or not - but this sounds to much complicated for now.
Also as an option V8FunctionInvocationHandler
and resulting proxy could implement Releasable
interface and released manually if they need to be called known amount of times. E.g. 2 or 3 , etc.
@crahda as for me, adding v8 executor does not make things to much complicated for end users as it would be need only for listeners (but not for call-backs). Instead it would allow proper memory clean-up.
Additionally if this behaviour is implemented - some default functional interface like JsFunction
could be created. And if function is present inside of the JS object - it could be automatically converted to Map without worries of leaking memory.
Hello, is it possible to inject the File class using the V8JavaAdapter?
I've tried the following:
public static void main(String[] args) {
V8 v8 = V8.createV8Runtime();
V8JavaAdapter.injectClass(File.class, v8);
v8.executeVoidScript("var f = new File( \"test.txt\" );");
}
This results in:
Exception in thread "main" undefined:1: Constructor received invalid arguments!
this.File = function() {v8ConstructJavaClassjava_io_File.apply(this, arguments);
^
com.eclipsesource.v8.V8ScriptExecutionException
at com.eclipsesource.v8.V8._executeVoidScript(Native Method)
at com.eclipsesource.v8.V8.executeVoidScript(V8.java:944)
at com.eclipsesource.v8.V8.executeVoidScript(V8.java:652)
at com.eclipsesource.v8.V8.executeVoidScript(V8.java:638)
at vcmp.NewMain1.main(NewMain1.java:22)
Caused by: java.lang.IllegalArgumentException: Constructor received invalid arguments!
at io.alicorn.v8.V8JavaClassProxy.invoke(V8JavaClassProxy.java:455)
at com.eclipsesource.v8.V8.callObjectJavaMethod(V8.java:739)
... 5 more
This is one feature of Rhino, which is still missing in current project - ability to access Java maps and lists as JS objects and JS arrays when they are injected in V8 runtime.
Right now, after implementing this pull request, JS objects could be read as Java maps. Vice Versa conversion would be nice as well.
It could be easily done, but there are some issues related to backward compatibility and expected behaviour: currently when map is injected in JS runtime - it provides .get()
/.put()
api. Thus:
Map
and List
objects could be desired/expected behaviour by the JS script.Thus keeping .get()
/ .put()
api is the needed as well as ability to access data in JS-object way. E.g. following should work:
Possible solutions:
.get()
, .put()
, .putAll()
, .contains()
, etc. method. Must be done per instance.Proxy
. Could be done per class.Options 1
and 2
looks a bit complicated and not the best from performance point of view if map has big amount of entries and JS access only one or two of them.
Option 4
looks the easiest to implement, but it must be read-only JS object at the end, which is not matching all the use-cases.
Thus option 3
looks most easy and reliable. The only complicated part - is compatibility with v8
/ j2v8
version. Shortly: we need to use newer version of it.
@crahda what do you think about this issue in general and the preferred approach to implement it?
After injecting the Date class and the Long class I get an Unknown return type: class java.lang.Long when calling Date#getTime
V8 v8 = V8.createV8Runtime();
V8JavaAdapter.injectClass(Long.class, v8);
V8JavaAdapter.injectClass(Date.class, v8);
v8.executeVoidScript("var d = new Date(); var time = d.time;");
I also tried to inject long.class instead of Long.class but the result was the same
Right now when class is "injected" to V8, it's methods could have arguments as
For example, there is no way to read data from JS object {y: 'done'}
when it passed to java method - following exception is thrown:
IllegalArgumentException: No signature exists for readJsObjectAsJavaObjectAndTryGetY with parameters [[object Object], ].
Instead, when there is call similar to x.readJsObjectAsMapAndGetY({y: 'done'})
, it should try to "translate" the content of the JS object to Java object, e.g. Map.
Here x is our Java class.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.