Using and creating GWT modules Tutorial

Posted by

Introduction

If you are trying to build a complex GWT application that needs to be split into multiple modules, or if you need to import 3rd party modules into your application, this tutorial will show you how to do both of these things. At the end of this tutorial, you will find the IDEA project that you can use to see the end result of the steps you have to take in this tutorial.

If you are unfamiliar with GWT basics, please refer to our GWT Intro, Anatomy of a GWT Project, and Hello World tutorials.

To learn more about GWT, I recommend reading these good books – GWT Solutions, GWT Applications, AJAX Security.

Using modules

If you are building applications with GWT, it’s very likely that you will have to import modules, either standard GWT modules like com.google.gwt.user.User, or 3rd party modules that you’ve written yourself, or you’ve downloaded from the web. Here’s an example of a good GWT module that can be used in just about any GWT app – GWT Log by Fred Sauer.

GWT Log

Just as a quick background, GWT does not have a console log class. GWT Log is the rough equivalent of Log4J for your GWT apps. You are able to display error, info, debug, and warning messages to your browser, as your app runs. You can set the log level globally, and even turn of logging when you put your app into production. You can download the latest version here.

Step 1 of 2 : Importing the JAR file

Fortunately, importing a 3rd party library in GWT is very similar to regular Java, with a few major differences:

  1. The JAR file must have source code and compiled classes placed in the same folders as the source code
  2. The rules for naming/referencing items in the package are different and will be covered in the “Creating modules” section.

Using your favorite IDE, I’m going to show you how use IDEA, but the steps are very similar for any other IDE, add the JAR file as a project library. Here’s a screenshot that shows you how to this in IDEA:

1. Open Project Settings, and then select Libraries, and add a module library.

2. Be sure to add this module to an existing project as a dependency.

image

3. Now attach the JAR file for GWT Log to this library, by clicking on “Attach Classes”, and locate the JAR file on your machine.

We’re not done yet. You have now added an external library to your GWT project in your IDE, but GWT still has to be told that you want to use this JAR file in your XML module descriptor.

So if you start to add references to the GWT Log file in your code, your IDE might prompt you to import the required Java classes:

image

However, even after you add this statement “import com.allen_sauer.gwt.log.client.*;“, your GWT module will still not know how to use this class? Why? Read on…

Need more help? developerlife.com offers training courses to empower you, and consulting services to enable you.

Step 2 of 2 : Adding a dependency in your XML module descriptor

GWT is a nice facade over a Java -> Javascript compiler, and this is where you “feel it”. Even though your IDE can access this module that you’ve just added, you can’t really use it in your GWT Java code yet. Why? Because you have to describe all the Java source and other resources for your GWT module in your XML module descriptor. This is not a problem for IDEA, because you can use the Intention to do this step for you:

image

Here’s the line that’s added to the XML descriptor file as a result of this action:

<module>
  <inherits name='com.google.gwt.user.User'/>
  <!-- THE FOLLOWING LINE IS ADDED TO IMPORT GWT LOG INTO YOUR MODULE -->
  <inherits name="com.allen_sauer.gwt.log.gwt-log"/>
  <!-- Change default value from 'OFF' to 'DEBUG' -->
  <extend-property name="log_level" values="DEBUG"/>
  <set-property name="log_level" value="DEBUG"/>
  <entry-point class='client.Module1'/>
  <servlet path="/Module1/TestService" class="server.TestServiceImpl"/>
</module>

The key line is “<inherits name=”com.allen_sauer.gwt.log.gwt-log”/>“. This line tells your GWT module to inherit the Log module. Notice that there is no reference made to the JAR file, only to the fully qualified name of the GWT Log Module (not the GWT Log classes). I will show you how to create a module, and how to name a module in the next section. Once you know how to name a module, you will understand how GWT names things, as this can be a little confusing at first, if you are used to Java classpaths, packages, and naming conventions.

Also, note the “log_level” extend-property and set-property entries have to be made in the XML module descriptor, in order for GWT Log to display anything to your browser. For version 1.4.3 you have to add these parameters in your XML module descriptor, because logging is turned off by default (for production). More information on this is available here.

Usage

Here’s some source code in the “Module1.java” file that shows you how to use this Log class. You can find it in the downloads section of this tutorial.

package client;
import com.allen_sauer.gwt.log.client.*;
import com.google.gwt.core.client.*;
/**
 * Module1
 *
 * @author Nazmul Idris
 * @version 1.0
 * @since Jan 11, 2008, 5:45:29 PM
 */
public class Module1 implements EntryPoint {
public void onModuleLoad() {
  Log.setCurrentLogLevel(Log.getLowestLogLevel());
  Log.setUncaughtExceptionHandler();
  Log.info("msg");
}
}

Creating modules

The toughest part in creating a module is understanding which folder to include in the JAR file of the module, and how to reference this module from a different module. Here are some things to remember to make this process easier:

  1. Include the source code for your module along with the classes in the same folders.
  2. Which folder should you include in your JAR file? What’s the top level/root folder that get’s put in the JAR file? This is a tough one to answer… most of the time, this will be the folder that is the top level folder that you reference in your package statements in the classes that you write. The XML module descriptor can be placed anywhere, so don’t assume that the folder with the <ModuleName>.gwt.xml file is the root!

Let’s use GWT Log as an example. If you look at the gwt-log-1.4.1.jar file, this is what you will find:

