Maven

Basic setup of Maven

  1. Download and install Maven+JDK as described here.
  2. Tune system variables. You need to create JAVA_HOME and M2_HOME variables and append the path to maven's bin directory to your path, as shown on below screenshot:
  3. Maven needs the initial configuration to setup HTTP proxy (if you have it in your office). The following configuration file1) should be placed to C:\Documents and Settings\<yourID>\.m2 directory:

    settings.xml

    <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                          http://maven.apache.org/xsd/settings-1.0.0.xsd">
     
        <proxies>
            <proxy>
                <id>mylocalproxy</id>
                <active>true</active>
                <protocol>http</protocol>
                <host>proxy</host>
                <port>8080</port>
                <!-- <nonProxyHosts>*.google.com|ibiblio.org</nonProxyHosts> -->
            </proxy>
        </proxies>
    </settings>

    Maven does not support the configuration of both HTTP and HTTPS proxy (see MNG-2305).

  4. You need to deploy all libraries, which are missed in public Maven repositories:
    call mvn install:install-file -Dversion=0.1-SNAPSHOT -Dpackaging=jar -DgroupId=org.company.package -DartifactId=library-name -Dfile=library.jar
  5. Checkout the projects needed, better using Eclipse .psf file.
  6. Run the following commands:
    • To build the complete project and create a packaged ZIP file with editor:
      mvn install package
      As the result the following package is build, which is a packaged application: project_folder\target\project.zip
    • To generate Eclipse classpaths from POMs run:
      mvn eclipse:eclipse
    • For the quick install (no tests and no updates from remote repositories) run:
      mvn -Dmaven.test.skip=true -o install

Unfortunately, it is hardly possible to make an assembly in nn_build project (see 1, 2, 3). So the assembly is done in a project, which contains the main class. This allows also the assembly to be bound to “package” goal.

Developing C++ projects with maven

Questions answered

Where can I get more information about maven?

Where I can get more detailed explanation about POM?

See here.

What is the build phases sequence (lifecycle)?

See here.

What is project's version number?

What is maven “super POM”?

All POMs extend the Super POM unless explicitly set. It defines the central repository location, defines the “release-profile”, and since maven v2.0.9 also freezes the versions for core plugins. See here the complete definition, which you may also extract from maven distribution (e.g. lib\maven-x.x.x-uber.jar/org\apache\maven\project\pom-4.0.0.xml).

How to print the “effective POM”?

Effective POM is a combination (merge) of all parent POMs with a current. You can learn it from the output of mvn help:effective-pom.

What is the sequence about how effective POM is formed?

From Maven Model Builder:
  • profile activation
  • profile injection
  • parent resolution until super-pom
  • model variables (${…}) interpolation

What are Maven alternatives?

How to print the help for plugin configuration options?

Use mvn help:describe -DgroupId=org.apache.maven.plugins -DartifactId=maven-dependency-plugin -Dfull=true.

How to integrate Maven into Java application?

From Calling Maven goals from Java and Can I use Maven repository manager outside of Maven?:
  • Use Maven Embedder API if you want to call something like mvn clean package
  • Use Aether if you want to benefit from Maven dependency resolution mechanizm.

How to use Ant plugins with maven-antrun-plugin?

The given example shows how to export functions from ant-contrib library (on example of <propertyregex>):
<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
    <dependencies>
        <dependency>
            <groupId>ant-contrib</groupId>
            <artifactId>ant-contrib</artifactId>
            <version>1.0b3</version>
            <exclusions>
                <exclusion>
                    <groupId>ant</groupId>
                    <artifactId>ant</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <executions>
        <execution>
            <phase>process-resources</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <tasks>
                    <taskdef resource="net/sf/antcontrib/antlib.xml" classpathref="maven.plugin.classpath" />
                    <propertyregex property="another.version" input="${project.version}" regexp="^(\d+)\.(\d+)\.(\d+)" select="\1-\2-\3" />
 
                    <echo message="Got ${another.version} ..." />
                </tasks>
            </configuration>
        </execution>
    </executions>
</plugin>

Running Maven

How to define Java heap space for maven?

Use MAVEN_OPTS=-Xmx512m. To increase the memory for test cycle in case when Unit test execution is run in a forked JVM, use <configuration><argLine>-Xmx756m</argLine></configuration> option for maven-surefire-plugin.

How to hide the progress information (KB downloaded/uploaded) from Maven output e.g. for maven-deploy-plugin?

Use -B (batch) Maven option key.

How to separate unit and integration tests?

The idea is to bind maven-surefire-plugin to two phases (test and integration-test) with different configuration settings.

Also check Combining profiles in Maven to skip multiple categories of unit tests concerning how to fine-tune which tests to run.

