GWT Plugin

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 to find out how to use it.

Jan Ehrhardt has kindly created a simple tutorial with sample code.

Installation

  1. Download and install GWT from here. Make sure you get the right version for your platform!
  2. Set the GWT_HOME environment variable to the directory where you extracted GWT, e.g. /home/sinbad/dev/gwt-linux-1.4.60 .
  3. Install the plugin in any Grails project by running grails install-plugin gwt .
MacOS X 10.5 (Leopard) users should use the GWT binaries from here:

http://google-web-toolkit.googlecode.com/files/gwt-leopard-1.4.61.tar.gz

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:

grails run-gwt-client

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

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.

You should now run the application ( grails run-app ) so that the plugin generates the required RPC interfaces. The plugin will also update these interfaces as you make changes to your service unless you modify the interfaces yourself. As soon as you make changes to them, the plugin will stop synchronising them with the corresponding Grails service. This allows you to maintain full control of the interface definitions, although you lose the convenience of automatic synchronisation.

  • src/java/example/client/MyService.java , and
  • @src/java/example/client/MyServiceAsync.java@
Note If you modify either file yourself, then the plugin will no longer update them automatically. This is to ensure that any changes that you make are preserved, such as adding '@gwt.typeArgs' javadoc annotations.

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.MapTypeArg

class 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:

grails war

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.

9 Comments

  • Gravatar
    Hi, I am getting a problem with the Java code for the Grails service generated by the plugin.

    The GWT compiler will not compile them ( "ERROR (+) In order to produce smaller cl ient-side code, 'Object' is not allowed; consider using a more specific type")

    [java]             Generating client proxy for remote service interface 'or
    g.example.client.MyService'
         [java]                Analyzing 'org.example.client.MyService' for serializ
    able types
         [java]                   Analyzing methods:
         [java]                      public abstract java.lang.Object super$1$clone(
    )
         [java]                         Return type: java.lang.Object
         [java]                            java.lang.Object
         [java]                               [ERROR] In order to produce smaller cl
    ient-side code, 'Object' is not allowed; consider using a more specific type
         [java]                      public abstract java.lang.Class super$1$getClas
    s()
         [java]                         Return type: java.lang.Class
         [java]                            java.lang.Class
         [java]                               [ERROR] Type 'java.lang.Class' was not
     serializable and has no concrete serializable subtypes
         [java] [ERROR] Errors in 'file:/C:/workspace/gwt/src/java/org/example/clien
    t/MyApp.java'
         [java]    [ERROR] Line 22:  Failed to resolve 'org.example.client.MyService
    ' via deferred binding
         [java] [ERROR] Cannot proceed due to previous errors

    This code is generate by the plugin, though! Why would it not compile?

    Similar issues here

    http://code.google.com/p/derjanandhisblog/wiki/GWTGrailsTutorial (most recent comments)

    http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/8b2f2df7f9931504

    Someone please tell me how I can please the compiler :P

    Apr 01, 2009 00:04 AM jmitcheson
  • Gravatar
    Sorry Grails 1.1 GWT 1.5.3
    Apr 01, 2009 00:04 AM jmitcheson
  • Gravatar
    Well, seems that plugin creates service with all methods stubs derived from Object (e.g. wait(), notify(), toString() etc.

    As the workaround, you can just manually remove them from YourService and YourServiceAsync. According to documentation, it will stop synchronizing service stubs code with Grails service, but at least it will compile. Plugin need to be fixed definitely to do not produce method stubs derived from Object.

    Apr 07, 2009 04:04 AM softsky
  • Gravatar
    I did a rather silly patch for this in GwtGrailsPlugin.groovy. I added the last condition and this solved the problem.

    <code> if (!Modifier.isPublic(method.modifiers) || Modifier.isStatic(method.modifiers) || GROOVY_METHODS.contains(method.name) || propMethods.contains(method) || method.name =~ /$/ ) { return } </code>

    May 03, 2009 08:05 AM scottburch
  • Gravatar
    There is supposed to be a backslash before the dollar sign in the previous comment, it did not show up.
    May 03, 2009 08:05 AM scottburch
  • Gravatar
    So they released GWT 1.6, and it seems they changed quite a bit, not the least of it being the directory structure. They also added a better eclipse project builder and a new HostedMode browser as well as support for deploying the server side on app-engine in build.xml and the new googleplugin for eclipse. Sadly grails 1.1 does not yet work on appeng, but it seems they are working on that (there is also a plugin for grails). Maybe on day we can get all that working together inside eclipse (meaning: gwt, and grails deployment on app-eng).

    I been doing a lot of tinkering with eclipse and gwt-grails plugin lately, like writing my own launch.conf to get both the server and client launched inside eclipse, but I can't get it running with GWT-1.6. Anyone working on that or interested in my help for getting it working again? Lemme know.

    May 05, 2009 20:05 PM derDoc
  • Gravatar
    Hi, I'm trying to use gwt plugin 0.3.1 (0.3.2 is not available) with a grails application but when I use the command grails create-gwt-module <module> it creates the module in the folder src/gwt of my project. Then, when I use grails generate-gwt-rpc command it creates the classes in src/java instead of src/gwt. When I finish it obviously doesn't work. I'm trying it with grails 1.1.1 and gwt 1.6 and gwt plugin 0.3.1. A week ago I tried to do it with grails 1.1 gwt 1.5.3 and gwt plugin 0.3 (it creates modules in src/java) and following Jan Ehrhardt tutorial it worked. Any suggestions?thx
    May 18, 2009 04:05 AM alexm
  • Gravatar
    With the tutorial and the documents above I was able to get a simple prototype to run.

    I am not able to debug said prototype.

    I'd like to use:

    grails run-gwt-client

    so that I can debug my application.

    When trying to run the application, I get:

    ERROR (+) Unable to find 'proto.gwt.xml' on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source?

    I think some more hints in the docs wrt "grails run-gwt-client" would be apropos.

    My app runs fine with grails run-app but not at all with run-gwt-client. How do you use run-gwt-client to debug a GWT GUI?

    May 19, 2009 15:05 PM RickHigh
  • Gravatar
    Hi, When I use the generate-gwt-rpc, I get the empty Java classes created. But without any content. I'm using Grails 1.1.1.

    /daniel

    Jun 12, 2009 04:06 AM dgraversen

Post a Comment