Maven
Eine Snippet-Sammlung für Maven 2.
Links
- Übersicht über Maven 2-Plugins
- Übersicht über Maven Properties
- Suchmaschine für öffentliche Maven-Artefakte
Installation
Ubuntu:
sudo apt-get install maven2
Mac OS X:
- Maven herunterladen: http://maven.apache.org/download.html
- Paket auspacken.
~/.bash_profile
öffnen und Umgebungsvariablen eintragen:export M2_HOME=/Users/otto/Tools/apache-maven-2.2.1 export M2=$M2_HOME/bin export JAVA_HOME=/Library/Java/Home/ export PATH=$PATH:$M2
Eclipse-Integration:
- Details siehe: http://m2eclipse.sonatype.org/installing-m2eclipse.html
- Im Eclipse-Menü: Help -> Install new software...
- Unter "Work with" angeben:
http://m2eclipse.sonatype.org/sites/m2e
- "Maven Integration for Eclipse" auswählen
- Dem Dialog folgen und installieren
Befehle
Version aller Module in einem Multi-Modul-Projekt ändern (alternativ ohne versions:commit
und mit -DgenerateBackupPoms=false
):
mvn versions:set versions:commit -DnewVersion=1.0-SNAPSHOT
Test-Phase auslassen:
mvn -Dmaven.test.skip=true install
Parent-POM ohne Kind-Module bauen (-N
für non-recursive):
mvn -N install
Effective-POM anzeigen:
mvn help:effective-pom
Dependency Tree anzeigen (Siehe auch: Beispiel):
mvn dependency:tree -Dverbose -Dincludes=commons-collections
Abhängigkeiten neu laden:
mvn -U install
Basics
Scopes
Siehe Guide über scopes
Phasen im Default-Life-Cycle
Quelle: http://www.maestrodev.com/node/219
Phase | Description |
---|---|
validate |
Validate the project is correct and all necessary information is available. |
initialize |
Initialize the build process. |
generate-sources |
Generate any source code for inclusion in compilation. |
process-sources |
Process the source code, for example to filter any values. |
generate-resources |
Generate resources for inclusion in the package. |
process-resources |
Copy and process the resources into the destination directory, ready for packaging. |
compile |
Compile the source code of the project. |
process-classes |
Post-process the generated files from compilation, for example to do byte code enhancement on Java classes. |
generate-test-sources |
Generate any test source code for inclusion in compilation. |
process-test-sources |
Process the test source code, for example to filter any values. |
generate-test-resources |
Create resources for testing. |
process-test-resources |
Copy and process the resources into the test destination directory. |
test-compile |
Compile the test source code into the test destination directory |
test |
Run tests using a suitable unit testing framework. These tests should not require the code be packaged or deployed. |
package |
Take the compiled code and package it in its distributable format, such as a JAR. |
pre-integration-test |
Perform actions required before integration tests are executed. This may involve things such as setting up the required environment. |
integration-test |
Process and deploy the package if necessary into an environment where integration tests can be run. |
post-integration-test |
Perform actions required after integration tests have been executed. This may including cleaning up the environment. |
verify |
Run any checks to verify the package is valid and meets quality criteria. |
install |
Install the package into the local repository, for use as a dependency in other projects locally. |
deploy |
Done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects. |
Parent-POM mit Multi-Modulen
Best practise:
- Definition von Versionen für mehrfach verwendete Abhängigkeiten
- Sollte nur im
dependencyManagement
definiert werden. Die Parent-POM sollte keine echtendependency
-Elemente vererben.
- Sollte nur im
- Mögliche Alternative: Dependency imports (ab Maven 2.0.9)
- Zentrale Definition von Distribution-Management
- Zentrale Definition gemeinsam genutzter Properties
Verzeichnisstruktur:
mainproject/
pom.xml (parent POM)
submodule-bla/
pom.xml (POM for submodule bla)
submodule-blubb/
pom.xml (POM for submodule blubb)
Parent pom.xml
:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>mygroup</groupId>
<artifactId>mainproject-parent</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>submodule-bla</module>
<module>submodule-blubb</module>
</modules>
<dependencyManagement>
<dependencies>
...
</dependencies>
</dependencyManagement>
<distributionManagement>
...
</distributionManagement>
</project>
Submodule pom.xml
:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>mygroup</groupId>
<artifactId>submodule-bla</artifactId>
<!-- version comes from parent POM -->
<parent>
<groupId>mygroup</groupId>
<artifactId>mainproject-parent</artifactId>
<version>0.1-SNAPSHOT</version>
</parent>
...
</project>
Plugin-Executions
Ein Plugin-Goal in einer bestimmten Phase ausführen:
<project>
...
<build>
<plugins>
<plugin>
<groupId>some.group</groupId>
<artifactId>maven-stuff-plugin</artifactId>
<executions>
<execution>
<id>devcon-war</id> <!-- Only when having more than one execution -->
<phase>compile</phase> <!-- Only when != the goal's default phase -->
<goals>
<goal>some-goal</goal>
</goals>
<configuration>
<!-- Config goes here (if needed) -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Profile
Details siehe: Introduction to Build Profiles
Definition von Profilen:
<project>
...
<profiles>
<profile>
<id>test</id>
<build></build> <!-- May be anything normally defined in "project" -->
</profile>
</profiles>
</project>
Bedingte Plugin-Ausführung
Mit Hilfe von Profilen kann man auch eine bedingte Plugin-Ausführung erreichen.
Beispiel: Wir wollen einige Maven-Projekte aufsetzen, welche jeweils ein ZIP-Artefakt erzeugen. Um ein ZIP-Artefakt zu erzeugen muss man das maven-zip-plugin konfigurieren. Damit das nicht in jedem dieser Maven-Projekte erneut gemacht werden muss (unnötige Redundanz), wollen wir die Konfiguration des maven-zip-plugin in eine gemeinsame Parent-POM auslagern. Das Problem dabei ist, dass das maven-zip-plugin nicht beim Beu der Parent-POM selbst ausgeführt werden sollen, sondern nur bei den POM, die davon erben.
FIXME Der Trick mit ${project.packaging}.xml
funktioniert nicht. Properties werden scheinbar nicht aufgelöst. Man muss statt dessen testen, ob eine bestimmte Datei (oder Verzeichnis) vorhanden ist.
Parent-pom.xml
mit bedingter Plugin-Ausführung:
<project>
<groupId>mygroup</groupId>
<artifactId>my-parent</artifactId>
<version>0.1</version>
<packaging>pom</packaging>
<profiles>
<profile>
<!-- Activate this profile only for child POMs, not for this parent POM -->
<activation>
<file>
<!-- "pom.xml" won't be missing, but "zip.xml" will -->
<missing>${project.packaging}.xml</missing>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jboss.maven.plugins</groupId>
<artifactId>maven-zip-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<sourceDirectory>${basedir}/target/some-dir</sourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Beispiel-pom.xml
, welche die obige Parent-POM verwendet:
<project>
<groupId>mygroup</groupId>
<artifactId>my-using-project</artifactId>
<version>0.1</version>
<packaging>zip</packaging>
<parent>
<groupId>mygroup</groupId>
<artifactId>my-parent</artifactId>
<version>0.1</version>
</parent>
</project>
Eigene Maven-Artefakte in einem eigenen Maven-Repo deployen
In der POM Deiner Bibliothek folgendes hinzufügen:
<project>
...
<distributionManagement>
<repository>
<id>my-maven-repoe</id>
<url>scp://myfileserver/path/to/maven-repo/</url>
</repository>
<snapshotRepository>
<!-- Verhindert, dass SNAPSHOT-Versionen im Remote-Repo landen -->
<id>snapshot-killer</id>
<url>file:/tmp/</url>
</snapshotRepository>
</distributionManagement>
</project>
Danach per mvn deploy
das Artefakt ins Remote-Repo deployen.
Dann im Projekt, das die Bibliothek verwendet, folgendes hinzufügen:
<project>
...
<dependencies>
...
<dependency>
<groupId>mygroup</groupId>
<artifactId>mylib</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>my-maven-repo</id>
<url>scp://myfileserver/path/to/maven-repo/</url>
</repository>
</repositories>
</project>
Jetzt das Projekt ganz normal bauen. Wenn nötig lädt Maven die Bibliothek aus dem Remote-Repo herunter (und speichert sie im lokalen Repo).
Statt scp
gehen auch andere Protokolle wie file
, http
oder auch ftp
.
Ant beim Build verwenden
pom.xml
erweitern:
<project>
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echoproperties/>
<zip destfile="${basedir}/target/classes/example.zip"
basedir="${basedir}/src/main/example/stuff" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Groovy beim Build verwenden
Details: http://docs.codehaus.org/display/GMAVEN/Executing+Groovy+Code
Variablen:
project
: The MavenProject, with auto-resolving properties.session
: The executing MavenSessionsettings
: The executing Settingslog
: A SLF4J Logger instanceant
: An AntBuilder instance for easy access to Ant tasksfail()
: A helper to throw MojoExecutionException
pom.xml
erweitern:
<project>
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
if (project.packaging != 'pom') {
log.info('Copying some stuff...')
def dir = new File(project.basedir, 'target/classes/META-INF')
// You can even use ant tasks
ant.mkdir(dir: dir)
ant.copy(todir: dir) {
fileset(dir: project.basedir) {
include(name: 'LICENSE.txt')
include(name: 'NOTICE.txt')
}
}
// You can fail
fail("Some error")
fail("Some error", exc)
fail(exc)
// Attach extra artifacts
def helper = new org.apache.maven.project.DefaultMavenProjectHelper()
helper.attachArtifact(project, extraFile, "extra")
}
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Den Groovy-Code kann man auch in eine andere Datei auslagern:
<project>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>${project.basedir}/src/build/groovy/MyScript.groovy</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Groovy Jars
Details siehe: [http://docs.codehaus.org/display/GMAVEN/Building+Groovy+Projects]()
Verzeichnisstruktur:
pom.xml
src/
main/
groovy/
MyClass.groovy
test/
groovy/
MyTest.groovy
pom.xml
:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>mygroup</groupId>
<artifactId>my-artifact</artifactId>
<version>0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy.maven.runtime</groupId>
<artifactId>gmaven-runtime-1.5</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Jar mit Dependencies
Für Stand-alone-Applikationen bietet es sich an, ein Jar zu packen, das neben dem eigenen Code auch alle Abhängigkeiten enthält, so dass das Jar direkt ausführbar ist (von den Amis auch "uber jar" genannt).
pom.xml
erweitern:
<project>
<build>
<plugins>
...
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>my.package.MyMain</mainClass>
</transformer>
<!-- Wenn man Spring verwendet, sind noch die
folgenden Einträge wichtig -->
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>with-deps</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Siehe auch:
- http://stackoverflow.com/questions/8523997/unable-to-locate-spring-namespacehandler-for-xml-schema-namespace-http-www-sp/8574629#8574629
- http://stackoverflow.com/questions/8609322/need-understanding-of-spring-handlers-and-spring-schemas
Jetty einbinden
Details see: [http://jetty.codehaus.org/jetty/maven-plugin/run-mojo.html]()
pom.xml
erweitern:
<project>
<build>
<plugins>
...
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.15</version>
<configuration>
<!-- <contextPath>/</contextPath> -->
<scanIntervalSeconds>2</scanIntervalSeconds>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>9090</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
</configuration>
</plugin>
</plugins>
</build>
</project>
Jetty starten:
mvn jetty:run
Client-Build in war einbinden
pom.xml
erweitern:
<project>
...
<packaging>war</packaging>
<build>
<plugins>
<!-- Execute client-build before building the package -->
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<workingDirectory>${basedir}/src/main/client/</workingDirectory>
<executable>npm</executable>
<arguments>
<argument>run</argument>
<argument>production</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<!-- Enable variable replacement in web.xml -->
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/web.xml</include>
</includes>
</resource>
<resource>
<!-- Include the client assets in the war file -->
<directory>src/main/client/assets</directory>
<targetPath>assets-${project.version}</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
Zip-Packaging
Doku gibt es irgendwie nicht. Parameter muss man sich aus dem Quellcode rauslesen.
In Version 1.0 gibt es folgende Parameter:
outputDirectory
: Directory containing the generated zipfile. Default:${project.build.directory}
sourceDirectory
: Directory containing the content to be zipped. Default:${project.build.outputDirectory}
finalName
: Basename of the generated zipfile. Default:${project.build.finalName}
forceCreation
: Whether creating the archive should be forced. Default:false
classifier
: Classifier to add to the artifact generated. If given, the artifact will be an attachment instead. Default: nullincludeSourceDirectory
: Whether the source directory itself should be included in the archive. Default:false
Excludes und Includes werden in Version 1.0 leider nicht unterstützt.
pom.xml
für Haupt-Artefakt als Zip:
<project>
...
<packaging>zip</packaging>
...
<build>
<plugins>
<plugin>
<groupId>org.jboss.maven.plugins</groupId>
<artifactId>maven-zip-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<!-- this is the default -->
<sourceDirectory>${basedir}/target/classes</sourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
pom.xml
für Zusatz-Artefakt als Zip:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.jboss.maven.plugins</groupId>
<artifactId>maven-zip-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<configuration>
<sourceDirectory>${basedir}/target/some/dir</sourceDirectory>
<classifier>extra-stuff</classifier>
</configuration>
<goals>
<goal>zip</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
JavaScript komprimieren
JavaScript komprimieren:
<project>
...
<dependencies>
<dependency>
<groupId>com.yahoo.platform.yui</groupId>
<artifactId>yuicompressor</artifactId>
<version>2.3.6</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>compile</phase>
<configuration>
<tasks>
<java jar="${maven.dependency.com.yahoo.platform.yui.yuicompressor.jar.path}"
fork="true" failonerror="true">
<arg value="${basedir}/.../myscript.js" />
<arg value="-o" />
<arg value="${basedir}/.../myscript.min.js" />
<arg value="--line-break" />
<arg value="100" />
</java>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
JavaScript-Tools (JSLint, JSDoc)
Details siehe: http://dev.abiss.gr/mvn-jstools/usage.html
<project>
...
<reporting>
<plugins>
<plugin>
<groupId>gr.abiss.mvn.plugins</groupId>
<artifactId>maven-jstools-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<!-- the default is src/main/js -->
<jsDir>${project.build.directory}/site/sarissa</jsDir>
<!-- this is actually the default -->
<includes>**/*.js</includes>
<!-- maybe you need to exclude compressed JS files -->
<excludes>**/*-compressed.js</excludes>
<!-- this is actually the default -->
<caseSensitive>true</caseSensitive>
</configuration>
<reportSets>
<reportSet>
<reports>
<!-- include the desired reports -->
<report>jslint</report>
<report>jsdoc</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
</project>
CSS komprimieren
<project>
...
<dependencies>
<dependency>
<groupId>com.yahoo.platform.yui</groupId>
<artifactId>yuicompressor</artifactId>
<version>2.3.6</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>compile</phase>
<configuration>
<tasks>
<concat destfile="${basedir}/target/combined.css">
<fileset file="${basedir}/.../reset.css" />
<fileset file="${basedir}/.../main.css" />
<fileset file="${basedir}/.../footer.css" />
</concat>
<java jar="${maven.dependency.com.yahoo.platform.yui.yuicompressor.jar.path}"
fork="true" failonerror="true">
<arg value="--type" />
<arg value="css" />
<arg value="${basedir}/target/combined.css" />
<arg value="-o" />
<arg value="${basedir}/.../generated/style.css" />
</java>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>