Maven is a software project management and comprehension tool, so in other words it can be used to manage all software cycle. This software it helps me a lot in my works and personal projects and in this post I try to share some knownledge and information that I learned.
I create a simple project available on github, click here to get the example. I hope it will help you on your job or personal project(s).
In this post I will try cover all maven lifecycle using my sample project:
- Clean: remove all files generated by the previous build. This phase is outside the default lifecycle and it is possible to execute using "Goals" (see "How To build")
- Validate: validate the project is correct, for example by analying source code, 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 distributable format, such as a JAR.
- Integration-test: process and deploy the package if necessary into an environment where integration tests can be run (missing in my example ☹ )
- Verify: run any checks to verify the package is valid and meets quality criteria (missing in my example ☹ )
- 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.
You found after explanation about pom.xml a little "How To build" and "How To execute".
Explanation about pom.xml
Validate
It is possible to check and Validate source code with different tools:
checkstyle: a development tool to help programmers write Java code that adheres to a coding standard, example: check formatting code, check naming conventions, ... . Add the following lines in pom.xml:
<project ...>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.15</version>
<executions>
<execution>
<id>verify-java-code</id>
<phase>verify</phase>
<configuration>
<encoding>UTF-8</encoding>
<!-- Output errors to console. -->
<consoleOutput>true</consoleOutput>
<!-- Build should fail upon a violation. -->
<failsOnError>true</failsOnError>
<!-- If you have some class to exclude use
"exclude" node -->
<!--<excludes>org/pirola/maven_example/MavenExample.java</excludes>-->
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
...
<plugins>
...
</build>
...
</project>
findbugs: a program which uses static analysis to look for bugs in Java code by applyng some patterns. Add the following lines in pom.xml:
<project ...>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<!-- Max level of analisys and error reporting. -->
<effort>Max</effort>
</configuration>
<goals>
<goal>check</goal>
</goals>
</plugin>
...
<plugins>
...
</build>
...
</project>
Sonar: Sonar is a great tools that can analyse your code and get you a Web Interface to view the results. The Web Application is simple and intuitive, I found it very usefull and well done but analysis the code it takes some times. Because it takes some times to have the result I prefer to create a profile and execute it when I have a relatively stable version. Add the following lines in pom.xml:
<project ...>
...
<!-- Begin profile. -->
<profiles>
<profile>
<!-- Sonar profile, useful for analyze/validate Java code. -->
<id>sonar</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<!-- Example for H2 -->
<sonar.jdbc.url>
jdbc:h2:tcp://localhost:9092/sonar
</sonar.jdbc.url>
<sonar.jdbc.username>sonar</sonar.jdbc.username>
<sonar.jdbc.password>sonar</sonar.jdbc.password>
<!-- Optional URL to server. Default value is http://localhost:9000 -->
<sonar.host.url>
http://localhost:9000
</sonar.host.url>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>sonar</id>
<phase>install</phase>
<goals>
<goal>sonar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!-- End profile. -->
...
</project>
Declare Java version you are using either for source code and for the compiler
<project ...>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<!-- The -source argument for the Java compiler.
1.7 stand for Java 7. -->
<source>1.7</source>
<!-- The -target argument for the Java compiler.
1.7 stand for Java 7. -->
<target>1.7</target>
<!-- Show source locations where deprecated APIs are used. -->
<showDeprecation>true</showDeprecation>
<!-- Show compilation warnings. -->
<showWarnings>true</showWarnings>
</configuration>
</plugin>
...
<plugins>
...
</build>
...
</project>
Generate and save a version/build number for the code compiled and other informations in a special file called Manifest, see Oracle documentation for more information.
In order to have a reproducible build the version number is only store last git sha version on scm-version.
<project ...>
...
<!-- Fake URLs.
This fake URL is used to fail search remote repository and
it use instead the local repository
(see buildnumber-maven-plugin). -->
<scm>
<connection>scm:git:http://none</connection>
<url>scm:git:https://none</url>
</scm>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>set-build-properties</id>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- It will first check to see if you have locally
modified files, and will fail if there are any. -->
<doCheck>true</doCheck>
<!-- If this is made true, then the revision will be
updated to the latest in the repo, otherwise
it will remain what it is locally -->
<doUpdate>true</doUpdate>
<!-- This ensures that even if we are not connected
to scm than also
take the version from local .svn file -->
<format>{0}</format>
<items>
<item>scmVersion</item>
</items>
<!-- If the plugin fails to get the scm revision,
set it to "unavailable" -->
<revisionOnScmFailure>unavailable</revisionOnScmFailure>
</configuration>
</plugin>
...
</build>
</project>
Test
In this phase it is possible to test your software via automatic test. In my example I use JUnit to test the return of the function "getGreeting", please see src/test/java/org/pirola/maven_example/test/TestGreeting class. In order to use Junit you need to add the following lines:
<project ...>
...
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
...
</project>
Package
It is possible to choose different packaging such as: JAR, WAR, EAR, ...
project.mainClass and project.vendor are defined as project properties (see pom.xml: project → properties).
In my example I choose to create an executable JAR by adding the following lines:
<project ...>
...
<packaging>jar</packaging>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<!-- Update Manifest file (META-INF/MANIFEST.MF)
with the new informations.
So this "transformation" will add the following
lines:
- Main-Class: THE program entry point;
- Implementation-Title: the title of the
implementation;
- Implementation-Version: information
retrieved from pom.xml (this file).
See project -> version node;
- Implementation-Vendor: the vendor of the
implementation;
- Scm-Revision: with git sha, "unavailable
if it is impossible to retrieve.
-->
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>${project.mainClass}</Main-Class>
<Implementation-Title>${project.name}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Implementation-Vendor>${project.vendor}</Implementation-Vendor>
<Scm-Revision>${buildNumber}</Scm-Revision>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
</project>
In this phase it is possible to generate javadoc files (html pages) by adding the following lines:
<project ...>
...
<packaging>jar</packaging>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
</project>
Deploy
In this phase is possible deploy your final JAR to remote server.
For security reason is better save username and password in a different file than pom.xml.
In order to do this you need with the following steps:
Create file settings.xml in your .m2 directory (/home/[user]/.m2 or C:\Users\[user]\.m2)
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
<servers>
<server>
<id>develop-server</id>
<username>example</username>
<password>password1234</password>
</server>
</servers>
</settings>
Add the following lines to pom.xml:
<project ...>
...
<packaging>jar</packaging>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<!-- add support for ssh/scp -->
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.9</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>execute-test-commands</id>
<phase>deploy</phase>
<goals>
<goal>upload</goal>
</goals>
<configuration>
<serverId>develop-server</serverId>
<!-- URL to upload final jar -->
<url>scp://example.com</url>
<!-- Input directory (local) -->
<fromDir>${project.build.outputDirectory}/../</fromDir>
<!-- File to upload -->
<includes>maven-example-project.jar</includes>
<!-- Output directory (server side) -->
<toDir>/bin</toDir>
<!--Jar is sent without compression over the net -->
<optimize>false</optimize>
<commands>
<!-- Remove from the server the oldest file -->
<command>\rm /bin/maven-example-project.jar</command>
</commands>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
</project>
How to build
In order to execute build my example you have two way:
Maven CLI (Command Line Interface). In this case you need to install maven see here for more details. Here the instruction:
Clone git repository or download the maven project
Open terminal or your prompt and navigate to maven example project (you must go inside the folder)
Execute the following command
mvn clean install
- Go to "How To execute" in order to execute the program
Eclipse
The following instructions are tested for Eclipse Mars (version 4.5).
Clone git repository or download the maven project
Start eclipse
Click with the right mouse button on the root project and select "Run As" → "Maven build"
Write "clean install" in "Goals" input field, then click on "Apply" and finally click on "Run"
If you want execute sonar, you will insert "sonar" in "Profiles" input field.
Go to "How To execute" in order to execute the program
How to execute
- Open terminal or your prompt and navigate to maven example project (you must go inside the folder)
- Execute the following command (replace '/' with '\' if you are on windows environment)
java -jar ./target/maven-test-project.jar
Comments (1)
Add Comment