Giter VIP home page Giter VIP logo

v8-adapter's People

Contributors

alextrotsenko avatar caer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

v8-adapter's Issues

Issues with multiple threads and V8Runtime cache

When using this adapter with multiple threads, and therefore multiple V8 instances, there are two problems I see with the design.

  1. There is no way to remove the V8 item from the cache, so this will grow indefinitely if used in a multi-threaded server installation.
  2. Once a V8 object is released, the equals function throws an exception. Most of the time, this isn't a problem, because there isn't a hash collision. However, with enough repetition there will be a hash collision and the equals method will be called causing a problem.

Seems like we need a way to release things from this cache either automatically or manually when releasing the V8 object.

How to create a complete NodeJS env?

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?

Indexed access on Java objects

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.

Bug with static methods in javascript to java linker(v8JavaStaticMethodProxy)

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.

Java bridge and synthetic methods should not be exported to JS object proxy

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.

Accessing injected java map values as JS Object properties

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?

Can you inject java classes during script execution?

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?

Adapter doesn't detect method signature with a V8Function parameter

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?

v8-adapter project visibility & discovery

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:

  1. Add link to this project in the the "read me" of J2V8 itself.
  2. Rename project/repo to something like J2V8-adapter. It will help people to discover it during the search in GitHub. E.g. Simple search for "j2v8" shows similar, but not finished J2V8-classes, but not v8-adapter.

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.

Injecting enums

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.

Next Generation V8 Engine for Java

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:

  1. Split up the unit test suite into separate test files for related functionality. Having one giant test is hard to maintain.

  2. 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.

  3. Cull all annotations and options that do not directly relate to injecting Objects, Classes, and Methods as they are.

  4. 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.

  5. Merge in the J2V8 project by taking only the V8-to-Java components (no Node.js support).

  6. 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!

Are objects being created in the global scope everytime V8JavaObjectUtils#translateJavaArgumentToJavascript is called?

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?

"JS function to Java Interface" Proxy leaking V8 native resources when GC-ed

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:

  1. in .finalize() method, which called during the GC.
  2. If Proxy was not GC yet - during the call to 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:

  1. By default implement the proxy as call-back function, but not listeners. E.g. allow functions to be called once. This way V8Function could be released right after it's invoked.
  2. If listener behaviour is required - introduce annotation like @JsListener. I could be present either on java interface declaration or when 3rd party interface is used as method argument.
  3. Listener implementation could be implemented in 2 ways:
    3.1. Keep hard reference to all the call-back functions and thus they will be released in the V8JavaObjectUtils.releaseV8Resources() as mentioned above.
    3.2. Provide "V8 executor" during V8-adapter initialisation. When .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 V8Functionlisteners 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.

How to inject the File class?

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

Conversion of Java Maps and List to JS objects and arrays.

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:

  • Behaviour of providing java api of Map and List objects could be desired/expected behaviour by the JS script.
  • It might be not desired/expected behaviour, but current api is still used by some existing 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:

  • injectedMap.get("myKey")
  • injectedMap.myKey
  • injectedMap["myKey"]

Possible solutions:

  1. Do not inject java map instance, but convert it to js object. Define .get(), .put(), .putAll(), .contains(), etc. method. Must be done per instance.
  2. Keep current approach of injecting objects and for the every key use "defineProperty" to emulate JS object api. Must be done per instance.
  3. Keep current approach of injecting objects and wrap it in the Proxy . Could be done per class.
  4. Do both: inject java map and convert java object to js Object. Set injected object as prototype of js object. Finally return js object.

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?

Unknown return type: class java.lang.Long when calling Date#getTime

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

Add ability to read data from V8 JS object

Right now when class is "injected" to V8, it's methods could have arguments as

  • primitives & String
  • or another Java class, which was injected from Java to V8 previously.

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.