Why my Unit tests are run twice?

You have Cobertura plugin enabled. From Running junits and cobertura with maven: Cobertura runs Unit tests both for original and instrumented code to make sure that instrumentation has not introduced bugs.

How to disable unit test for a particular project?

There is no handy options for that (similar to -Dmaven.test.skip=true) so one need to define the following profile:

pom.xml

<profiles>
    <profile>
        <id>disable-unit-tests</id>
 
        <activation>
            <property>
                <name>maven.test.skip.myproject</name>
                <value>true</value>
            </property>
        </activation>
 
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <configuration>
                            <skipTests>true</skipTests>
                        </configuration>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    </profile>
</profiles>

and then say mvn -Dmaven.test.skip.myproject=true install

Unfortunately it is not possible to generalize this profile and put to parent POM, see Disable unit tests in a submodule using system property.

How to configure Maven to use custom settings-security.xml?

From MNG-4853: Use -Dsettings.security=path/to/security-settings.xml.

How to exclude given repository from being mirrored?

From Advanced Mirror Specification:

For example, to bypass repository vaadin-addons use the following configuration:

<mirrors>
    <mirror>
        <url>http://repository.internal/nexus/content/groups/development</url>
        <mirrorOf>*,!vaadin-addons</mirrorOf>
    </mirror>
</mirrors>
<profiles>
    <profile>
        <id>extra-repositories</id>
        <repositories>
            <repository>
                <id>vaadin-addons</id>
                <url>http://maven.vaadin.com/vaadin-addons</url>
            </repository>
        </repositories>
    </profile>
</profiles>
<activeProfiles>
    <activeProfile>extra-repositories</activeProfile>
</activeProfiles>

How to configure Maven to check for -SNAPSHOT versions less frequent?

Indeed for big projects checking for -SNAPSHOT versions each time the dependency is resolved slows down the project build. The way out is to override the default <updatePolicy>daily</updatePolicy> in your settings.xml and set it for 10 days (14400 minutes):

settings.xml

<repositories>
    <repository>
        <id>central</id>
        <url>http://central</url>
        <releases>
            <enabled>true</enabled>
            <updatePolicy>daily</updatePolicy>
        </releases>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>interval:14400</updatePolicy>
        </snapshots>
    </repository>
</repositories>

How to speedup maven build?

From Ускоряем процесс сборки с maven:
  • Use -T option to run build in parallel threads:
    • alias mvnn='mvn -T4' – always use 4 threads
    • alias mvnn='mvn -T1.0C' – use number of CPUs multiplied by 1.0 (with two CPU cores the number of threads will be 2).
  • Use mvnsh – a background process to keep maven always loaded into memory
  • Use -o switch not to update dependencies / or check How to configure Maven to check for ''-SNAPSHOT'' versions less frequent?

From Takari: Maven на стероидах:

  • Download takari-local-repository-0.11.2.jar and takari-smart-builder-0.6.1.jar (check for later version) and put them to maven/lib/ext/. In combination with above one can enable smart build using the following alias:
    alias mvnn='mvn -T1.0C --builder smart'
  • Extra optional setting: export MAVEN_OPTS="-Xmx1200m -XX:+TieredCompilation -XX:TieredStopAtLevel=1"

How to print system properties?

pom.xml

<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <target>
                    <property environment="env" />
                    <echoproperties />
                </target>
            </configuration>
        </execution>
    </executions>
</plugin>

How to pass system properties to maven test task?

  • The latest v2.6 of the plugin allows to pass the options via command-line as -Dname=value (fixes SUREFIRE-121).
  • From v2.5 you can use <systemPropertyVariables> configuration option of surefire plugin (see here):

    pom.xml

    <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
            <systemPropertyVariables>
                <http.proxyHost>proxy</http.proxyHost>
                <http.proxyPort>8080</http.proxyPort>
            </systemPropertyVariables>
        </configuration>
    </plugin>
  • In v2.4.3 of the plugin the <systemPropertyVariables> behaviour is broken. Also the parent JVM variables are not copied to forked JVM (see SUREFIRE-491). The only working configuration is:

    pom.xml

    <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
            <argLine>-ea -Xmx756m -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080</argLine>
        </configuration>
    </plugin>

How to configure several source directories for maven project?

This can be achieved using build-helper-maven-plugin like below:

pom.xml

<project>
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.mycompany</groupId>
    <artifactId>project</artifactId>
    <packaging>jar</packaging>
    <version>1.1</version>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>${basedir}/import</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

How to strip one folder from path during resource copy?

This can be achieved by using <cutdirsmapper dirs="1" /> (see also <flattenmapper /> which removes all folders).

pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <target>
                    <move todir="${project.build.directory}/dest" verbose="true">
                        <fileset dir="${project.build.directory}/source">
                            <include name="**/*.txt" />
                        </fileset>
                        <cutdirsmapper dirs="1" />
                    </move>
                </target>
            </configuration>
        </execution>
    </executions>
</plugin>

How to generate site using maven, ignoring test results?

Use mvn -Dmaven.test.error.ignore=true install site

How to set plugin's version on the command line?

Example: mvn org.apache.maven.plugins:maven-dependency-plugin:2.9:tree > tree

Cannot use custom protocol handler when executing the program

Both maven-surefire-plugin and exec-maven-plugin are impacted by this issue. java.net.URL cannot resolve protocol handler for isolated classloader which is set up by Maven. Workaround is to use custom URLStreamHandlerFactory which can locate the handler class (e.g. provided by runtime dependency):
static class HttpHandlerFactory implements URLStreamHandlerFactory {
    private final URLStreamHandler handler;
 
    public HttpHandlerFactory(URLStreamHandler handler) {
        this.handler = handler;
    }
 
    @Override
    public URLStreamHandler createURLStreamHandler(String protocol) {
        if (protocol.equals("http")) {
            return handler;
        }
 
        return null;
    }
}
 
public static void main(String[] args) throws Exception {
    try {
        Class<?> cl = Class.forName("org.mycompany.protocol.http.Handler");
        URL.setURLStreamHandlerFactory(new HttpHandlerFactory((URLStreamHandler) cl.newInstance()));
    }
    catch (ClassNotFoundException e) {
        // Specific handler is not in the classpath
    }
 
    ...
}

See also:

Profiles

Are maven profiles inherited? How to “import” profiles?

No, maven profiles are not inherited and not merged as dependencies for example. When activated, the profile is applied directly to the parent POM prior to being used for merging with the child. This leads to certain limitations, e.g. you cannot define the profile partially in parent POM and extend it in a child. Also if you need the profile my in module A to have impact on dependent module B you need to activate a profile during a multi-module build, but build only one module (mvn -Pmy -pl B, see here).

However it is possible to activate profiles in dependent artifact, e.g. as described in MNG-1388.

How to negate a property in pom.xml?

The profile basically negates the value of “failOnError” property:

pom.xml

<properties>
    <!-- By default unit tests fail the build: -->
    <failOnError>true</failOnError>
</properties>
 
<profiles>
    <profile>
        <id>failOnError</id>
        <activation>
            <property>
                <name>failOnError</name>
                <value>false</value>
            </property>
        </activation>
 
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <configuration>
                            <testFailureIgnore>true</testFailureIgnore>
                        </configuration>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    </profile>
</profiles>

How to override plugin configuration in profile?

Suppose that one has parent POM that defines the following profile:
<profile>
    <id>doit</id>
 
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>step1</id>
                        <phase>install</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <echo message="Step 1" />
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

And now one wants to extend this profile in module POM in a way that more steps are executed in addition to above. One need to create profile with same profile ID, but choose different execution ID:

<profile>
    <id>doit</id>
 
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>step2</id>
                        <phase>install</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <echo message="Step 2" />
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

Now if mvn -Pdoit is executed, you will see Step1 Step2 printed to console.

For more advanced merging facilities check Maven How-To: Merging Plugin Configuration in Complex Projects (combine.children="append" to append children, combine.self="override" to ignore children for the parent being overridden). Note that you can't merge e.g. build.resources the same way: use build-helper-maven-plugin to achieve that:

pom.xml

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
 
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>add-resource</goal>
            </goals>
            <configuration>
                <resources>
                    <resource>
                        <directory>src/main/extra</directory>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

Dependency management

What is the consequence of leaving out Maven plugin version?

From 8711914: When version is omitted, maven tries to find and uses the most recent version. The real problem here is that you never know which version of the plugin was used and will the plugin behave the same in the future. This makes builds unreproducible/unrepeatable.

How to exclude dependencies from dependent tree?

To view the dependency tree use mvn dependency:tree. And see here.

How to import dependency management rules from other POM?

As multiple inheritance is not supported by Maven POM hierarchy, it is still possible to inherit dependency management rules from other POMs. You should include the reference to the interested POM into dependencyManagement with import scope (example was taken from here):

pom.xml

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.test</groupId>
            <artifactId>common-libs</artifactId>
            <version>1.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Note that version ranges are not supported if dependencies are inherited either from parent POM or the way above (see MNG-2199).

Is it possible to define the “group” dependency?

There is no way to do it directly as mentioned in MNG-2059. But you can define them in POM artifact and put a dependency on it.

How to display the dependency tree for plugins?

As from here just follow mvn -X output.

