JsInterop hello world

565 views
Skip to first unread message

Brian Pedersen

unread,
Sep 15, 2015, 8:46:01 AM9/15/15
to GWT Users
So I am doing my first baby-steps in JsInterop, exposing a Java class to javascript, and I can't seem to figure out what I am doing wrong.

My java class looks like this:
@JsExport("poc.Hello")
public class JsHello  {
 
public String sayHello(String name) {
   
return "Hello " + name;
 
}
}

And the javascript in my host page like this:
var obj = new poc.Hello();
alert(obj.sayHello("there"));

My browser complains about 'poc' being undefined:
Uncaught ReferenceError: poc is not defined

Which is understandable, when looking at the implementation generated:
_.sayHello_0_g$ = function Cyb_g$(name_0_g$){
 
return 'Hello ' + name_0_g$;
}
;
var Ldk_bitwerk_client_JsHello_2_classLit_0_g$ = cDb_g$('dk.bitwerk.client', 'JsHello', 428, Ljava_lang_Object_2_classLit_0_g$);

I have tried all sorts of things, such using the real package/class name inside @JsExport, omiting the package/class name inside @JsExport and adding @JsType to the class declaration.
I have also tried annotating a constructor instead of the class.

I am running gwt-2.8.0-snapshot with jsInteropMode=JS, and I have committed the code here: https://github.com/bitwerk/jspoc

Any help will be much appreciated ...

/Brian

Jens

unread,
Sep 15, 2015, 1:31:58 PM9/15/15
to GWT Users
@JsNamespace("$wnd.poc")
@JsExport("Hello")
@JsType

public class JsHello {
 
public String sayHello(String name) {
   
return "Hello " + name;
 
}
}



I think the above should work. But there is already a commit pending which introduces new annotations for JsInterop which should make things a bit easier. The above example with new annotations would look like

@JsType(namespace = "poc", name = "Hello", export = true)

public class JsHello {
 
public String sayHello(String name) {
   
return "Hello " + name;
 
}
}


-- J.

Brian Pedersen

unread,
Sep 15, 2015, 3:15:30 PM9/15/15
to GWT Users
That didn't seem to make much of a difference, the generated javascript still have the wrong identifiers, and the error message is the same :(

I wonder if there is something wrong with my build, it looks to me as if the annotations are ignored.
I know that I run gwt 2.8, as I did a lambda to verify that, and I can see that the code server is started with '-XjsInteropMode, JS'.

Could I simplify it further, by removing the namespace or something?

Thanks ...

/Brian

Jens

unread,
Sep 15, 2015, 5:32:36 PM9/15/15
to GWT Users
Ok just played a bit and its like the following:


@JsExport // value attribute is ignored here, probably because it acts as a shortcut to apply @JsExport to any static member
@JsType // required so you also have exported instance members (your sayHello method) and not just static members
@JsNamespace("poc") // the default namespace, should probably go in a package-info.java file

public class JsHello {
 
public String sayHello(String name) {
   
return "Hello " + name;
 
}
}

With the above you can do

 
var hello = new poc.JsHello(); hello.sayHello("World");


If you want to rename JsHello to Hello you do

@JsExport
@JsType
public class JsHello {
 
 
@JsExport("poc.Hello") // replaces any @JsNamespace default value so you need to add namespace here
 
public JsHello() {}

 
 
public String sayHello(String name) {
   
return "Hello " + name;
 
}
}


I would try to avoid renaming, as you must repeat the namespace in @JsExport. Just name your classes correctly and stick with the first example with @JsNamespace in a package-info.java file.

-- J.

Brian Pedersen

unread,
Sep 16, 2015, 2:07:45 AM9/16/15
to GWT Users
Thank's Jens, your help is much appreciated. For now I will definitely go for a no-renaming approach.

It must be something with the way I run my code server.

I still get the same error, and when I inspect the generated javascript in my browser, it still has the obfuscated format. 
The generated javascript in the war file however, looks much better.

Maybe I just need to get the configuration of my gwt-maven-plugin right.

Thanks...
/Brian

Cristiano

unread,
Sep 17, 2015, 3:18:34 AM9/17/15
to GWT Users
Hi Brian,

I had problems similar to you when studying JsInterop, so I've tried your code.
I've forked your repo (see https://github.com/cristcost/jspoc) and I have made it work but with some considerations to take into account.
Other than the problems on using JsInterop annotations as reported by Jens, I've found a script load timing issue:
you execute the the Javascript code in the main page script, but at that point GWT has not yet loaded!

