Maven2: love it or hate it?
●
Widespread build platform
– used by many open source and commercial projects
●
PROs
– automatic dependency management – good tool/IDE support
– automate the entire build life cycle – highly configurable
●
CONs
– highly configurable :-) – too much XML...
also...
lots of tutorials on simple cases, less documentation
Presentation goals
●
Maven can be your friend (and save lots of time!)
– if you
● learn it and understand it ● use it in the right way
●
My talk is about how to
maximize usefulness
and
efficiency
– while minimizing complexity & overhead
●
Sharing real world experience
– in designing and managing the build process for several large projects (>20 modules, >100 kLoc)
Part 1
Maven2 in 5 minutes
●
Maven is a modular automation system built
around 4 main elements
– input: project src/resources + POM – output: tested and packaged artifact
Maven
POM
repository
Plugins src
Maven in 5': the POM
●
The
Project Object Model
describes
– project coordinates – project type
● packaging (JAR, WAR, EAR, POM)
– source structure – build phases
● standard + custom
– dependencies – plugins
groupId: net.juggenova
artifactId: sample
Maven in 5': build lifecycle
●
Default life cycle
– validate – generate-sources – process-resources – compile – test-compile – test – package – integration-test – verify – install – deploy
– (some skipped for clarity)
●
Every goal implies all
the previous ones
– mvn compile
– actually executes
– validate
– generate-sources – process-resource – compile
●
Stand-alone goals
Maven in 5':
Dependency Management
●
Dependencies
– include all external libraries and files needed to completely assemble the output
● JARs, WARs, ZIPs, POMs
– are versioned
– can be transitive
● e.g. include just spring, get commons-logging automatically
●
Conflict resolution mechanism
– determines the version to be used when a jar is included multiple times
Maven in 5': repositories
●
Maven repository
– a structured store containing artifacts (JAR, WAR, ZIP...)
●
Maven uses at leas two
– local repository – on your PC
– central repository – http://repo1.maven.org/maven2/
●
Three types of repositories
– plain filesystem folder
– folder served by HTTP daemon
● populated via SCP/FTP/WEBDAV
– full “intelligent” repository (with indexing, search, cache, ...)
local repository ${user.home}/ .m2/repository
From code to repo (and back)
local repository
central repository
remote repository
install
deploy
package
Part 2
Getting the most out of Maven
●
Good old
sw engineering principles
still apply!
●
Don't repeat yourself
– the DRY principle
● reduce time, effort, maintenance ● minimize the impact of changes
●
Separate concerns
●
Automate as much as possible
●
Use the right tools (plugins & repositories)
●
Keep the build fast
things
always change in a project
How to minimize XML
●
Exploit the three main POM relationships
– inheritance, aggregation, dependency
●
This is a valid (and working) maven POM
– <project xmlns="..." xmlns:xsi="..."
xsi:schemaLocation="...">
● <modelVersion>4.0.0</modelVersion>
● <groupId>net.juggenova.sample</groupId> ● <artifactId>minimal</artifactId>
● <version>1.0</version>
– </project>
The Super POM
●
Implicitely, all POMs inherit from the
Super POM
– see http://maven.apache.org/pom.html
●
Defines
– standard directory structure – default plugins & repo
– where it is? inside mvn jars – how to check it?
– mvn help:effective-pom
●
Convention over Configuration
Super POM
your POM
The Super-POM
<repos itories ><repos itory>
<id>central</id>
<name>Maven Repos itory S witchboard</name> <url>http://repo1.maven.org/maven2</url>
</repos itory> </repos itories > <build>
<s ourceDirectory>s rc/main/java</s ourceDirectory>
<tes tS ourceDirectory>s rc/tes t/java</tes tS ourceDirectory> <outputDirectory>target/clas s es</outputDirectory>
...
<res ources >
<res ource>
<directory>s rc/main/res ources</directory> </res ource>
</res ources >
The Super-POM
<pluginManagement><plugins > <plugin>
<artifactId>maven-as s embly-plugin</artifactId> <vers ion>2.2-beta-1</vers ion>
</plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <vers ion>2.0.2</vers ion>
</plugin> ...
</plugins >
</pluginManagement> </build>
Parent POM: make you own
●
Create a POM defining your project conventions
and tools
– additional resource directories – default plugin configuration
● e.g. custom configuration for maven-compiler-plugin
– standard libraries
● e.g. default spring version with
– <dependencyManagement>
– repositories and deployment config
● e.g. your company repository with
net.juggenova.sample:parent
<build>
<s ourceDirectory>java/s rc</s ourceDirectory> ...
<pluginManagement> <plugins >
<plugin>
<groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration>
<s ource>1.6</s ource> <target>1.6</target> </configuration>
</plugin> <plugin>
<artifactId>maven-s urefire-plugin</artifactId> <configuration>...</configuration>
</plugin> </plugins >
Parent POM: use it
●
Reference the parent at the beginning of a POM
– <parent>
● <artifactId>parent</artifactId>
● <groupId>net.juggenova.sample</groupId> ● <version>1.1</version>
● <relativePath>../parent</relativePath>
– </parent>
●
Useful
– if you have many similar projects/components – to separate responsibilities between senior and
junior developers
Issues and suggestions
●
Main issue: children must reference parent
version explicitely
– strong dependency! (as usual with inheritance) – there is no <version>LATEST</version> or
<version>[1.0,)</version> for the parent
– if you change the parent, must update ALL children
●
So, avoid putting in the parent things that change
– your project modules versions
Suggestion
Separate things that change
from things that stay the same
Dependency POMs
●
Maven2 supports
transitive
dependencies
– controlled by a
consistent use of the <scope> tag
●
compile (default)
– your libs
●
test
– junit, spring-test
●
provided
– servlet-api ●runtime
– log4j ●system
tools.jar minimize them! your POM libraryIssues and suggestions
●
Good old encapsulation / minimize coupling
– minimize dependencies – minimize visibility
●
Can also define codeless POMs, which only
contain a group of other dependencies
– declare with<packaging>pom</packaging>
– used with
– <dependency>...
● <type>pom</type>
Dependency Management
●
Several libraries are often used in many modules
● commons-logging, spring, servlet-api,...
– avoid repeating their version everywhere in POMs
●
Apply DRY & separation of concerns
– which version to use in the parent/main POM
● <dependencyManagement> (artifact, group, version)
– whether to use it
● <dependency> (artifact, group only) </dependency> ● Tip: <dependencyManagement> is also effective in
Aggregation
●
Multimodule projects
– every goal is repeated on
all modules by the reactor plugin
– mvn clean – mvn compile
– modules can be children of master
● but not necessarily
<modules >
<module>client</module> <module>s erver</module> <module>tes t</module> </modules >
main POM module POM
Issues and suggestions
●
Issue: modules are referenced by folder name
– beware when checking out or renaming
●
Issue: IDE plugin support is not perfect
– m2eclipse requires manual refresh of dependencies after configuration changes
● also, different classpaths in eclipse and maven when opening a multimodule project as a single project
– netbeans only supports separate modules
●
Risk: pom proliferation (think of maintenance)
Suggestion
Common Reuse Principle
Package together what is used/reused togehter
Tip: create a “Master” POM
●
A “component list” POM
– does not have its own code or settings – just an index of all modules to be built – it is NOT the parent of the modules
●
Example: the main spring pom which triggers the
build of
– spring-core – spring-mvc – spring-test
Make it easy to create
new projects
●
Define an archetype
– a customizable template for creating a kind of projects (e.g. a web application)
● defines POMs, project structure
●
Simple setup with
– mvn archetype:create-from-project
– customize with resource filtering
● ${property} references in the archetype
●
Use
http://appfuse.org
Part 3
Automate the entire build
●
Build means much
more than compile
!
●
Avoid manual steps!
– copy, rename, deploy to a test server... – pass configuration information
●
Automatically process resources
– copy and filter configuration files, CSS, HTML, properties
●
Share resources across projects
– package them as jar/zip
– reuse them in a war project with jar/zip/war overlays
Assembly plugin
●
Creates zips/jars containing any kind of resource
– project sources – common files
● XSDs
● html/CSS ● templates
Preview and test webapps
with the Jetty plugin
●
Run a webapp directly from source folders
– mvn jetty:run
●
Advantages
– very fast
– resource changes are visible without restart – automatic redeploy after code changes
– http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin
●
Now a
mvn glassfish:rungoal is also available
– full JEE 5.0 support
Automate deployment
●
Deploy to an application server with cargo
– can even download, install and run a full Jboss instance for testing purposes
– http://cargo.codehaus.org/
●
Write custom ssh-based scripts using the
ssh/scp
ant tasks
within the maven-antrun-plugin
– transfer files to test serversIntegrate with the IDE
●
E.g. Eclipse plugin (m2eclipse)
Use a group repository
●
Why your own?
●
Within a Team
– deploy and share your project artifacts
● so that other developers do not have to rebuild them
– “mavenize” external jars which miss a POM
– centrally configure and control which repositories and artifacts are used
– cache dependencies
● available when internet connection breaks ● faster download times
Sonatype Nexus repository
●
Powerful web-based console
– and REST API
●
Lightweight
●
Easily upload artifacts via HTTP
●
Quickly search for jars
– with the included index
●
Download from
http://nexus.sonatype.org/
settings.xml: Mirror definition
● Team repository in addition to central
– <repository>
● <id> set </id>
● <url> http://server:8080/repository </url> – </repository>
● Team repository as a mirror of central (or others)
– <mirror>
● <id> central </id>
● <url> http://server:8080/repository</url> ● <mirrorOf> central </mirrorOf>
– </mirror>
● Team repository as the only one
– <mirror>
● <id> ... </id> <url> ... </url> ● <mirrorOf> * </mirrorOf>
Part 4
Build troubleshooting
●
Verify POM structure
– mvn validate
●
Verify actually used dependencies
– mvn dependency:tree
● -Dinclude=spring
●
Verify the full POM
– mvn help:effective-pom
– m2eclipse plugin
●
Moreover,
Debug/Log
●
Run mvn with
– -e (print Exception stacktraces) – -X (print debug info)
●
POM information can be accessed at runtime!
– META-INF/<group>/<artifact>/pom.properties
● groupId ● artifactId ● version
– META-INF/../pom.xml
● full POM info
Res ource[] res ources = applicationContext
.getRes ources ("clas s path*:META-INF/maven"+ "/**/pom.properties ");
for (Res ource r : res ources ) {
Properties p = new Properties (); p.load(r.getInputS tream());
artifact = p.getProperty("artifactId"); vers ion = p.getProperty("vers ion"); }
Add a timestamp to your builds
●
Automatically define a timestamp property
– use it in resources or test properties
– <plugin>
● <groupId>org.codehaus.mojo</groupId> ● <artifactId>
buildnumber-maven-plugin</artifactId>
● <executions> ... </executions> ● <configuration>
● <format>{0,date,yyyy-MM-dd HH:mm:ss}</format> ● <items>
● <item>timestamp</item> ● </items>
● </configuration>
</plugin>
Part 5
Keep the build fast
●
Ideally,
zero-time
build
– http://blog.carbonfive.com/2008/09/java/make-the-things-you-do-often-fast-and-easy
●
The more often a task is performed, the more its
optimization improves developer productivity
– save time for actual project work●
Run maven on the latest JDK
Eclipse compiler
●
Faster than JDK's javac
– also provides more warnings (unused variables, generics
misuse...)
– <plugin>
– <artifactId>maven-compiler-plugin</artifactId> – <configuration>
– <compilerId>eclipse</compilerId> – </configuration>
– <dependencies> – <dependency>
● <groupId>org.codehaus.plexus</groupId>
– <artifactId>plexus-compiler-eclipse</artifactId> – <version>1.5.2</version>
– </dependency> – </dependencies> – </plugin>
Unit test vs integration tests
●
Run unit tests often
– must not take half an hour! or else developers will just skip them
– -Dmaven.test.skip=true
●
Separate unit tests from integration tests
– unit tests in every project/module
● fast
● run at every build (within mvn install)
– integration and acceptance tests in dedicated module
Remove useless build elements
●
POM, plugin and dependency list keeps growing
●
Periodically
review the POM
– Remove unused dependencies
● copying them around means more slow disk accesses ● mvn dependency:analyze
– Remove unused plugins
Speed-up day-to-day tasks
●
Define a default goal
– <defaultGoal>compile</defaultGoal>
– then just run
– mvn
●
Use the right goal
– avoid a full mvn install if you just need a mvn test
●
Define shell aliases for common tasks
●
Use a CI server that reads and reuses mvn
configuration such as hudson
– https://hudson.dev.java.netIncrementally build large
multimodule projects
●
Reactor plugin
– http://maven.apache.org/plugins/maven-reactor-plugin/ – manages dependencies and build order
● resume a build from the last failed module
– mvn reactor:resume
● build a project and all its dependencies
– mvn reactor:make
● build all modules which have an SVN status of changed
References
●
Maven official site
– http://maven.apache.org
●
Best online book
– Maven 2 – The Definitive Guide – http://books.sonatype.com/maven-book
●
JavaWorld articles
– Introduction to maven2
● http://www.javaworld.com/javaworld/jw-12-2005/jw-1205-maven.html
– POM
Thanks for your attention!
● Learn more at
– http://www.carlobonamico.com/blog – http://juggenova.net
● presentations, demos, code samples
● Play with the samples
– http://juggenova.net/code-samples/
● Contact me at
● Related reading: Continuous Integration with Hudson