Artifact management

How enable the deployment of JAR artifact for WAR project?

How can I make maven to create and install two artifacts with different packaging? For example, how to deploy JAR artifact next to WAR artifact when POM packaging is war?

If you have a war packaging in your pom.xml and you want to create a JAR file together with WAR file, try this command:

mvn -o jar:jar install:install-file -Dfile=${project.build.directory}\${project.artifactId}-${project.version}.jar -Dpackaging=jar -DpomFile=pom.xml

In latest WAR plugin versions it is possible to specify the attachClasses option to achieve the same effect: <configuration><attachClasses>true</attachClasses></configuration>. Also using profiles like in Building For Different Environments with Maven 2 may help.

What is the location of resources in ''META-INF'' for WAR?

Depending on how this resource is going to be used, its location may vary:
  • If it will be read by web application container (like Tomcat META-INF/context.xml), then it should be placed to src/webapp/META-INF/context.xml.
  • If it will be used by web application itself (like AspectJ META-INF/aop.xml, or Hibernate META-INF/hibernate.xml, or any other via String#getResource()), then it should be placed to src/main/resources/META-INF/aop.xml.

How to share resources between maven projects? How to put JAR artifact to WAR as a resource (e.g. applet code)?

See here and here. The example below shows how to copy resources from supplier-project to consumer-project/target/addon folder:

pom.xml

<project>
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.mycompany</groupId>
    <artifactId>consumer-project</artifactId>
    <packaging>jar</packaging>
    <version>1.1</version>
 
    <dependencies>
        <dependency>
            <groupId>org.mycompany.common</groupId>
            <artifactId>supplier-project</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <!-- Copy shared resources: -->
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>unpack-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/addon</outputDirectory>
                            <includeGroupIds>org.mycompany.common</includeGroupIds>
                            <includeArtifacIds>supplier-project</includeArtifacIds>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

For the WAR file (e.g. when adding an applet) use the same technique:

pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>applet-artifact-id</artifactId>
                    </artifactItem>
                </artifactItems>
                <outputDirectory>${project.build.directory}/${project.build.finalName}/applet</outputDirectory>
                <stripVersion>true</stripVersion>
            </configuration>
        </execution>
    </executions>
</plugin>

How to share test code between projects?

For the test-common project add to your pom the following:

pom.xml

<project ...>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <executions>
                     <execution>
                         <goals>
                             <goal>test-jar</goal>
                         </goals>
                     </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

and then use the resulting jar artifact with tests classifier in test scope:

pom.xml

<project ...>
    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>text-common</artifactId>
            <version>0.1</version>
            <classifier>tests</classifier>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

How to create a ZIP archive with script to run the program?

In contrast to all-in-one executable JAR which can be created using maven-shade-plugin or maven-jar-plugin2), we need to create ZIP file which after unpacking will result run.cmd and all dependencies in lib folder. This gives more control over the JVM settings (e.g. heap size).

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    ...
    <properties>
        <main.class>package.Main</main.class>
        <classpath.prefix>lib</classpath.prefix>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>build-classpath</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build-classpath</goal>
                        </goals>
                        <configuration>
                            <prefix>${classpath.prefix}</prefix>
                            <outputProperty>classpath.all</outputProperty>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <id>assemble-zip-package</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <descriptors>
                                <descriptor>src/main/package/assembly.xml</descriptor>
                            </descriptors>
                            <appendAssemblyId>false</appendAssemblyId>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- This will suppress generation of JAR artifact: -->
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-jar</id>
                        <phase>dummy</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

src/main/package/assembly.xml

<?xml version="1.0" encoding="UTF-8"?>
<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
 
    <id>package</id>
 
    <formats>
        <format>zip</format>
    </formats>
 
    <baseDirectory />
 
    <dependencySets>
        <dependencySet>
            <outputDirectory>${classpath.prefix}</outputDirectory>
        </dependencySet>
    </dependencySets>
 
    <fileSets>
        <fileSet>
            <directory>${build.outputDirectory}</directory>
            <outputDirectory>${classpath.prefix}</outputDirectory>
        </fileSet>
    </fileSets>
 
    <files>
        <file>
            <source>src/main/package/run.cmd</source>
            <outputDirectory>/</outputDirectory>
            <filtered>true</filtered>
        </file>
    </files>
</assembly>

Note that adding the lib folder to classpath is necessary as that folder will contain e.g. main class as well as resources:

src/main/package/run.cmd

java -cp "${classpath.prefix}${path.separator}${classpath.all}" ${main.class} %1

How can I optimize all-in-one JAR?

I have assembled all-in-one jar, however there are classes which are never used by the application. How they could be automatically removed from the package to make it smaller?