gwt-log-1.4.1.jar:
+---com                       <--- this is the ROOT folder
¦   +---allen_sauer
¦       +---gwt
¦           +---log           <--- this is where the XML module descriptor goes
¦               +---client    <--- this is where the Java source code goes
¦               ¦   +---impl  <--- more Java source code
¦               +---public    <--- any resources that should be copied to the inheritor module
+---META-INF

The XML module descriptor “gwt-log.gwt.xml” is in the “gwt-log-1.4.1comallen_sauergwtlog” folder. There is no “src” folder in this JAR file. The ROOT folder, for this module is “com”. So how do you know what a root folder is, given that the XML module descriptor can be anywhere? Well, in GWT, since the XML module descriptor can be anywhere, the ROOT folder is determined based on how far up the folder hierarchy you reference the XML module descriptor in the Java source code. In this example, all the class files are in the following Java package – com.allen_sauer.gwt.log.client. So, this package path references the “com” folder as the ROOT. If you wanted to distribute this module in a JAR file, you would have to make sure to include everything (class files and Java files) under and including the “com” folder. But make sure you don’t nest the “com” folder under some other folder. Whew!

A simpler example – “Module1.jar”

Let’s say that you didn’t want to create a complex package structure like the one in GWT Log. Let’s say you wanted to take the following module structure and distribute it in a JAR file, as a reusable module:

src            <--- this is where the XML module descriptor goes
+---client     <--- all the Java source code goes here
+---public     <--- all the resources (CSS, HTML, images) go here

In this simplified project structure, we have a single class Module1.java, in the client folder, which contains the following:

package client;
import com.allen_sauer.gwt.log.client.*;
import com.google.gwt.core.client.*;
/**
 * Module1
 *
 * @author Nazmul Idris
 * @version 1.0
 * @since Jan 11, 2008, 5:45:29 PM
 */
public class Module1 implements EntryPoint {
public void onModuleLoad() {
  Log.setCurrentLogLevel(Log.getLowestLogLevel());
  Log.setUncaughtExceptionHandler();
  Log.info("msg");
}
}

As you can see from this code listing, the Java class is in the “client” package, which is under the “src” ROOT folder. This means to find “client.Module1” class, you have to look for a Module1.java file in the “./src/client” folder. If you wanted to share this module with other modules, you would have to make a Module1.jar file that contains everything underneath the “src” folder, but does not include the “src” folder itself! Then you would have to add an inherits element in the XML module descriptor of the module that is going to use it. That inherits tag would look like: <inherits name=”Module1″/>.

Why so simple? Well, since we didn’t have any nested folders like “com/developerlife/reusable/module/one“, we just reference “Module1” without any prefix. Here’s the Module1.jar file for you to take a look at. When you open it up, note the existence of the .class files alongside the Java source files.

Why does the Java source have to be included with the .class files? The GWT compiler will need it when it’s generating JavaScript. For server-side code and GWT services that you include, this is not a requirement, since no JS needs to be generated for such things. Just keep this in mind – anything that will require GWT to generate JS for, you must include the Java source files for, along with the .class files. The .class files are for your IDE to be able to work with the JAR file and enable autocomplete, and all the other great things IDEs do for you. The Java files are for GWT’s Java -> JS compiler.

Multiple imports and other JAR files

If you have multiple GWT modules to import in your GWT app, then you can just add multiple inherits tags in the XML module descriptor for your app. If you have a situation where your app imports a module that imports another module, then there’s no need to have 2 inherits tags in your app’s XML module descriptor, just one (for the immediate dependency). However, be sure to add the JAR files for BOTH modules in your IDE’s project libraries. An example is if you are writing an app that uses the Module1 JAR file. Then you will need to add an inherits tag in your app’s XML module descriptor, but you don’t have to add an inherits tag for the GWT Log module. However, your IDE must have access to both the Module1.jar GWT Log JAR file at compile time.

In case your module has dependencies itself, like if you have services that might need JDOM or ROME, then be sure to add those JAR files as dependencies in your project in your favorite IDE. Just remember that all dependencies must be resolved when the GWT compiler goes to generate the JS for your project. And the inherits tag is used to let the GWT compiler know which Java source files to turn into JS.

Notes on the IDEA GWT plugin and modules

  • In IDEA, you can create multiple IDEA modules that depend on each other. Inside of these IDEA modules, you can create GWT modules. Then you can assign one of these modules as a dependency for another module (in IDEA). If you have GWT facets in each of these modules, then when you deploy your GWT facet, the app will work correctly. IDEA runs the GWT compiler correctly on the source packages that are identified in the GWT XML module descriptors for each of your GWT facets/modules. They all get compiled into JS for you and are available in a WAR file if you deploy to a servlet container. When you look in the WAR file, you will find that there only the HTML host page and XML module descriptor for the current GWT module is provided. All the JS from the imported modules are present, and the CSS files from these imports are included in the WAR file, but not the HTML Host pages.
  • This is not specific to IDEA, but when you import multiple modules, all the entry points (if they exist) are executed in the order in which the include statements appear in the XML module descriptor of the project.
  • If your dependent GWT modules have services, then the web.xml file for these servlets will not be rolled up automatically by IDEA when you deploy the main project. The client side JS stuff will come along with no issues, but not the web.xml. The classes for web.xml are imported correctly and show up in the WEB-INF folder of the WAR file, but, alas the web.xml file is not updated to include the dependent module’s servlet mappings.

Downloads

You can download the IDEA project files used in this tutorial here.

You can download the Module1.jar file generated from this tutorial here.