Skip to content

Instantly share code, notes, and snippets.

@javajack
Forked from ashrithr/A_maven.md
Created October 1, 2015 12:09
Show Gist options
  • Save javajack/b0f4240f3c91f028908c to your computer and use it in GitHub Desktop.
Save javajack/b0f4240f3c91f028908c to your computer and use it in GitHub Desktop.
build java projects using maven

Intro to Maven

###Create a project from Maven Template:

To start a new maven project, use the maven archetype plugin from the command line using the archetype:generate goal.

The following command will tell maven to create a java project from maven-archetype-quickstart template, if you ignore the archetypeArtifactId argument, then a list of the templates will be listed for you to choose.

mvn archetype:generate -DgroupId={project-packaging} -DartifactId={project-name} \
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

The following command will create a new java project named 'NumberGenerator'.

mvn archetype:generate -DgroupId=com.example -DartifactId=NumberGenerator \
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Maven Directory Layout:

NumberGenerator
   |-src
   |---main
   |-----java
   |-------com
   |---------example
   |-----------NumberGenerator.java
   |---test
   |-----java
   |-------com
   |---------example
   |-----------NumberGeneratorTest.java
   |-pom.xml

Working with Eclipse IDE:

To convert maven project to support Eclipse, issue the following command from project dir (this will generate all the project files required by eclipse):

mvn eclipse:eclipse

###Working with IntelliJ IDE:

mvn idea:idea

Maven Core Concepts

###Basic pom.xml:

<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.sonatype.mavenbook.simple</groupId>
    <artifactId>simple</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>simple</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

This pom.xml is the basic POM , the first few elements groupid, artifactid, packaging, version are known as maven coordinates which uniquely identify a project name, url are descriptive elements of the pom. The dependencies element defines a single, test-scoped dependency on a unit testing framework called junit.

###Maven Coordinates:

  • groupid - The group, company, team, organization, project, or other group. The convention for group identifiers is that they begin with the reverse domain name of the organization that creates the project
  • artifactId - A unique identifier under groupId that represents a single project.
  • version - A specific release of a project. Projects that have been released have a fixed version identifier that refers to a specific version of the project. Projects undergoing active development can use a special identifier that marks a version as a SNAPSHOT.
  • packaging - The type of project, defaulting to jar, describing the packaged output produced by a project. A project with packaging jar produces a JAR archive; a project with packaging war produces a web application.

###Maven Repositories In Maven, artifacts and plugins are retrieved from a remote repository when they are needed. A repository is a collection of project artifacts stored in a directory structure that closely matches a project’s Maven coordinates. The standard for a Maven repository is to store an artifact in the following directory relative to the root of the repository:

/<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>

Maven downloads artifacts and plugins from a remote repository to your local machine and stores these artifacts in your local Maven repository. Once Maven has downloaded an artifact from the remote Maven repository it never needs to download that artifact again as Maven will always look for the artifact in the local repository before looking elsewhere. On Unix systems, your local Maven repository is available in ~/.m2/repository.

###Maven Dependency Management In the previous mentioned simple pom example, Maven resolved the coordinates of the JUnit dependency —+junit:junit:3.8.1+— to a path in a Maven repository /junit/junit/3.8.1/junit-3.8.1.jar. The ability to locate an artifact in a repository based on Maven coordinates gives us the ability to define dependencies in a project’s POM.

Maven Plugins and Goals

To execute a single Maven plugin goal, we used the syntax mvn archetype:generate, where archetype is the identifier of a plugin and generate is the identifier of a goal. When Maven executes a plugin goal, it prints out the plugin identifier and goal identifier to standard output:

$ mvn archetype:generate -DgroupId=org.sonatype.mavenbook.simple \
-DartifactId=simple \
-Dpackage=org.sonatype.mavenbook
...
[INFO] [archetype:generate]
[INFO] artifact org.apache.maven.archetypes:maven-archetype-quickstart: \
checking for updates from central
...

