Overview Of Maven


1. Introduction

As probably you know that building a software project typically consists of such tasks as downloading dependencies, putting additional jars on a classpath, compiling source code into binary code, running tests, packaging compiled code into deployable artifacts such as a JAR, WAR, and ZIP files, and deploying these artifacts to an application server or repository.
Apache Maven automates these tasks, minimizing the risk of humans making errors while building the software manually and separating the work of compiling and packaging our code from that of code construction.

2. What is Maven?

Apache Maven is a software project management and comprehension tool and as such provides a way to help with managing:
  • Builds
  • Documentation
  • Reporting
  • Dependencies
  • SCMs
  • Releases
  • Distribution
A more formal definition of Apache Maven: Maven is a project management tool which encompasses a project object model, a set of standards, a project lifecycle, a dependency management system, and logic for executing plugin goals at defined phases in a lifecycle. When you use Maven, you describe your

a project using a well-defined project object model, Maven can then apply cross-cutting logic from a set of shared (or custom) plugins.

3. Maven’s Objectives

Maven’s primary goal is to allow a developer to comprehend the complete state of a development effort in the shortest period of time. In order to attain this goal there are several areas of concern that Maven attempts to deal with:
  • Making the build process easy
  • Providing a uniform build system
  • Providing quality project information
  • Providing guidelines for best practices development
  • Allowing transparent migration to new features

4. What is the Build Tool?

A build tool takes care of everything for building a process. It does the following:
  • Generates source code (if the auto-generated code is used)
  • Generates documentation from source code
  • Compiles source code
  • Packages compiled code into a JAR of a ZIP file
  • Installs the packaged code in the local repository, server repository, or central repository

5. Key features of Maven

Apache Maven can be used in environments where common build tools like GNU Make or Apache Ant were used. The key features of Maven are:
  • Convention over configuration: Maven tries to avoid as much configuration as possible, by choosing real-world default values and supplying project templates (archetypes).
  • Dependency management: It is possible to define dependencies to other projects. During the build, the Maven build system resolves the dependencies and it also builds the dependent projects if needed.
  • Repository: Project dependencies can be loaded from the local file system, from the Internet or public repositories. The company behind the Maven project also provides a central repository called Maven Central.
  • Extensible via plug-ins: The Maven build system is extensible via plug-ins, which allows keeping the Maven core small. The Maven core does for example not know how to compile Java source code, this is handled by the compiler plug-in

5. Comparing Maven with Ant

Let's compare Maven and Ant with an example so that you can understand easily. When you use Ant, you supply Ant with specific instructions for compiling and packaging your output. Look at the following example of a simple build.xml file:
<project name="my-project" default="dist" basedir=".">
    <description>simple example build file</description>
    <!-- set global properties for this build -->
    <property name="src" location="src/main/java"/>
    <property name="build" location="target/classes"/>
    <property name="dist" location="target"/>
    <target name="init">
        <!-- Create the time stamp -->
        <tstamp/>
        <!-- Create the build directory structure used by compile -->
        <mkdir dir="${build}"/>
    </target>
    <target name="compile" depends="init"
description="compile the source " >
        <!-- Compile the java code from ${src} into ${build} -->
        <javac srcdir="${src}" destdir="${build}"/>
    </target>
    <target name="dist" depends="compile"
description="generate the distribution" >
        <!-- Create the distribution directory -->
        <mkdir dir="${dist}/lib"/>
        <!-- Ouput into ${build} into a MyProject-${DSTAMP}.jar file -->
        <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar"
basedir="${build}"/>
    </target>
    <target name="clean"
description="clean up" >
        <!-- Delete the ${build} and ${dist} directory trees -->
        <delete dir="${build}"/>
        <delete dir="${dist}"/>
    </target>
</project>
In this simple Ant example, you can see how you have to tell Ant exactly what to do. There is a compile goal which includes the javac task that compiles the source in the src/main/java directory to the target/classes directory. 
You have to tell Ant exactly where your source is, where you want the resulting bytecode to be stored, and how to package this all into a JAR file. While there are some recent developments that help make Ant less procedural, a developer’s experience with Ant is in coding a procedural language written in XML.
Contrast the previous Ant example with a Maven example. In Maven, to create a JAR file from some Java source, all you need to do is create a simple pom.xml, place your source code in ${basedir}/ src/main/java and then run mvn install from the command line. 
The same Ant example can be achieved using maven in a very simple way:
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.sonatype.mavenbook</groupId>
    <artifactId>my-project</artifactId>
    <version>1.0-SNAPSHOT</version>
</project>
Running mvn install from the command line will process resources, compile the source, execute unit tests, create a JAR, and install the JAR in a local repository for reuse in other projects.
The differences between Ant and Maven in this example are:

Apache Ant

  • Ant doesn’t have formal conventions like a common project directory structure or default behavior. You have to tell Ant exactly where to find the source and where to put the output. Informal conventions have emerged over time, but they haven’t been codified into the product.
  • Ant is procedural. You have to tell Ant exactly what to do and when to do it. You have to tell it to compile, then copy, then compress.
  • Ant doesn’t have a lifecycle. You have to define goals and goal dependencies. You have to attach a sequence of tasks to each goal manually.

