teavm icon indicating copy to clipboard operation
teavm copied to clipboard

Compiling and then calling static Java methods from third-party javascript code

Open aghasemi opened this issue 5 years ago • 6 comments

Hi, I tried to find the answer to my question in the section "Interacting with JavaScript" of the docs, but I got a bit confused.

Suppose I have a Java codebase for some CPU-bound application, which I know want to run as a client-side web application by compiling then through TeaVM and calling from inside a UI framework (e.g. React). The "interfaces" to my Java code/library are static methods which receive and return simple objects (e.g. JSON). How is that done? Are there examples that I can see?

By the way, how does one deal with dependencies (e.g. in the form of JARs or one big fat jar) of such Java code? Are they all compiled in some huge .js file?

Many thanks

aghasemi avatar Nov 05 '20 19:11 aghasemi

First of all, TeaVM is not intended for CPU-bound applications. It produces JavaScript code which runs in the same JavaScript interpreter that executes hand-written JavaScript. Second, TeaVM was not intended to write libraries to be used from JavaScript. You can use workaround for this, like following:

interface Extported extends JSObject {
    void foo();
}

public class Main {
    public static void main(String[] args) {
        exportAPI(new Exported() {
            @Override
            public void foo() {
                System.out.println("It works");
            }
        });
    }

    @JSBody(params = "o", script = "main.api = o;")
    private static native void exportAPI(Exported o);
}

Then, from JavaScript use it like following:

main();
main().api.foo();

All code including dependencies is compiled into one JavaScript, not necessarily huge.

konsoletyper avatar Nov 06 '20 09:11 konsoletyper

Thanks for the workaround. Can you please elaborate a bit more, why is TeaVM "not intended to write libraries to be used from JavaScript"?

And about the interpreter, can't I run the CPU-heavy code then in a separate thread?

aghasemi avatar Nov 06 '20 09:11 aghasemi

Straightforward compilation of Java to JavaScript will produce poor results. Thus TeaVM has to apply different interprocedural optimizations, for which closed-world model is used. This produces some restrictions to interoperation with JavaScript and to reflection API. This also makes it impossible to generate modularized result (TeaVM consumes modules but produces single flat JS). If you have N Java libraries which you want to turn into N JavaScript libraries with TeaVM, you'll end up with N copies of Java runtime (each is unique, depending on how each specific library uses runtime).

You don't have threads in the browser. You have web workers that aren't threads, since they don't have shared state (so this makes them similar to processes). You can write web worker in pure JavaScript manually, so TeaVM does not give any significant advantage here. TeaVM was not intended for the goal "make CPU-bound computations efficient". TeaVM was intended (1) to share Java code between web client and other types of clients (2) to share Java code between client and server (3) to make it possible to write web applications in pure Java for the teams that already have infrastructure built around Java.

konsoletyper avatar Nov 06 '20 10:11 konsoletyper

Many thanks for the details. I believe moving (some) business logic and computational load from server to the client can be a legitimate goal as well. Here is an example, implementing some optimisation algorithms (in GWT, by me): https://mvgdemo.herokuapp.com/

As my last question, what happens if I need to pass/return some arguments to/from that foo function in your sample? How does one pas JSON objects for example?

aghasemi avatar Nov 06 '20 10:11 aghasemi

As my last question, what happens if I need to pass/return some arguments to/from that foo function in your sample? How does one pas JSON objects for example?

I think this article explains this in detail. You'll see JSON objects as JavaScript objects and you can interact them using JSO API. For example, you can define JSObject interfaces that declare all necessary properties or you can even define map-like interface (or re-use existing JSMapLike) to access dynamic JSON objects. Also, if you want to deserialize JSON to Java objects, you can use JSON serialization library from Flavour framework.

konsoletyper avatar Nov 06 '20 10:11 konsoletyper

Thanks. Will try.

aghasemi avatar Nov 06 '20 10:11 aghasemi