GWT JsInterop for TeaVM

312 views
Skip to first unread message

Marcio Alves

unread,
Apr 17, 2017, 10:37:46 AM4/17/17
to TeaVM
Hello Alexey,

  I'm currently creating a converter from elemental2-beta1 to TeaVM JSO. My intent is to provide a smooth migration path from GWT to TeaVM. Since TeaVM JSO doesn't allow constructors, I'm converting to static create methods. 

  But I'm wondering if it would be better to create an implementation of GWT JsInterop for TeaVM.

  Is it technically possible to create a implementation of JsInterop using full or partial GWT JsInterop 1.0?

  The current JSO implementation could be a good starting point to implement it?


Thanks and best regards

Alexey Andreev

unread,
Apr 17, 2017, 10:46:07 AM4/17/17
to te...@googlegroups.com

  But I'm wondering if it would be better to create an implementation of GWT JsInterop for TeaVM.

  Is it technically possible to create a implementation of JsInterop using full or partial GWT JsInterop 1.0?
Yes, it's possible

  The current JSO implementation could be a good starting point to implement it?
JSO implementation is a good starting point, yes. Another starting point is html4j implementation (which can be found here). Also, I started jsinterop implementation myself, but abandoned it due to lack of free time. It can be found in this branch. The most non-trivial thing here is to understand how to interact with dead code elimination (which is for historical reasons is called DependencyChecker). JSO is designed to have very low impact on DCE, while html4j is not, so you can examine its code to understand how to extend TeaVM to properly track dataflow information for jsinterop.

Marcio Alves

unread,
Apr 17, 2017, 12:24:50 PM4/17/17
to TeaVM
Thanks Alexey! I will have a look.

Kirill Prazdnikov

unread,
Apr 18, 2017, 11:47:10 AM4/18/17
to TeaVM
Hi, we use a maven plugin that replace JsInterop annotations with TeaVM annotations so that the JsInterop code might be compilable under TeaVM.

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>delightex.ast.TeavmClassTransformer</mainClass>
<arguments>
<argument>${project.build.directory}/classes</argument>
</arguments>
</configuration>
</plugin>
...
</plugins>
</build>
this is the transformer class:

https://gist.github.com/kirillp/2a9aae58069090a06a71fcb5a9121f41

however this does not solve all the compatibility issues

Marcio Alves

unread,
Apr 21, 2017, 10:21:26 PM4/21/17
to TeaVM
Hi Kirill,

  Thanks for sharing. 

  I'm working at source code level. My implementation will try to solve all the compatibility issues. I planning to replace all the constructor invocations by factory method also. 

  As soon as I have some better results I'll share it. The libs first, then the converters.

  I'm working also in a JSweet def.* to JsInterop converter. This way we wiil have access to DefinetllyTyped definitions.

 My intent is to have convertes for GWT, TeaVM, JSweet, Bck2Brwsr, JTransC, Dragome, (J2CL?). 

 This way we will have freedom of choice.

 The guys from google are working in a generator from Closure external definitions (maybe .d.ts also).to JsInterop;

 Once they release it in the wild it will be possible to have access to those definitions, besides JSweet ones and currently available JsInterop projects. . .    

Best regards,

Patrick Pfeifer

unread,
Apr 28, 2017, 3:35:08 AM4/28/17
to te...@googlegroups.com
Running /root/org/teavm/jsinterop/ClassExportTest
Tests run: 18, failed: 0,

:-)

Hey - that looks promising.

But really cumbersome to set up - it took me some time until I figured
out that I need to start src/test/js/run.sh and then open start
src/test/js/index.html in Firefox before the timeout wins the
Promise.race() so that a websocket connection is established from
Firefox to Node to run the tests.

Is there an easier way to do it?


