Thursday, November 06, 2008

GWT: Calling GWT Classes and Methods from Regular Javascript

My current project involves us working with a group who uses a custom built web framework that works on top of Dojo. Since I prefer to use GWT, even for strictly client side Javascript due to the debugger, I needed something that would allow me to create a somewhat functional Javascript based library. Out of the box, doing so in GWT is a bit of a pain, involving the need to create native JSNI mappings to the GWT methods. This is ugly, and one of the reasons I like GWT is because the code can be much prettier in development, even if it is not in deployment. I would prefer a much more efficient way, where the creation of the publically exposed methods are hidden for the most part during the development. This would normally take some function of the compiler to do this, but the clever folks behind the GWT Chronoscope project figured out a way to do this using Generators. They were even nice enough to release the fruits of that work free of charge.

Now, I will give you fair warning, download the sample code from the SVN repository. The documentation for this is non-existent, and the only way you can figure anything out is by looking at the samples. Here I will try to give you a good idea how to implement this in your own code by using a real simple proof of concept.

In the following example, I am going to create a new GWT module that will expose a simple Hello World return to a DOM object whose ID will be passed in. I will be doing so in a GWT project in Eclipse, and my runtime stuff will be done using the Instantiations GWT Designer, although you can do this in any GWT IDE you like. This will be compiled against GWT 1.5.2.

The first thing you need to do is add the library for GWT-Exporter into your projects classpath. In my case, I am using the Alpha release for version 2.

Once added, I create a simple module with a blank onModuleLoad. Normally in the onModuleLoad, we want to load and prepare out Ajax based stuff, but in this case, I don’t want anything yet, I will add a little code to jumpstart the export process in a bit. First, I want to create a class that looks like so:

package com.digiassn.blogspot.client;

import org.timepedia.exporter.client.Export;
import org.timepedia.exporter.client.ExportPackage;
import org.timepedia.exporter.client.Exportable;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;

@Export
@ExportPackage("helloworld")
public class UpdateWithHelloWorld implements Exportable {
@Export
public void UpdateMyDomObject(String id)
{
DOM.getElementById(id).setInnerHTML("Hello World");
}
}

Also note the annotations for package and Export. This tells the generator that this class is to be exported, and that it is accessible by that package name.

With that class there is a slight problem. The Exportable class is not set up properly in the GWT Modules XML file. So I need to modify my ExporterExample.gwt.xml file to contain the Exportable class. Be sure to add in the option to export, otherwise it won't export your classes.


<module>
<inherits name="com.google.gwt.user.User"/>
<inherits name='com.google.gwt.user.theme.standard.Standard'/>
<entry-point class="com.digiassn.blogspot.client.ExporterExample"/>

<inherits name="org.timepedia.exporter.Exporter"/>
<set-property name="export" value="yes"/>
</module>


Now I can go ahead and update my onModuleLoad to tell the GWT-Export to export UpdateWithHelloWorld for outside Javascript to use.


package com.digiassn.blogspot.client;

import org.timepedia.exporter.client.Exporter;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class ExporterExample implements EntryPoint {
public void onModuleLoad() {
try {
Exporter export = (Exporter)GWT.create(UpdateWithHelloWorld.class);
export.export();
} catch (Exception e) {
Window.alert("Exception " + e.toString());
}
}
}


For now, I want to open my public HTML page, and create two things, the DIV tag that will be updated, and a small Javascript method that will call my GWT class. I use the following as a small test.


<html>
<head>
<title>Wrapper HTML for ExporterExample</title>
<link type="text/css" rel='stylesheet' href='ExporterExample.css'/>

<script language="javascript" src="com.digiassn.blogspot.ExporterExample.nocache.js"></script>

<script language="javascript">
function updateText()
{
var hello = new helloworld.UpdateWithHelloWorld();
hello.UpdateMyDomObject("updateMe");
}
</script>
</head>

<body>
<div id="updateMe">I show nothing right now</div>
<input type="button" onclick="updateText();">
</body>
</html>


And whala, when I click on my button, it will update my DOM code using the GWT. This demonstrates that a GWT based class and method are called from and outside Javascript.

You got to hand it to the guys over at Timepedia, this is a pretty cool little library. Now it is possible for me to do any Javascript based development, debugging, and re-use of components with my development in GWT for reliability and cross-browser support, and use in non-GWT based calls.

5 comments:

Scott Rosenbaum said...

how to you spell voila?

Bosco So said...

In the first code example, you didn't need to annotate the UpdateMyDomObject method with @Export. You'd already annotated the whole class so UpdateMyDomObject is exported automatically.

This article - http://tinyurl.com/at7ktl - talks about whitelisting or blacklisting exports in gwt-exporter.

Kalimaha said...

Many thanks, this article has been really useful to me!!!

Kalimaha said...

Many thanks, this article has been really useful to me!!!

Bosta Frontal said...

Thank you very much buddy!! This practical example was very helpful..