Maven is a build system to compile application artifacts for a Java based application. Apache Maven is different from Apache Ant in that it uses convention over configuration. Maven assumes a Java project directory layout for source, tests, etc rather than explicitly specifying the layout as one does in Apache Ant.
Maven also automatically pulls in dependencies for the Java project from http://central.maven.org/maven2/, allowing one to focus on the CM and management of source code rather than library versions and library dependencies. The specific version of the Java Jar file can be specified and easily upgraded. This dependency management helps reduce the practice of holding Jar file dependencies in a CM system (ie Git, Subversion, CVS) which is best used to manage changes in text files and not binary files.
Maven is directed by a configuration file called pom.xml. This may also be distributed in a project hierarchy where a "parent" pom file calls subsequent pom.xml files lower in the build hierarchy. Maven also has default targets which perform tasks defined by convention. All operations can be modified and expanded with more detail. This is also in contrast to Ant which requires one to define all targets and behavior.
Maven Path Conventions:
Project Artifact | Maven Path |
---|---|
Java Source | Applications: src/main/java/com/megacorp/projectx/...
Servlets:
|
Unit Tests | src/test/java/com/megacorp/projectx/... |
Compiled Code | From source: target/classes/com/megacorp/projectx/... Unit tests: target/test-classes/com/megacorp/projectx/... |
Build Artifacts | eg JAR file: mvn package: target/projectx-1.0-SNAPSHOT.jar mvn install: $HOME/.m2/repository/com/megacorp/projectx/projectx/1.0-SNAPSHOT/projectx-1.0-SNAPSHOT.jar |
Maven has implicit targets which are steps in its "Lifecycle". The targets are executed in the following order:
Maven Target | Description |
---|---|
validate | validate the project is correct and all necessary information is available |
compile | compile the source code of the project |
test | test the compiled source code 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 distributed format, such as a JAR. mvn package : Generates projectx/target/projectx-1.0-SNAPSHOT.jar |
verify | run any checks on results of integration tests to ensure quality criteria are met |
install | install the package into the local repository, for use as a dependency in other projects locally. mvn install : compiles and runs tests. copies jar file to $HOME/.m2/repository/com/megacorp/projectx/projectx/1.0-SNAPSHOT/projectx-1.0-SNAPSHOT.jar |
deploy | done in the build environment, copies the final package to the remote repository for sharing with other developers and projects. |
clean | cleans up artifacts created by prior builds. |
site | generates site documentation for this project. |
The target is inclusive of all prior to it. Thus "mvn install" will execute targets validate, compile, package, verify and install.
This tutorial describes how to configure a "Maven" build for a Java application.
Maven itself is a Java application and requires the installation of Java. See our Java on Linux tutorial.
Download Maven from the Apache website: Maven Download apache-maven-3.5.3-bin.zip
Install Maven:
- cd /opt
- sudo unzip ~/Downloads/apache-maven-3.5.3-bin.zip
if [ -d /usr/java/latest ] then export JAVA_HOME=/usr/java/latest export JDK_HOME=$JAVA_HOME export CLASSPATH=$JAVA_HOME/lib/tools.jar:./ fi if [ -d /opt/apache-maven-3.5.3/bin/ ] then PATH=/opt/apache-maven-3.5.3/bin:$PATH fi
Maven will generate an example "Hello World" Maven project with the following command:
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false -DgroupId=com.megacorp.projectx -DartifactId=projectx
- Default Maven build file: projectx/pom.xml
- Hello World default program: projectx/src/main/java/com/megacorp/projectx/App.java
- JUnit test driver: projectx/src/test/java/com/megacorp/projectx/AppTest.java
<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>com.megacorp.projectx</groupId> <artifactId>projectx</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>projectx</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>
Build project: mvn package
- cd projectx
- mvn package
This will generate target/projectx-1.0-SNAPSHOT.jar
Run: mvn exec:java -Dexec.mainClass="com.megacorp.projectx.App" (with loads of Maven messages) or java -cp target/projectx-1.0-SNAPSHOT.jar com.megacorp.projectx.App
Result: Hello World!
Run tests: mvn verify (with loads of Maven messages)
... ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.megacorp.projectx.AppTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.008 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 ...
Top parent POM file: pom.xml Maven configuration file:
<?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> <name>ProjectX Parent POM</name> <groupId>com.megacorp.projectx</groupId> <artifactId>projectx</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.20</version> <configuration> <redirectTestOutputToFile>true</redirectTestOutputToFile> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <compilerArgument>${compilerArgument}</compilerArgument> </configuration> </plugin> </plugins> </build> <properties> <skipTests>true</skipTests> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.jar.plugin>2.3.2</maven.jar.plugin> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <log4j.version>1.2.16</log4j.version> <metainf-services.version>1.6</metainf-services.version> <slf4j.version>1.6.1</slf4j.version> <spring.version>4.0.5.RELEASE</spring.version> <junit.version>4.12</junit.version> </properties> <modules> <module>lib/MyLibX</module> <module>lib/MyLibY</module> <module>lib/MyLibZ</module> </modules> <dependencyManagement> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependencies> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <!--Test--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> <version>1.3</version> </dependency> </dependencyManagement> </project>
- The directive "<packaging>pom</packaging>" states the the parent pom is just responsible for calling other pom files.
- The "child" pom Maven modules in hierarchy:
- projectx/lib/MyLibX/pom.xml
- projectx/lib/MyLibY/pom.xml
- projectx/lib/MyLibZ/pom.xml
- projectx/lib/MyLibX/README.txt
- projectx/lib/MyLibX/src/main/java/com/megacorp/...
- projectx/lib/MyLibX/src/test/java/com/megacorp/...
Child POM: projectx/lib/MyLibX/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> <parent> <groupId>com.megacorp.projectx</groupId> <artifactId>projectx</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <groupId>com.megacorp.lib</groupId> <artifactId>MyLibX</artifactId> <version>1.10.0</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
- <parent> : relativePath to parent pom.xml
- Show full hierarchy from parent directory: mvn dependency:display-ancestors
- Jar files are downloaded from the Maven repository to your local cache in $HOME/.m2/ for example the JUnit jar gets downloaded to: $HOME/.m2/repository/junit/junit/4.12/junit-4.12.jar
Maven convention: projectx/src/com/megacorp/projectx/App.java
To do this acknowledge default then modify/over-ride the default:
<project> ... <properties> <src.dir>src/main/java</src.dir> </properties> <build> <sourceDirectory>${src.dir}</sourceDirectory> ... </build> <profiles> <profile> <id>projectx</id> <properties> <src.dir>${project.build.directory}/src</src.dir> </properties> </profile> </profiles> </project>
or specify on the command line: mvn -DtestSourceDirectory=src install
Specify an alternate target directory:
<properties> <deploy.path>/opt/apache-tomcat-6.0.33/webapps/projectx.war</deploy.path> </properties>
We can look at an existing GitHub library example: https://github.com/fiji/Jama/blob/master/pom.xml
... <ciManagement> <system>Jenkins</system> <url>http://jenkins.imagej.net/job/Jama/</url> </ciManagement> <scm> <connection>scm:git:git://github.com/fiji/Jama</connection> <developerConnection>scm:git:git@github.com:fiji/Jama</developerConnection> <tag>HEAD</tag> <url>https://github.com/fiji/Jama</url> </scm> ...
The modern corporate network environment increasingly makes use of the proxy gateway which requires local SSL certificates so that the gateway can examine the contents for viruses and malware. This also makes it difficult to use use https for anything other than the web browser. Maven often gets stuck in this complicated mess and the easiest way out is to use http rather than https. The following configuration is to point Maven to the proxy gateway and to use http to access the public Maven repository.
Edit the Maven global configuration file /opt/apache-maven-3.5.3/conf/settings.xml or your local user configuration ~/.m2/settings.xml:<?xml version="1.0" encoding="UTF-8"?> <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>optional</id> <active>true</active> <protocol>http</protocol> <host>proxy.megacorp.com</host> <port>80</port> <nonProxyHosts>*.megacorp.com|localhost</nonProxyHosts> </proxy> </proxies> <profiles> <profile> <id>http-override</id> <!--Override the default https repository (and pluginRepository) from the Maven Super POM --> <repositories> <repository> <id>central</id> <url>http://central.maven.org/maven2</url> <releases> <enabled>true</enabled> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>central</id> <url>http://central.maven.org/maven2</url> <releases> <enabled>true</enabled> </releases> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <activeProfile>http-override</activeProfile> </activeProfiles> </settings>
"Maven Essentials"
by Prabath Siriwardena ISBN # 178398676X, Packt Publishing For Java developers |
|