A Maven Plugin is a collection of one or more goals. Examples of Maven plugins can be simple core plugins like the Jar plugin, which contains goals for creating JAR files, Compiler plugin, which contains goals for compiling source code and unit tests, or the Surefire plugin, which contains goals for executing unit tests and generating reports. Other, more specialized Maven plugins include plugins like the Hibernate3 plugin for integration with the popular persistence library Hibernate, the JRuby plugin which allows you to execute ruby as part of a Maven build or to write Maven plugins in Ruby. Maven also provides for the ability to define custom plugins. A custom plugin can be written in Java, or a plugin can be written in any number of languages including Ant, Groovy, beanshell, and, as previously mentioned, Ruby.

A goal is a specific task that may be executed as a standalone goal or along with other goals as part of a larger build. A goal is a “unit of work” in Maven. Examples of goals include the compile goal in the Compiler plugin, which compiles all of the source code for a project, or the test goal of the Surefire plugin, which can execute unit tests. Goals are configured via configuration properties that can be used to customize behavior.

###Maven Lifecycle Lifecycle phases are intentionally vague, defined solely as validation, testing, or deployment, and they may mean different things to different projects. For example, in a project that produces a Java archive, the package phase produces a JAR; in a project that produces a web application, the package phase produces a WAR.

Plugin goals can be attached to a lifecycle phase. As Maven moves through the phases in a lifecycle, it will execute the goals attached to each particular phase.

Bound goals are run when phases execute

  • resources:resources - plugin is bound to the process-resources phase. This goal copies all of the resources from src/main/resources and any other configured resource directories to the output directory.
  • compiler:compile - is bound to the compile phase. This goal compiles all of the source code from src/main/java or any other configured source directories to the output directory.
  • resources:testResources - plugin is bound to the process-test-resources phase. This goal copies all of the resources from src/test/resources and any other configured test resource directories to a test output directory.
  • compiler:testCompile - plugin is bound to the test-compile phase. This goal compiles test cases from src/test/java and any other configured test source directories to a test output directory.
  • surefire:test - bound to the test phase. This goal executes all of the tests and creates output files that capture detailed results. By default, this goal will terminate a build if there is a test failure.
  • jar:jar - to the package phase. This goal packages the output directory into a JAR file.

##Maven Example

###Defining a simple weather project

$ mvn archetype:generate -DgroupId=org.test.mavenbook.custom \
      -DartifactId=simple-weather \
      -Dpackage=org.test.mavenbook \
      -Dversion=1.0