From Minimizing jar dependency sizes:

Try maven-shade-plugin:

  • Use the following Maven configuration:

    pom.xml

    <properties>
        <jar.final.classifier>all</jar.final.classifier>
    </properties>
     
    <plugin>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.0</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <minimizeJar>true</minimizeJar>
                    <shadedArtifactAttached>true</shadedArtifactAttached>
                    <shadedClassifierName>${jar.final.classifier}</shadedClassifierName>
                    <filters>
                        <filter>
                            <artifact>commons-logging:commons-logging</artifact>
                            <includes>
                                <include>**</include>
                            </includes>
                        </filter>
                    </filters>
                </configuration>
            </execution>
        </executions>
    </plugin>

Try GenJar (generally, didn't worked well for me):

  • Download sources. Compile with Ant.
  • Remove org.apache.tools package from resulting build/lib/genjar.jar (otherwise there will be problems as maven-antrun-plugin is compiled against future versions of Ant).
  • Install to your local repository:
    mvn install:install-file -Dfile=genjar.jar -DgroupId=net.sf.genjar -DartifactId=genjar -Dversion=1.0 -Dpackaging=jar
  • Use the following Maven configuration:

    pom.xml

    <properties>
        <main.class>org.mycompany.myproject.Main</main.class>
        <jar.final.classifier>all</jar.final.classifier>
        <jar.final.name>${project.build.directory}/${project.artifactId}-${project.version}-${jar.final.classifier}.jar</jar.final.name>
    </properties>
     
    <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
            <execution>
                <id>minify-jar</id>
                <phase>package</phase>
                <goals>
                    <goal>run</goal>
                </goals>
                <configuration>
                    <target name="minify-jar">
                        <!--
                            Check maven-antrun-plugin manual concerning build-in classpath references:
                                http://maven.apache.org/plugins/maven-antrun-plugin/examples/classpaths.html
                        -->
                        <taskdef resource="genjar.properties" classpathref="maven.plugin.classpath" />
                        <genjar jarfile="${jar.final.name}">
                            <class name="${main.class}" />
     
                            <classpath>
                                <pathelement location="${project.build.directory}/${project.artifactId}-${project.version}.jar" />
                            </classpath>
     
                            <manifest>
                                <attribute name="Implementation-Title"        value="${project.name}" />
                                <attribute name="Implementation-Version"    value="${project.version}" />
                                <attribute name="Implementation-Vendor"        value="${project.organization.name}" />
                                <attribute name="Implementation-Vendor-Id"    value="${project.groupId}" />
                                <attribute name="Main-Class"            value="${main.class}" />
                            </manifest>
                        </genjar>
                        <attachartifact file="${jar.final.name}" classifier="${jar.final.classifier}"/>
                    </target>
                </configuration>
            </execution>
        </executions>
        <dependencies>
            <dependency>
                <groupId>net.sf.genjar</groupId>
                <artifactId>genjar</artifactId>
                <version>1.0</version>
            </dependency>
        </dependencies>
    </plugin>
  • The problem was that runtime classes cannot be specified for inclusion (see issue#1).

Try ProGuard:

  • Use the following Maven configuration:

    pom.xml

    <properties>
        <main.class>org.mycompany.myproject.Main</main.class>
        <jar.assembly.classifier>jar-with-dependencies</jar.assembly.classifier>
        <jar.final.classifier>all</jar.final.classifier>
    </properties>
     
    <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
            <execution>
                <id>package-jar-with-dependencies</id>
                <phase>package</phase>
                <goals>
                    <goal>single</goal>
                </goals>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>${jar.assembly.classifier}</descriptorRef>
                    </descriptorRefs>
                    <appendAssemblyId>true</appendAssemblyId>
                    <attach>false</attach>
                    <archive>
                        <manifest>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                    </archive>
                </configuration>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <groupId>com.github.wvengen</groupId>
        <artifactId>proguard-maven-plugin</artifactId>
        <version>2.0.6</version>
        <executions>
            <execution>
                <id>minify-jar</id>
                <phase>package</phase>
                <goals>
                    <goal>proguard</goal>
                </goals>
                <configuration>
                    <addMavenDescriptor>true</addMavenDescriptor>
                    <attachArtifactClassifier>${jar.final.classifier}</attachArtifactClassifier>
                    <attach>true</attach>
     
                    <includeDependency>false</includeDependency>
                    <obfuscate>false</obfuscate>
                    <injar>${project.artifactId}-${project.version}-${jar.assembly.classifier}.jar</injar>
                    <options>
                        <option>-keep class ${main.class} { public static void main(java.lang.String[]); }</option>
                        <option>-keep class org.apache.commons.logging.impl.LogFactoryImpl { *; }</option>
                        <option>-keep class org.apache.commons.logging.impl.Log4JLogger { *; }</option>
                        <option>-dontoptimize</option>
                        <option>-ignorewarnings</option>
                    </options>
                    <!-- Additional libs to search dependencies in: -->
                    <libs>
                        <lib>${java.home}/lib/rt.jar</lib>
                        <lib>${java.home}/lib/jsse.jar</lib>
                    </libs>
                </configuration>
            </execution>
        </executions>
        <dependencies>
            <dependency>
                <groupId>net.sf.proguard</groupId>
                <artifactId>proguard-base</artifactId>
                <version>4.8</version>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
    </plugin>
  • The problem java.lang.ClassFormatError: LVTT entry for ... does not match any LVT entry is solved by adding -optimizations !code/allocation/variable (from here).
  • The problem ClassFormatError: Invalid index N in LocalVariableTable in class file … is solved by using -dontoptimize (see Troubleshooting).

Finally, check other alternatives.

How to add SCM build number and build date to jar MANIFEST?

From Stamping Version Number and Build Time in a Properties File with Maven:

One need to enable filtering and use additional bridging variable, for example ${timestamp}:

pom.xml

<properties>
    <timestamp>${maven.build.timestamp}</timestamp>
 
    <maven.build.timestamp.format>yyyy-MM-dd</maven.build.timestamp.format>
</properties>
 
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

Another alternative is to use buildnumber-maven-plugin. To achieve this one need to activate buildnumber-maven-plugin twice (one per each goal):

pom.xml

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                        <manifestEntries>
                            <Scm-Url>${project.scm.developerConnection}</Scm-Url>
                            <Implementation-Build>${project.buildNumber}</Implementation-Build>
                            <Implementation-Build-Date>${project.buildDate}</Implementation-Build-Date>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                        <manifestEntries>
                            <Scm-Url>${project.scm.developerConnection}</Scm-Url>
                            <Implementation-Build>${project.buildNumber}</Implementation-Build>
                            <Implementation-Build-Date>${project.buildDate}</Implementation-Build-Date>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
 
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>buildnumber-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>create-buildnumber</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>create</goal>
                    </goals>
                    <configuration>
                        <buildNumberPropertyName>project.buildNumber</buildNumberPropertyName>
                    </configuration>
                </execution>
                <execution>
                    <id>create-timestamp</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>create-timestamp</goal>
                    </goals>
                    <configuration>
                        <timestampFormat>yyyy-MM-dd</timestampFormat>
                        <timestampPropertyName>project.buildDate</timestampPropertyName>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Artifacts cannot be fetched from repo1 with wget. Why?

This request fails:
$ wget -S http://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.0/commons-compress-1.0.jar.md5
--22:44:21--  http://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.0/commons-compress-1.0.jar.md5
           => `commons-compress-1.0.jar.md5'
Resolving repo1.maven.org... 38.97.124.18
Connecting to repo1.maven.org|38.97.124.18|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 403 Forbidden
  Server: nginx/0.7.62
  Date: Mon, 08 Mar 2010 21:44:26 GMT
  Content-Type: text/html
  Content-Length: 169
  Connection: keep-alive
22:44:21 ERROR 403: Forbidden.

but this succeeds:

22:44 ws1.grid.sara.nl:/home/dmitry
dmitry$ man wget

22:44 ws1.grid.sara.nl:/home/dmitry
dmitry$ wget -S --user-agent="Mozilla" http://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.0/commons-compress-1.0.jar.md5
--22:44:52--  http://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.0/commons-compress-1.0.jar.md5
           => `commons-compress-1.0.jar.md5'
Resolving repo1.maven.org... 38.97.124.18
Connecting to repo1.maven.org|38.97.124.18|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Server: nginx/0.7.62
  Date: Mon, 08 Mar 2010 21:44:57 GMT
  Content-Type: text/plain
  Content-Length: 75
  Last-Modified: Fri, 10 Jul 2009 20:11:52 GMT
  Connection: keep-alive
  Accept-Ranges: bytes
Length: 75 [text/plain]

100%[====================================================================================>] 75            --.--K/s

repo1 protects itself from being cloned with wget. See here and here for more information.

Artifact deployment

How can I run embedded Web container?

How to deploy to remote Tomcat?

We gonna use Tomcat Maven Plugin for deployment. First we need to add the tomcat manager username and password to maven configuration file:

settings.xml for maven

<settings>
    <servers>
        <server>
            <id>local-server-id</id>
            <username>tomcat</username>
            <password>Ab1nXmI</password>
        </server>
    </servers>
</settings>

This user should have “manager” rights in Tomcat server config:

/etc/tomcat6/tomcat-users.xml

<tomcat-users>
    ...
    <user username="tomcat" password="Ab1nXmI" roles="manager"/>
</tomcat-users>

Now we add the plugin to pom.xml for service (and for client, but changing the deployment context path):

pom.xml

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>tomcat-maven-plugin</artifactId>
    <configuration>
        <!-- Server credentials are stored in settings.xml: -->
        <server>local-server-id</server>
        <url>http://local-server.net:8080/manager</url>
        <!-- Deployment context: -->
        <path>/my-manager</path>
    </configuration>
</plugin>

and use mvn tomcat:deploy or later mvn tomcat:redeploy3) to do the job:

...
[INFO] ------------------------------------------------------------------------
[INFO] Building RDF Storage Web Service
[INFO]    task-segment: [tomcat:redeploy]
[INFO] ------------------------------------------------------------------------
...
[INFO] [tomcat:redeploy]
[INFO] Deploying war to http://local-server.net:8080/my-manager
[INFO] OK - Undeployed application at context path /my-manager
[INFO] OK - Deployed application at context path /my-manager
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

Your Tomcat instance should have manager application running, as plugin communicates to Tomcat through that interface.

How to deploy to remote JBoss?

Currently neither jboss-maven-plugin nor maven-jboss-deploy-plugin allow to deploy the maven artifacts to remote JBoss AS. Look at this page or this bug report for possible solutions. At the moment one of the reasonable solutions is scp the artifact to JBoss deploy directory (make sure you have org.jboss.deployment.scanner.URLDeploymentScanner bean enabled in conf/jboss-service.xml).

For example you can do it by binding to deploy phase so that artifact is deployed from CI server each time on successful build:

pom.xml

<build>
    <pluginManagement>
        <plugins>
            <!-- SCP the artifact to remote JBoss: -->
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.4</version>
                <executions>
                    <execution>
                        <phase>deploy</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <!-- You need to run "pscp.exe" once in advance for it to store the server's public key into registry [HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys] -->
                                <!-- Passing the command to CMD allows to delegate argument split & environment variables substitution to CMD. -->
                                <exec executable="cmd">
                                    <arg value= "/C" />
                                    <arg value= "pscp.exe -batch -i &quot;%USERPROFILE%/.ssh/id.ppk&quot; ${project.build.directory}/${project.artifactId}-${project.version}.ear ${jboss.server.host}:${jboss.server.deploydir}" />
                                </exec>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

or artifact is deployed when you run mvn antrun:run manually:

pom.xml

<build>
    <pluginManagement>
        <plugins>
            <!-- SCP the artifact to remote JBoss: -->
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.7</version>
                <configuration>
                    <target>
                        <!-- You need to run "scp.exe" once in advance for it to store the server's public key into %USERPROFILE%\.ssh\known_hosts -->
                        <!-- All arguments should be manually split. -->
                        <exec executable="scp.exe">
                            <arg value="-q" />
                            <!-- ${project.build.directory} substitution will not work here as scp will interpret "C:" as host -->
                            <arg value="target/${project.artifactId}-${project.version}.ear" />
                            <arg value="${jboss.server.host}:${jboss.server.deploydir}" />
                        </exec>
                    </target>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

Releasing the project

For those, who want to make a release from a command line, I would refer them to look at maven-release-plugin (see good reference here). Here we will setup the following infrastructure:

  • Using Nexus as Maven repository manager4)
  • Using Hudson as continuous integration system.