Apache Maven

  • Maven has conventions. It knows where your source code is because you followed the convention. Maven’s Compiler plugin put the bytecode in target/classes, and it produces a JAR file in a target.
  • Maven is declarative. All you had to do was create a pom.xml file and put your source in the default directory. Maven took care of the rest.
  • Maven has a lifecycle which was invoked when you executed mvn install. This command told Maven to execute a series of sequential lifecycle phases until it reached the install lifecycle phase. As a side effect of this journey through the lifecycle, Maven executed a number of default plugin goals which did things like compile and create a JAR.

6. Project Object Model - Pom.xml

The configuration of a Maven project is done via a Project Object Model (POM), represented by a pom.xml file. The POM describes the project, manages dependencies, and configures plugins for building the software.
The POM also defines the relationships among modules of multi-module projects. Let’s look at the basic structure of a typical POM file:
<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>net.javaguides.hibernate</groupId>
    <artifactId>hibernate-tutorial</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>hibernate-tutorial</name>
    <url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <modules>
        <module>hibernate-xml-config-example</module>
        <module>hibernate-java-config-example</module>
        <module>hibernate-save-entity-example</module>
    </modules>
    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
Let’s take a closer look at these constructs.

Project Identifiers

Maven uses a set of identifiers, also called coordinates, to uniquely identify a project and specify how the project artifact should be packaged:
  • groupId – a unique base name of the company or group that created the project
  • artifactId – a unique name of the project
  • version – a version of the project
  • packaging – a packaging method (e.g. WAR/JAR/ZIP)
The first three of these (groupId:artifactId:version) combine to form the unique identifier and are the mechanism by which you specify which versions of external libraries (e.g. JARs) your project will use.

Dependencies

These external libraries that a project uses are called dependencies. The dependency management feature in Maven ensures automatic download of those libraries from a central repository, so you don’t have to store them locally.
This is a key feature of Maven and provides the following benefits:
  • uses less storage by significantly reducing the number of downloads off remote repositories
  • makes checking out a project quicker
  • provides an effective platform for exchanging binary artifacts within your organization and beyond without the need for building artifact from source every time.
In order to declare a dependency on an external library, you need to provide the groupId, artifactId, and the version of the library.

Let’s take a look at an example:
<dependencies>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.3.7.Final</version>
    </dependency>
</dependencies>
As Maven processes the dependencies, it will download Hibernate library into your local Maven repository.

Repositories

A repository in Maven is used to hold build artifacts and dependencies of varying types. The default local repository is located in the .m2/repository folder under the home directory of the user.
If an artifact or a plug-in is available in the local repository, Maven uses it. Otherwise, it is downloaded from a central repository and stored in the local repository. The default central repository is a Maven Central.
Some libraries, such as JBoss server, are not available at the central repository but are available at an alternate repository. For those libraries, you need to provide the URL to the alternate repository inside the pom.xml file:
<repositories>
    <repository>
        <id>JBoss repository</id>
        <url>http://repository.jboss.org/nexus/content/groups/public/</url>
    </repository>
</repositories>
Please note that you can use multiple repositories in your projects.

Properties

Custom properties can help to make your pom.xml file easier to read and maintain. In the classic use case, you would use custom properties to define versions for your project’s dependencies.
Maven properties are value-placeholders and are accessible anywhere within a pom.xml by using the notation ${name}, where a name is the property.
Let’s see an example:
<properties>
    <springboot.version>2.1.0.RELEASE</springboot.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${springboot.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>${springboot.version}</version>
    </dependency>
</dependencies>
Now if you want to upgrade Spring to a newer version, you only have to change the value inside the<spring.version> property tag and all the dependencies using that property in their tags will be updated.
Properties are also often used to define build path variables:
<properties>
    <project.build.folder>${project.build.directory}/tmp/</project.build.folder>
</properties>
 
<plugin>
    //...
    <outputDirectory>${project.resources.build.folder}</outputDirectory>
    //...
</plugin>

Build

The build section is also a very important section of the Maven POM. It provides information about the default Maven goal, the directory for the compiled project, and the final name of the application. The default build section looks like this:
<build>
    <defaultGoal>install</defaultGoal>
    <directory>${basedir}/target</directory>
    <finalName>${artifactId}-${version}</finalName>
    <filters>
        <filter>filters/filter1.properties</filter>
    </filters>
    //...

</build>
The default output folder for compiled artifacts is named the target, and the final name of the packaged artifact consists of the artifactId and version, but you can change it at any time.

Using Profiles

Another important feature of Maven is its support for profiles. A profile is basically a set of configuration values. By using profiles, you can customize the build for different environments such as Production/Test/Development:
<profiles>
    <profile>
        <id>production</id>
        <build>
            <plugins>
                <plugin>
                //...
                </plugin>
            </plugins>
        </build>
    </profile>
    <profile>
        <id>development</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <plugins>
                <plugin>
                //...
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
As you can see in the example above, the default profile is set to develop. If you want to run the production profile, you can use the following Maven command:
mvn clean install -Pproduction

7. Conclusion

In this article, we learned what is a maven, its features and what is the use of maven, we compared maven with Ant, We have seen different components of Pom.xml with example etc. In the next article, we will learn the standard directory layout of a typical Maven project.

Comments