Building J2EE Projects with Mavenby Vincent Massol
Maven is a formidable tool for simplifying the construction of J2EE applications. If you're currently using an Ant build or some other build tool you'll be able to reduce your build script by several folds, thus saving maintenance time. But perhaps even more importantly, you'll get as a result a nicely-structured directory organization that follows building best practices. We'll assume you have general Maven knowledge and that you already know how to create and build a simple JAR project. For more general knowledge on Maven see the Maven website, Maven: A Developer's Notebook, and the Mavenbook.org website.
Note: You'll need to use Maven 1.1 beta 2 or greater to try out the build examples in this article. Do not try them with Maven 1.0.2, as the examples use new features available only in plugins released with Maven 1.1 beta 2 and above.
Generating J2EE Artifacts
In order to get you some real-life experience in building a J2EE application we'll be exploring how to build the Java Petstore and the xPetstore J2EE applications. The xPetstore is different in that it's using XDoclet to generate lots of J2EE files including Home, Local, and Remote interfaces, in addition to deployment descriptors. To make it easy to follow we've made all the source code available under an Apache License at www.mavenbook.org/viewcvs/mdn/code/j2ee/ (the sources can also be checked out from a Subversion repository at www.mavenbook.org/svn/mdn/code/j2ee.
During the course of this article you'll learn to generate J2EE artifacts (EJB JARs, WARs, EARs) with Maven.
Overall Directory Organization
When you're building with Maven you need to think in terms of artifacts (i.e. what files your build produces). A typical full-fledged J2EE application will produce EJB-JARs, possibly one or several WARs, and an EAR. For each artifact produced you'll need to create a Maven project in your source tree. Figure 1 shows a general directory structure for a build that produces several applications (EARs) containing JARs, WARs, and EJBs.
Figure 1. General directory structure for a J2EE Maven project
The Java Petstore and the xPetstore application currently have an Ant build and they're not organized in this manner. We've reorganized them for the purpose of this article into the directory structures shown in Figures 2 and 3.
Figure 2. Java Petstore directory structure for our Maven build showing what artifact each subproject produces
Figure 3. xPetstore directory structure for our Maven build showing what artifact each subproject produces
Building an EJB-JAR
Let's start by building the address EJB-JAR module from the Java Petstore. The recommended directory structure is to put the sources that make the runtime jar in
src/main (see figure 4). The java sources go in src/main/java and the resources, like deployment descriptors, go in src/main/resources. Java test sources go into src/test/java. As you can see in figure 4, there are no tests in the Java Petstore source code. We'll examine how to run unit tests later on when we'll build the xPetstore project, which has some tests.
Figure 4. A typical directory structure for an EJB-JAR project
Let's now examine the content of the project.xml file. It has all the usual definition found in any Maven project but the part specific to this EJB-JAR project are in two places: in the <build> section and in the <dependencies> one. In the build section, we need to specify the location of our sources:
<build> <defaultGoal>ejb:install</defaultGoal> <sourceDirectory> src/main/java </sourceDirectory> <unitTestSourceDirectory> src/test/java </unitTestSourceDirectory> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> <unitTest> <includes> <include>**/*Test.java</include> </includes> <resources> <resource> <directory> src/test/resources </directory> </resource> </resources> </unitTest> </build>
Notice also the use of the <defaultGoal> tag. This element is used to tell Maven what goal it should run if you just execute the "maven" command in this project root directory, without specifying any goal.
Note: In Maven 1.0.2 this was achieved by creating a custom maven.xml file and defining a default attribute in the top-level <project> tag. This has been deprecated in Maven 1.1.
This address module actually depends on another module that produces a JAR artifact named xmldocuments-1.4.jar. It also requires a J2EE JAR to be able to compile the EJBs. Thus you need to add the following two dependencies to the project.xml:
<dependencies> <dependency> <groupId>com.sun.j2ee.blueprints</groupId> <artifactId>xmldocuments</artifactId> <version>1.4</version> <properties> <ejb.manifest.classpath> true </ejb.manifest.classpath> </properties> </dependency> <dependency> <groupId>geronimo-spec</groupId> <artifactId>geronimo-spec-ejb</artifactId> <version>2.1-rc4</version> </dependency> </dependencies>
Tip: The J2EE JAR provided by Sun has a license that prevents it from being distributed on the main Maven remote repository on ibiblio. In addition, this J2EE JAR weighs several tens of megabytes. Luckily the Geronimo project provides a readily distributable J2EE JAR that also has the advantages of being lightweight and being available on ibiblio. Use it whenever you have a J2EE project to compile.