So, what you need to do:

  • Make sure, that you have installed Hudson Maven Release Plug-in in Hudson plugin manager.
  • You have to enable plugin for specific project in project settings. Basic and sufficient is release:prepare release:perform -Dresume=false
    • In case you don't access SVN repository anonymously, you may wish to specify username/password, e.g. … -Dusername=john -Dpassword=nnn
    • To pass user-defined versions from Hudson Maven Release Plugin use … -DreleaseVersion=${RELEASE_VERSION} -DdevelopmentVersion=${DEVELOPMENT_VERSION}

      Unfortunately this plugin works only with Maven2 Hudson projects, adding support for freestyle projects is in TODO list. For freestyle Hudson projects you may use Hudson Release Plugin. After this plugin is installed you need to configure “Before release step”, which is simply invoking Maven with goals release:prepare release:perform -Dusername=john -Dpassword=abc123:

      Hudson Release Plugin Settings

      If you need to pass version numbers from user, you need to wrap the call to maven into bash script as when releaseVersion and developmentVersion are passed in command-line but are empty they are not treated as not-defined.

  • maven-release-plugin will use project.scm.developerConnection (or project.scm.connection if the last one is not defined) to commit to source repository and project.distributionManagement for artifact deployment. So your pom.xml may look like this:

    pom.xml

    <project>
        <modelVersion>4.0.0</modelVersion>
     
        <groupId>org.mycompany.project</groupId>
        <artifactId>storage-service</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
     
        <name>My Service</name>
     
        <scm>
            <connection>scm:svn:https://localserver.com/svn/trunk/java/projects/myservice</connection>
        </scm>
     
        <distributionManagement>
            <repository>
                <id>nexus-server-id</id>
                <url>http://mavenserver.com/nexus/content/repositories/releases</url>
            </repository>
            <snapshotRepository>
                <id>nexus-server-id</id>
                <url>http://mavenserver.com/nexus/content/repositories/snapshots</url>
            </snapshotRepository>
        </distributionManagement>
        ...
    </project>
  • After that you can make a release from Hudson project menu

Sometimes the project build lifecycle generates logs, temporary files, which cause maven-release-plugin to complain with message Cannot prepare the release because you have local modifications. To exclude these files from being checked use <checkModificationExcludes> or pass via CLI, e.g. -DcheckModificationExcludeList=.maven (see How to disable maven release plugin check local modifications?).

Some helpful information for maven release plugin:

Concerning multi-project release:

Books:

Other:

How to update parent POM to latest version just before the project POM is committed by release:prepare?

You can do it using versions-maven-plugin in combination with preparationGoals setting:

pom.xml

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-release-plugin</artifactId>
                <version>2.5.3</version>
 
                <configuration>
                    <autoVersionSubmodules>true</autoVersionSubmodules>
                    <preparationGoals>versions:update-parent clean verify</preparationGoals>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>versions-maven-plugin</artifactId>
                <version>2.11.0</version>
                <configuration>
                    <generateBackupPoms>false</generateBackupPoms>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

mvn release:prepare fails with message svn: OPTIONS of Server certificate verification failed: issuer is not trusted

You need to run the svn list ... command manually under the specified user (possibly, changing the user via sudo -u host_user -H /bin/bash5) ), and then accept the server's certificate permanently6).

mvn release:prepare fails with message svn: '/tags/java/project' path not found

