Last updated by saavyone 4 months ago
GWT Plugin
The
Google Web Toolkit (GWT) is an advanced AJAX framework that allows you to develop rich user interfaces in Java, thus taking advantage of type-checking and code re-use. GWT will then compile your Java code and generate fast, cross-platform Javascript that can be included in any web page you choose.
The plugin makes it easy to incorporate GWT code into your GSP pages, and it also simplifies the handling of RPC requests on the server. If you have not used GWT before, please read the documentation on the GWT website.
Jan Ehrhardt has kindly created a simple
tutorial with sample code.
Alberto Zaccagni wrote a
gwt on grails tutorial with a working example of client side passing a transfer object to the server side.
You can also join in the discussions about the plugin and ask questions on the
Google Group for GWT/Grails integration.
You can find out what has changed between releases by looking at the
release notes.
How to use it
When starting with GWT, the first thing you need to do is create a module. This packages a bunch of client-side code into a single unit.
Creating a module
grails create-gwt-module <module>
The above command will generate a module file and a corresponding client class under your project's
src/java directory. If the name of the module includes a package (recommended), then the files are created in the appropriate directory path. For example:
grails create-gwt-module org.example.MyApp
will create the files
-
src/gwt/org/example/MyApp.gwt.xml , and
-
src/gwt/org/example/client/MyApp.java .
Creating a host page
Once you have a module, you need to create an HTML page that will host the user interface elements defined by it. Again, this is as simple as running another Grails command:
grails create-gwt-page <page> <module>
The first argument specifies the page to create, and the second specifies which GWT module the page should host. The page is given as a relative path to a file, which can for example have an "html" or "gsp" extension. If the path consists of a single directory and a GSP file name, then it is treated as a controller view. Otherwise it is treated as a normal web page.
// This will create the view file: grails-app/views/main/index.gsp
grails create-gwt-page main/index.gsp org.example.MyApp// This will create the file: web-app/dir/main.html
grails create-gwt-page dir/main.html MyModule// This will create the file: web-app/index.gsp
grails create-gwt-page index.gsp org.example.AnotherModule
With the first method, the script will offer to create the relevant controller if it does not already exist.
Trying it out
GWT has something called
hosted mode that allows you to test and debug your web interface from a custom browser. This is also available from the plugin. Just run this command:
This will launch the custom browser and point it at your running web application (it would be a good idea to run
grails run-app in one console, and this in another). If your web app is not running on the local machine, or it is not running on the default port (8080), you can pass a parameter to the script to point the custom browser at a different URL:
// Non-local host on port 8080.
grails run-gwt-client myServer // 'localhost' with a non-default port.
grails run-gwt-client 9090 // Combined.
grails run-gwt-client myServer:9090
To actually hit a breakpoint, you'll need to pass in -debug[=8000] (default debugPort is 5006). Then launch a process to attach to the debug port. I use STS(eclipse)'s debug launch configurations. So, run-gwt-client:
grails run-gwt-client -debug
will cause the following output:
Starting the GWT hosted mode client. …
[java] Listening for transport dt_socket at address: 5006Then, create a launch config in STS:
(Run->Debug Configurations...-> Select Remote Java Application in left tree view-> click New icon top-left)
Under Connect tab->
Project:Browse->select your project
Connection Type: Standard (Socket Attach)
Connection Properties:
Host: localhost (or remote host)
Port: 5006 (default, but whatever GWT Dev Mode is listening for)
Name: <whatever you want> I usually name it "<project> <command>"
Click Apply (or Debug if you're ready)Server-side RPC
Almost any non-trivial GWT application will require the use of its RPC support at some stage. GWT normally requires you to write a servlet for each service interface that you define, but the plugin simplifies this step by allowing you to implement the server-side RPC with normal Grails services. Any service can be configured for GWT by adding an
expose property, as is done with the Remoting plugin and others:
class MyService {
static expose = [ 'gwt:example.client' ] List listUsers() {
…
}
…
}The format of the GWT
expose entry is basically:
gwt:<package> where
<package> is the java package in which the associated RPC interfaces will be created. This will normally match a particular module's entry point package. The colon and package name are optional: if you just specify
gwt in the
expose list, the plugin will put the interfaces in a
client sub-package of the service's package. For example, if the Grails service is in the package
org.mysoft.myapp , then the interfaces will go into the package
org.mysoft.myapp.client by default.
You could create the RPC interfaces yourself, but the plugin provides a nice little command to give you a head start:
grails generate-gwt-rpc [--force] [--non-interactive]
This will create the required normal and asynchronous interfaces under the
src/java directory. The optional arguments shown only take effect if the interface files already exist. By default, the plugin asks you whether you want to overwrite such a file, but the
force option results in all existing files being overwritten, while
non-interactive automatically skips them.
For example, say you have a Grails service
example.MyService exposed via GWT. The plugin will generate these files for it:
-
src/java/example/client/MyService.java , and
- @src/java/example/client/MyServiceAsync.java@
Once you have generated the files, it is generally a good idea to maintain them yourself rather than regenerating them. You then have much greater control and usually much cleaner code.
When accessing the service from your client GWT code, use the URL described in this example:
MyServiceAsync myService = (MyServiceAsync) GWT.create(MyService.class);ServiceDefTarget endpoint = (ServiceDefTarget) myService;// Note the URL where the RPC service is located!
String moduleRelativeURL = GWT.getModuleBaseURL() + "rpc";
endpoint.setServiceEntryPoint(moduleRelativeURL);// Call a method on the service!
List users = myService.listUsers()
...
Collection and map types
GWT supports both collections (list, sets, etc.) and maps as method arguments and return types. However, it does not support generics to determine what types are collection or map holds; instead, the user must add a custom javadoc annotation to the RPC interface definition, '@gwt.typeArgs'. The plugin simplifies this process slightly if you are running on a 1.5+ JVM by supplying two annotation classes:
CollectionTypeArg and
MapTypeArg . These can be used to specify both argument types and return types like so:
import org.codehaus.groovy.grails.plugins.gwt.annotation.CollectionTypeArg
import org.codehaus.groovy.grails.plugins.gwt.annotation.MapTypeArgclass MyService {
static expose = [ 'gwt:example.client' ] // The return list contains objects of type java.lang.String.
@CollectionTypeArg(String)
List listUsers() {
…
} // The 'arg' parameter is a map whose keys are java.lang.Integers,
// and values are java.lang.Strings.
void processMap(@MapTypeArg(key=Integer, value=String) Map arg) {
…
}
…
} Note At the time of writing, the annotations will not work with method arguments. Hopefully this will be rectified for the Grails 1.0 release.
Compiling the GWT modules
The plugin will automatically compile your GWT modules the first time that you perform a normal Grails compile, for example via
grails compile or
grails run-app . Once a module has been compiled, however, it will not be compiled again in development mode. This is fine if you are using GWT's hosted mode to test your application, but any changes will not be picked up when using a standard browser. So, if you want to test the latest changes in development with a normal browser, you can manually compile the GWT modules with this command:
grails compile-gwt-modules
Creating a WAR
This is as simple as running the normal Grails command:
The plugin will ensure that the GWT modules are re-compiled before everything is packaged up in the WAR file. Once that's done, you can deploy your web application to any servlet container as normal.
Including inherited modules
Create a sub-directory called "gwt" under the Grails application "lib". Drop your GWT module jar files in this directory and compile-gwt-modules will automatically pick them up and add them.
Comment on the above client code (from yighu):
If you are using gwt 2+, you can put the following to the service interface MyService.java:
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("rpc")Then you can change these lines:
MyServiceAsync myService = (MyServiceAsync) GWT.create(MyService.class);ServiceDefTarget endpoint = (ServiceDefTarget) myService;// Note the URL where the RPC service is located!
String moduleRelativeURL = GWT.getModuleBaseURL() + "rpc";
endpoint.setServiceEntryPoint(moduleRelativeURL);
into:
MyServiceAsync myService = GWT.create(MyService.class);