[INFO] Preparing archetype:generate
...
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart \
(org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
...
16: internal -> maven-archetype-quickstart ()
...
Choose a number:  (...) 16: : 16
Confirm properties configuration:
groupId: org.test.mavenbook.custom
artifactId: simple-weather
version: 1.0
package: org.test.mavenbook.custom
Y: : Y
[INFO] Parameter: groupId, Value: org.test.mavenbook.custom
[INFO] Parameter: packageName, Value: org.test.mavenbook.custom
[INFO] Parameter: package, Value: org.test.mavenbook.custom
[INFO] Parameter: artifactId, Value: simple-weather
[INFO] Parameter: basedir, Value: /private/tmp
[INFO] Parameter: version, Value: 1.0
[INFO] BUILD SUCCESSFUL

###Initial pom generated by maven

<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.test.mavenbook.custom</groupId>
    <artifactId>simple-weather</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
    <name>simple-weather</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

###Provide CompilerConfiguration

<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.test.mavenbook.custom</groupId>
    <artifactId>simple-weather</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
    <name>simple-weather</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

###Cutomize project information: Adding project licence

<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">
    <!--...-->

    <name>simple-weather</name>
    <url>http://www.test.com</url>

    <licenses>
        <license>
            <name>Apache 2</name>
            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo</distribution>
            <comments>A business-friendly OSS license</comments>
        </license>
    </licenses>

    <organization>
        <name>Test</name>
        <url>http://www.test.com</url>
    </organization>

    <developers>
        <developer>
            <id>test</id>
            <name>full name</name>
            <email>[email protected]</email>
            <url>http://www.test.com</url>
            <organization>Test</organization>
            <organizationUrl>http://www.test.com</organizationUrl>
            <roles>
                <role>developer</role>
            </roles>
            <timezone>-6</timezone>
        </developer>
    </developers>

    <!--...-->
</project>

###Adding dependecies to the project Adding Dom4J, Jaxen, Velocity, and Log4J as Dependencies

<project>
    <!--[...]-->
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <!--[...]-->
</project>

###Adding test scoped dependencies A test-scoped dependency is a dependency that is available on the classpath only during test compilation and test execution. If your project has war or ear packaging, a test-scoped dependency would not be included in the project’s output archive.

<project>
    ...
    <dependencies>
        <!-- ... -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
            <scope>test</scope>
        </dependency>
        <!-- ... -->
    </dependencies>
</project>

###Define maven plugins and goals

<build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>org.test.mavenbook.weather.Main</mainClass>
              <addClasspath>true</addClasspath>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
      </plugin>
      <plugin>
       <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

###Running the program

$ mvn install
$ mvn exec:java -Dexec.mainClass=org.test.mavenbook.weather.Main

passing command line args to the program using exec.args:

mvn exec:java -Dexec.mainClass=org.sonatype.mavenbook.weather.Main \
      -Dexec.args="70112"

More about Exec plugin:

Exec plugin allows you to execute Java classes and other scripts. It is not a core Maven plugin, but it is available from the Mojo project hosted by Codehaus. For a full description of the Exec plugin, run mvn help:describe -Dplugin=exec -Dfull

###Executing Unit Tests

mvn test

###Skipping Unit Tests

mvn install -Dmaven.test.skip=true

###Packaging application The Maven Assembly plugin is a plugin you can use to create arbitrary distributions for your applications. You can use the Maven Assembly plugin to assemble the output of your project in any format you desire by defining a custom assembly descriptor.

Configuring the maven assembly descriptor:

<project>
    <!--[...]-->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <!--[...]-->
</project>

Once you’ve added this configuration, you can build the assembly by running the assembly:assembly goal

mvn install assembly:assembly

Attaching assembly goal to the package phase:

The following plugin configuration configures the Maven Assembly plugin to execute the attached goal during the package phase of the Maven default build lifecycle. The attached goal does the same thing as the assembly goal. To bind to assembly:attached goal to the package phase we use the executions element under plugin in the build section of the project’s POM.

<project>
    <!--[...]-->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>simple-command</id>
                        <phase>package</phase>
                        <goals>
                            <goal>attached</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <!--[...]-->
</project>

Once you have this configuration in your POM, all you need to do to generate the assembly is run mvn package. The execution configuration will make sure that the assembly:attached goal is executed when the Maven lifecycle transitions to the package phase of the lifecycle. The assembly will also be created if you run mvn install as the package phase precedes the install phase in the default Maven lifecycle.

###Exploring project dependencies

mvn dependency:resolve
mvn dependency:tree
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cloudera</groupId>
<artifactId>mapreduce</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Map Reduce</name>
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.0.0-cdh4.1.0</version>
</dependency>
<!-- For unit testing -->
<dependency>
<groupId>org.apache.mrunit</groupId>
<artifactId>mrunit</artifactId>
<version>0.8.0-incubating</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Tells maven to use the Java 6 JDK instead of its default -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>maven-hadoop</id>
<name>Hadoop Releases</name>
<url>https://repository.cloudera.com/content/repositories/releases/</url>
</repository>
<repository>
<id>cloudera-repos</id>
<name>Cloudera Repos</name>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
</repositories>
</project>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
<version>0.20.2</version>
</dependency>
<!-- For more releases
http://mvnrepository.com/artifact/org.apache.hadoop/hadoop-core -->
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>storm.cookbook</groupId>
<artifactId>hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>hello-world</name>
<url>https://bitbucket.org/ashrithr/hello-world</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- REPOSITORIES -->
<repositories>
<repository>
<id>github-releases</id>
<url>http://oss.sonatype.org/content/repositories/github-releases/</url>
</repository>
<repository>
<id>clojars.org</id>
<url>http://clojars.org/repo</url>
</repository>
<repository>
<id>twitter4j</id>
<url>http://twitter4j.org/maven2</url>
</repository>
</repositories>
<!-- DEPENDECIES -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>storm</groupId>
<artifactId>storm</artifactId>
<version>0.8.1</version>
<!-- keep storm out of the jar-with-dependencies -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--
bind the maven-assembly-plugin to the package phase
this will create a jar file without the stormdependencies
suitable for deployment to a cluster.
-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass></mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
<version>1.3.8</version>
<extensions>true</extensions>
<configuration>
<sourceDirectories>
<sourceDirectory>src/clj</sourceDirectory>
</sourceDirectories>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment