Where to Begin?
With Maven, the rule of thumb to use is to produce one artifact (JAR, WAR, etc.) per Maven project file. In the Spring example, that means you will need to have a Maven project (a POM) for each of the modules listed above.
To start, you will create a subdirectory called ‘m2’ to keep all the necessary Maven changes clearly separated from the current build system. Inside the ‘m2’ directory, you will need to create a directory for each of Spring’s modules.

Figure 8-2: A sample spring module directory
In the m2 directory, you will need to create a parent POM. You will use the parent POM to store the common configuration settings that apply to all of the modules. For example, each module will inherit the following values (settings) from the parent POM.
groupId:this setting indicates your area of influence, company, department, project, etc., and it should mimic standard package naming conventions to avoid duplicate values. For this example, you will usecom.exist.m2book.migrating, as it is our ‘unofficial’ example version of Spring; however, the Spring team would useorg.springframeworkartifactId:the setting specifies the name of this module (for example,spring-parent)version:this setting should always represent the next release version number appended with- SNAPSHOT– that is, the version you are developing in order to release. Recall from previous chapters that during the release process, Maven will convert to the definitive, non-snapshot version for a short period of time, in order to tag the release in your SCM.packaging:thejar,war, andearvalues should be obvious to you (apomvalue means that this project is used for metadata only)
The other values are not strictly required, and are primarily used for documentation purposes.
<groupId>com.exist.m2book.migrating</groupId>
<artifactId>spring-parent</artifactId>
<version>2.0-m1-SNAPSHOT</version>
<name>Spring parent</name>
<packaging>pom</packaging>
<description>Spring Framework</description>
<inceptionYear>2002</inceptionYear>
<url>http://www.springframework.org</url>
<organization>
<name>The Spring Framework Project</name>
</organization>
In this parent POM we can also add dependencies such as JUnit, which will be used for testing in every module, thereby eliminating the requirement to specify the dependency repeatedly across multiple modules.
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
As explained previously, in Spring, the main source and test directories are src and test, respectively. Let’s begin with these directories.
Using the following code snippet from Spring’s Ant build script, in the buildmain target, you can retrieve some of the configuration parameters for the compiler.
<javac destdir="${target.classes.dir}" source="1.3" target="1.3" debug="${debug}"
deprecation="false" optimize="false" failonerror="true">
<src path="${src.dir}"/>
<!-- Include Commons Attributes generated Java sources -->
<src path="${commons.attributes.tempdir.src}"/>
<classpath refid="all-libs"/>
</javac>
As you can see these include the source and target compatibility (1.3), deprecation and optimize (false), and failonerror (true) values. These last three properties use Maven’s default values, so there is no need for you to add the configuration parameters.
For the debug attribute, Spring’s Ant script uses a debug parameter, so to specify the required debug function in Maven, you will need to append -Dmaven.compiler.debug=false to the mvn command (by default this is set to true). For now, you don’t have to worry about the commons-attributes generated sources mentioned in the snippet, as you will learn about that later in this chapter. Recall from Chapter 2, that Maven automatically manages the classpath from its list of dependencies.
At this point, your build section will look like this:
<build>
<sourceDirectory>../../src</sourceDirectory>
<testSourceDirectory>../../test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.3</source>
<target>1.3</target>
</configuration>
</plugin>
</plugins>
</build>
The other configuration that will be shared is related to the JUnit tests. From the tests target in the Ant script:
<junit forkmode="perBatch" printsummary="yes" haltonfailure="yes" haltonerror="yes">
<jvmarg line="-Djava.awt.headless=true -XX:MaxPermSize=128m -Xmx128m"/>
<!-- Must go first to ensure any jndi.properties files etc take precedence -->
<classpath location="${target.testclasses.dir}"/>
<classpath location="${target.mockclasses.dir}"/>
<classpath location="${target.classes.dir}"/>
<!-- Need files loaded as resources -->
<classpath location="${test.dir}"/>
<classpath refid="all-libs"/>
<formatter type="plain" usefile="false"/>
<formatter type="xml"/>
<batchtest fork="yes" todir="${reports.dir}">
<fileset dir="${target.testclasses.dir}" includes="${test.includes}" excludes="${test.excludes}"/>
</batchtest>
</junit>
You can extract some configuration information from the previous code:
forkMode=”perBatch”matches with Maven’sforkModeparameter with a value of once, since the concept of a batch for testing does not exist.- You will not need any
printsummary,haltonfailureandhaltonerrorsettings, as Maven prints the test summary and stops for any test error or failure, by default. formatterelements are not required as Maven generates both plaintextandxmlreports.- The nested element
jvmargis mapped to the configuration parameterargLine - As previously noted,
classpathis automatically managed by Maven from the list of dependencies. - Maven sets the reports destination directory (
todir) totarget/surefire-reports, by default, and this doesn’t need to be changed. - You will need to specify the value of the properties
test.includesandtest.excludesfrom the nestedfileset; this value is read from theproject.propertiesfile loaded from the Ant script (refer to the code snippet below for details). - Maven uses the default value from the compiler plugin, so you will not need to locate the test classes directory (
dir).
# Wildcards to be matched by JUnit tests. # Convention is that our JUnit test classes have XXXTests-style names. test.includes=**/*Tests.class # # Wildcards to exclude among JUnit tests. # Second exclude needs to be used for JDK 1.3, due to Hibernate 3.1 # being compiled with target JDK 1.4. test.excludes=**/Abstract* #test.excludes=**/Abstract* org/springframework/orm/hibernate3/**
The includes and excludes referenced above, translate directly into the include/exclude elements of the POM’s plugin configuration.
hibernate3 tests. Note that it is possible to use another lower JVM to run tests if you wish – refer to the Surefire plugin reference documentation for more information.<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>once</forkMode>
<childDelegation>false</childDelegation>
<argLine>
-Djava.awt.headless=true -XX:MaxPermSize=128m -Xmx128m
</argLine>
<includes>
<include>**/*Tests.class</include>
</includes>
<excludes>
<exclude>**/Abstract*</exclude>
</excludes>
</configuration>
</plugin>
The childDelegation option is required to prevent conflicts when running under Java 5 between the XML parser provided by the JDK and the one included in the dependencies in some modules, mandatory when building in JDK 1.4. It makes tests run using the standard classloader delegation instead of the default Maven isolated classloader. When building only on Java 5 you could remove that option and the XML parser (Xerces) and APIs (xml-apis) dependencies.
Spring’s Ant build script also makes use of the commons-attributes compiler in its compileattr and compiletestattr targets, which are processed prior to the compilation. The commons-attributes compiler processes javadoc style annotations – it was created before Java supported annotations in the core language on JDK 1.5 – and generates sources from them that have to be compiled with the normal Java compiler.
From compileattr:
<!-- Compile to a temp directory: Commons Attributes will place Java Source here. -->
<attribute-compiler destdir="${commons.attributes.tempdir.src}">
<!--
Only the PathMap attribute in the org.springframework.web.servlet.handler.metadata
package currently needs to be shipped with an attribute, to support indexing.
-->
<fileset dir="${src.dir}" includes="**/metadata/*.java"/>
</attribute-compiler>
From compiletestattr:
<!-- Compile to a temp directory: Commons Attributes will place Java Source here. -->
<attribute-compiler destdir="${commons.attributes.tempdir.test}">
<fileset dir="${test.dir}" includes="org/springframework/aop/**/*.java"/>
<fileset dir="${test.dir}" includes="org/springframework/jmx/**/*.java"/>
</attribute-compiler>
In Maven, this same function can be accomplished by adding the commons-attributes plugin to the build section in the POM. Maven handles the source and destination directories automatically, so you will only need to add the inclusions for the main source and test source compilation.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>commons-attributes-maven-plugin</artifactId>
<executions>
<execution>
<configuration>
<includes>
<include>**/metadata/*.java</include>
</includes>
<testIncludes>
<include>org/springframework/aop/**/*.java</include>
<include>org/springframework/jmx/**/*.java</include>
</testIncludes>
</configuration>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
Later in this chapter you will need to modify these test configurations.