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 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.
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:
- The JAR file must have source code and compiled classes placed in the same folders as the source code
- 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.
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:
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…
Step 2 of 2 : Adding a dependency in your XML module descriptor
Here’s the line that’s added to the XML descriptor file as a result of this action:
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.
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.
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:
- Include the source code for your module along with the classes in the same folders.
- 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:
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:
In this simplified project structure, we have a single class Module1.java, in the client folder, which contains the following:
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.
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.
You can download the IDEA project files used in this tutorial here.
You can download the Module1.jar file generated from this tutorial here.