On 2017-04-27 22:34, Patrick Pfeifer wrote:
> On 2017-04-17 16:46, Alexey Andreev wrote:
>>
>>> But I'm wondering if it would be better to create an
>>> implementation of GWT JsInterop for TeaVM.
>>>
>>> Is it technically possible to create a implementation of JsInterop
>>> using full or partial GWT JsInterop 1.0?
>> Yes, it's possible
>>> The current JSO implementation could be a good starting point to
>>> implement it?
>> JSO implementation is a good starting point, yes. Another starting
>> point is html4j
>> <http://bits.netbeans.org/html+java/1.4/overview-summary.html>
>> implementation (which can be found here
>> <https://github.com/konsoletyper/teavm/tree/master/html4j>). Also, I
>> started jsinterop implementation myself, but abandoned it due to lack
>> of free time. It can be found in this branch
>> <https://github.com/konsoletyper/teavm/tree/jsinterop>. The most
>> non-trivial thing here is to understand how to interact with dead
>> code elimination (which is for historical reasons is called
>> DependencyChecker). JSO is designed to have very low impact on DCE,
>> while html4j is not, so you can examine its code to understand how to
>> extend TeaVM to properly track dataflow information for jsinterop.
>
> I decided to give that a try (i.e. JSO implementation). Thus I have
> migrated your branch back into current master and basically dumped all
> diffs and just kept the /jsonterop module and the files added in
> /tests . So far so good? It seems to work (e.g. it compiles).
> (JsInteropPostProcessor now implements RendererListener - which seems
> to be the successor of the AbstractRendererListener class that it
> extended.)
>
> I haven't run the tests (-DskipTests) but added the following two
> lines to HelloWorld Client instead.
>
> import static elemental2.dom.DomGlobal.window;
>
> window.alert("Ok");
>
> Now, when I try to compile that, I get the below errors. So I just
> wanted to ask a few things:
>
> * Do you think my approach is correct?
> * Can you point me in the right direction to make further progress?
> * When you look at the below error output, how would you go about
> fixing it? (In the teavm-samples-hello POM, I removed the "teavm-js"
> dependency and added "teavm-jsinterop" and "elemental2-dom".)
>
>
> [INFO] Building JavaScript file
> [INFO] Output file built with errors
> [ERROR] JS name collision (postMessage) detected on method
> elemental2.dom.DomGlobal.postMessage(Ljava/lang/Object;Ljava/lang/String;)V
> at elemental2.dom.DomGlobal.postMessage
> at org.teavm.samples.hello.Client.sayHello(Client.java:47)
> at org.teavm.samples.hello.Client.lambda$main$0(Client.java:35)
> at $$LAMBDA0$$.handleEvent
> at $$LAMBDA0$$.handleEvent
> [ERROR] JS name collision (postMessage) detected on method
> elemental2.dom.DomGlobal.postMessage(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V
> at elemental2.dom.DomGlobal.postMessage
> at org.teavm.samples.hello.Client.sayHello(Client.java:47)
> at org.teavm.samples.hello.Client.lambda$main$0(Client.java:35)
> at $$LAMBDA0$$.handleEvent
> at $$LAMBDA0$$.handleEvent
>
> ..... [truncated; ~ 100 more "JS name collision" errors] .....
>
> [ERROR] JS name collision (arguments) detected on method
> jsinterop.base.Js.arguments()Ljsinterop/base/JsArrayLikeOfAny;
> at jsinterop.base.Js.arguments
> [ERROR] JS name collision (undefined) detected on method
> jsinterop.base.Js.undefined()Ljava/lang/Object;
> at jsinterop.base.Js.undefined
> [INFO] Debug information successfully written
> [INFO] Source maps successfully written
> [INFO] Source files successfully written
> [INFO]
> ------------------------------------------------------------------------
> [INFO] BUILD FAILURE
> [INFO]
> ------------------------------------------------------------------------
>
>
>

Patrick Pfeifer

unread,
Apr 28, 2017, 3:35:08 AM4/28/17
to te...@googlegroups.com
On 2017-04-17 16:46, Alexey Andreev wrote:
>
>> But I'm wondering if it would be better to create an implementation
>> of GWT JsInterop for TeaVM.
>>
>> Is it technically possible to create a implementation of JsInterop
>> using full or partial GWT JsInterop 1.0?
> Yes, it's possible
>> The current JSO implementation could be a good starting point to
>> implement it?
> JSO implementation is a good starting point, yes. Another starting
> point is html4j
> <http://bits.netbeans.org/html+java/1.4/overview-summary.html>
> implementation (which can be found here
> <https://github.com/konsoletyper/teavm/tree/master/html4j>). Also, I
> started jsinterop implementation myself, but abandoned it due to lack
> of free time. It can be found in this branch
> <https://github.com/konsoletyper/teavm/tree/jsinterop>. The most
> non-trivial thing here is to understand how to interact with dead code
> elimination (which is for historical reasons is called
> DependencyChecker). JSO is designed to have very low impact on DCE,
> while html4j is not, so you can examine its code to understand how to
> extend TeaVM to properly track dataflow information for jsinterop.

Alexey Andreev

unread,
Apr 28, 2017, 3:43:02 AM4/28/17
to te...@googlegroups.com

> Running /root/org/teavm/jsinterop/ClassExportTest
> Tests run: 18, failed: 0,
>
> :-)
>
> Hey - that looks promising.
>
> But really cumbersome to set up - it took me some time until I figured
> out that I need to start src/test/js/run.sh and then open start
> src/test/js/index.html in Firefox before the timeout wins the
> Promise.race() so that a websocket connection is established from
> Firefox to Node to run the tests.
>
> Is there an easier way to do it?
Yes, there is. If you are an IDEA user, you can use shared run
configuration that runs tests. If you are not, you can create JUnit run
configuration from your IDE and pass following values for system properties:

-Dteavm.junit.js.runner=htmlunit -Dteavm.junit.js.threads=1 -Dteavm.junit.minified=true -Dteavm.junit.optimized=true


This will run tests in Rhino (htmlunit).

If you want to debug tests, you can go to tests/target/js-tests and
follow package/class/method you want, there you should find
run-test.html together with few JS files.

Alexey Andreev

unread,
Apr 28, 2017, 3:49:45 AM4/28/17
to te...@googlegroups.com

>
> import static elemental2.dom.DomGlobal.window;
>
> window.alert("Ok");
>
> Now, when I try to compile that, I get the below errors. So I just
> wanted to ask a few things:
>
> * Do you think my approach is correct?
I don't know what your approach is
> * Can you point me in the right direction to make further progress?
I don't know what you can do in particular. You can learn existing code
and implement missing features, write tests, test with existing GWT apps
that use JSInterop, ask certain questions. As for now, you should
probably investigate the reason of these error messages.
> * When you look at the below error output, how would you go about
> fixing it? (In the teavm-samples-hello POM, I removed the "teavm-js"
> dependency and added "teavm-jsinterop" and "elemental2-dom".)
They are obviously generated by JSO implementation, so you can simply
learn JSInterop support code base (it's not big comparing to entire
TeaVM). Another way is to set breakpoint on
AccumulationDiagnostics.error and see why compiler gets there.

Patrick Pfeifer

unread,
Apr 28, 2017, 2:31:26 PM4/28/17
to te...@googlegroups.com
Ah - that's a lot easier. I am an IDEA user and the config was right
there in the drop-down. Tests are running. (I don't understand yet what
the websocket connection is good for but will find out.)

Patrick Pfeifer

unread,
Apr 28, 2017, 2:45:47 PM4/28/17
to te...@googlegroups.com

>> [...] I have migrated your branch back into current master and
>> basically dumped all diffs and just kept the /jsonterop module and
>> the files added in /tests
>>
>> [...]
>>
>>
>> * Do you think my approach is correct?
> I don't know what your approach is
I was just referring to the way I merged your old branch back into
master. The question I should have asked is: Is it correct, that the
diffs outside of the /jsonterop and /tests modules are not relevant?
(The relevant unit tests passing seems to assert that this is the case.)

On another note I was wondering how, haw, if I should add any work that
I might be producing into the VCS repo ? Basically, I will fork the
project on Github and then push stuff there and make pull requests. This
seems clear so far. But then, on a more detailed level: Would you prefer
the changes to go on top of your old "jsinterop" branch or should I
merge-commit your branch into "master" - or should I start an entirely
new branch or should commit to master without merging your branch. :-)
(I will blame the fact that I have to bring up that question on git -
there are just too many possibilities and hence to many choices to be
made for me.)

Marcio Alves

unread,
May 1, 2017, 7:44:25 AM5/1/17
to TeaVM
Hi Patrick,

As far as I understood, the current jsinterop plugin deals with exporting to JS only. It doesn't deal with native access and that's what elemental2 is about.

Am I right Alexey?

Patrick Pfeifer

unread,
May 1, 2017, 9:01:53 AM5/1/17
to te...@googlegroups.com

> Hi Patrick,
>
> As far as I understood, the current jsinterop plugin deals with exporting to JS only. It doesn't deal with native access and that's what elemental2 is about.
>
> Am I right Alexey?
>
>
Hello Marcio

Yes, I ran into troubles with native methods. JsInterop allows name
clashes there:

"Note that name collision are allowed in native members since no code is
generated for them."
[https://docs.google.com/document/d/10fmlEYIHcyead_4R1S5wKGs1t2I7Fnp_PaNaa7XTEk0/edit#heading=h.igyjbkoshcvk]

But I haven't really seen that reflected in the code base yet.

Some namespace clashes are also happening on JsInterop @JsOverlay
annotated overloaded Java methods. (e.g. some non-native
Window.postMessage(X x, Y y), that is implemented as return
Window.postMessage(x, (Z) y))

/** * JsOverlay is used to enhance Java API of the native JsTypes and
JsFunctions so richer and more * Java friendly abstractions could be
provided. *
http://www.gwtproject.org/javadoc/latest/jsinterop/annotations/JsOverlay.html
This also, it seems, is yet to be implemented. ... Resolving the native method name clashes should be simple. They can basically just be ignored during JS generation I assume. As e.g. "Window.postMessage()" is defined in the browser anyway. Thus calls just need to be routed there properly, which I hope "just happens" somehow. But no implementation code needs to be generated.

In fact, apart from the "regular" Java Bytecode to Javascript transpilation, no JS code shall need to be generated for JsInterop classes at all, anyway. At least I have not yet spotted any possibility to "write Javascript" code via JsInterop, other than writing Java code and having it transpiled. (As compared to JSO's @JsMethod(body="your_javascript_here();").)

...

Anyhow. I actually am not really that much convinced of the whole JsInterop/elemental2 approach any more. I have shifted focus again already and am currently playing with the Python idl_parser in the cromium codebase. IDL scraping fromhttp://{html,dom,...}.spec.whatwg.org/ is trivial and so far I can feed it to the parser and print an AST representation. Chromium uses that parser to generate C++ glue code for communication between the Javascript (V8) and Layouting (Blink) engines in the browser. Being a bit disappointed of JsInterop, I am back to thinking about writing a generator that parser the IDL fragments from the HTML and DOM specs and generates JSO Java classes for TeaVM.

To make it short: I don't think I will actually be able to "fix" / get the JsInterop plugin to work any time soon. (Although by looking at the abstract problem and the existing code base by Alexey - ~10 classes in /jsinterop - it should not be too hard really and I would very much encourage anybody else to give it a shot.) But myself, I am so far just "playing" and being curious about TeaVM and web technologies. (Flow [https://flow.org/] is another thing that caught my attention recently. But it is unlikely that I will shift my attention that far away from Java, since I am really (too?) deep into that already. :-))

Reply all
Reply to author
Forward
0 new messages