Maven

Eine Snippet-Sammlung für Maven 2.

Links

Installation

Ubuntu:

sudo apt-get install maven2

Mac OS X:

Eclipse-Integration:

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:

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:

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:

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:

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>