This happens because plugin does not create parent path entries when tagging. See release:prepare should create the SVN tags parent dir if it doesn't already exist for more details.

Maven fails when executing plugin XXX with message Plugin XXX does not exist or no valid version could be found

Try the following:
  • check proxy settings (e.g. does your proxy requires NTLM authentication? haven't you got into proxy protocol trap?)
  • perform mvn -U ... (see FAQ)
  • if the group is amoung default org.apache.maven.plugins or org.codehaus.mojo, then add to your settings.xml (see maven's documentation):

    settings.xml

    <settings ...>
        <pluginGroups>
            <pluginGroup>org.mortbay.jetty</pluginGroup>
        </pluginGroups>
    </settings>

How to configure all SCM-dependant plugins to use native Java implementation to access SVN repository?

pom.xml

<properties>
    <maven.scm.svnjava.version>2.0.5</maven.scm.svnjava.version>
    <svnkit.version>1.7.8</svnkit.version> <!-- This dependency is optional. To be sure that all plugins are bound to one SVNKit version. -->
</properties>
...
<plugin>
    <artifactId>maven-release-plugin</artifactId>
    <configuration>
        ...
    </configuration>
    <dependencies>
        <dependency>
            <groupId>com.google.code.maven-scm-provider-svnjava</groupId>
            <artifactId>maven-scm-provider-svnjava</artifactId>
            <version>${maven.scm.svnjava.version}</version>
        </dependency>
        <dependency>
            <groupId>org.tmatesoft.svnkit</groupId>
            <artifactId>svnkit</artifactId>
            <version>${svnkit.version}</version>
        </dependency>
    </dependencies>
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <executions>
        ...
    </executions>
    <dependencies>
        <dependency>
            <groupId>com.google.code.maven-scm-provider-svnjava</groupId>
            <artifactId>maven-scm-provider-svnjava</artifactId>
            <version>${maven.scm.svnjava.version}</version>
        </dependency>
        <dependency>
            <groupId>org.tmatesoft.svnkit</groupId>
            <artifactId>svnkit</artifactId>
            <version>${svnkit.version}</version>
        </dependency>
    </dependencies>
</plugin>

1) See here the complete list of options for settings.xml
2) This solution still needs dependencies to be bundled or copied somehow
3) See here the complete list of goals for this plugin
5) -H option is important, otherwise authentication information will be persisted in somebody's else ~/.subversion/ folder
6) See also here, here and here more discussions on authentication topics for maven-release-plugin
software/maven.txt · Last modified: 2015/03/20 17:17 by dmitry
 
 
Recent changes RSS feed Driven by DokuWiki