Putting the execution of your javascript code inside window.onload event is not again enough: I think this is because of using the xsiframe linker (I'm curious to try out with the sso linker).
So I have used a 3 seconds timeout... 

In the fork I've added some console logging to outline the time each part of the Javascript is executed, and the order is:
- first javascript inside main html page is executed
- then javascript inside the window.onload
- finally the GWT entry point

Your javascript code, with the fixes suggested by Jens, has worked after a 3 seconds timeout.

Of course I don't like this workaround, but a more general approach could be to have your application started from the GWT entry point (i.e. define a "main" function in javascript, then run it from GWT entry point). If you don't like the ping-pong between JS and GWT, you may try different solution to detect when GWT has loaded, or - if the problem is the xsiframe linker - try another linker.


Please note that I've changed totally the pom.xml and copied configuration from one of mines: in particular I have added a configuration for maven-jetty-plugin, 
so to try it out you need can execute the following commands:

git clone https://github.com/cristcost/jspoc.git
cd jspoc
mvn clean install
mvn jetty
:run


After this you should be able to open your browser at http://localhost:8888/ and you should see the alert popup (but 3 seconds after the page load!)

Hope this is helpful,

Cristiano


PS. I'm using gwt 2.8.0-SNAPSHOT and also gwt-maven-plugin 2.8.0-SNAPSHOT that I have compiled personally, so I don't have added the repo on the pom.xml,
you should re-add it from your pom.xml or compile the two by yourself. The gwt-maven-plugin 2.8.0-SNAPSHOT is available at https://github.com/gwt-maven-plugin/gwt-maven-plugin and I compile it skipping the tests with

 mvn clean install -DskipTests







Cristiano

unread,
Sep 17, 2015, 4:02:13 AM9/17/15
to GWT Users
Update:

with the sso linker the project responds as expected: the GWT code is available as soon as page has loaded

You could check it out on this branch:

note that: 
- with sso linker super dev mode don't work (I've worked manually compiling javascript and testing the compiled code directly)
- sso works only if you have exactly one permutation, and to obtain exactly 1 permutation I've removed inheritance of 'com.google.gwt.user.User' module (in fact your example was not using anything from that module)

Brian Pedersen

unread,
Sep 17, 2015, 9:07:20 AM9/17/15
to GWT Users
It all makes perfectly sense now, thank's a lot for taking your time to clarify your findings.

I like the concept of the sso linker, a pity it doesn't work with super dev mode yet. 
Using JsInterop with the xsiframe linker in super dev mode works equally bad for me, but maybe that's just me messing things up ;)

For some reason, I can't build your code with the 2.8.0-SNAPSHOT version of the gwt-maven-plugin.
I can check out and build the plugin sucessfully, but then when I build your projects, it apparently tries to resolve the gwt dependencies through the nexus.codehaus.org repository and fails.

But it all works perfectly when I build it with the 2.7.0 version of the gwt-maven-plugin, as long as I run it with jetty:run and not gwt:run.

What are your reasons for using the 2.8.0 version of the gwt-maven-plugin?

Thanks ...
/Brian

Cristiano

unread,
Sep 17, 2015, 11:12:33 AM9/17/15
to GWT Users
I use gwt-maven-plugin 2.8.0-SNAPSHOT for no reason in particular, 
but if you use 2.7.0 and you want to compile correctly with version 2.8.0 of GWT, remember to override the plugin configuration like explained in this page https://gwt-maven-plugin.github.io/gwt-maven-plugin/user-guide/using-different-gwt-sdk-version.html

<plugin>
 
<groupId>org.codehaus.mojo</groupId>
 
<artifactId>gwt-maven-plugin</artifactId>
 
<version>2.7.0</version>
 
<dependencies>
   
<dependency>
     
<groupId>com.google.gwt</groupId>
     
<artifactId>gwt-user</artifactId>
     
<version>2.8.0-SNAPSHOT</version>
   
</dependency>
   
<dependency>
     
<groupId>com.google.gwt</groupId>
     
<artifactId>gwt-dev</artifactId>
     
<version>2.8.0-SNAPSHOT</version>
   
</dependency>
   
<dependency>
     
<groupId>com.google.gwt</groupId>
     
<artifactId>gwt-codeserver</artifactId>
     
<version>2.8.0-SNAPSHOT</version>
   
</dependency>
 
</dependencies>

</plugin>

In the fork of your project I used gwt-maven-plugin 2.8.0-SNAPSHOT only to avoid adding these explicit dependencies on the plugin (gwt-maven-plugin 2.7.0 compiles by default with GWT 2.7.0).


It is weird that you get dependencies resolved on nexus.codehaus.org - btw codehaus.org has closed so it make sense it does not work, it is weird that it uses it...
I don't know which of your dependencies does it trigger resource resolution in that repo.
Keep your git repo up-to-date in case so I can check it exactly if you need more help.

bye,

Cristiano
Reply all
Reply to author
Forward
0 new messages