Skip to content
bobby_dreamer

Maven fundamentals

java, maven4 min read

Maven is based around the central concept of a build lifecycle and its made up of phases and these are executed sequentially,

  • 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 distributable format. Some of the valid packaging values are jar, war, ear and pom.
  • 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
  • deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.

If you execute command mvn verify, it executes each default lifecycle phase in order (validate, compile, package, etc.), before executing verify.

Most commonly used command is mvn clean package

Each phase is made up of finer goals and these goals are grouped together in a Maven plugin. A plugin may have one or more goals wherein each goal represents a capability of that plugin. A goal not bound to any build phase could be executed outside of the build lifecycle by direct invocation. The order of execution depends on the order in which the goal(s) and the build phase(s) are invoked. For example, consider the command below. The clean and package arguments are build phases, while the dependency:copy-dependencies is a goal (of a plugin).

1mvn clean dependency:copy-dependencies package

If this were to be executed, the clean phase will be executed first, and then the dependency:copy-dependencies goal, before finally executing the package phase.


Setting up a simple maven project

Eclipse ➔ File ➔ New ➔ Project ➔ Maven Project ➔ Next

Don't check Create a simple project(skip archetype selection) as in the next screen you will have to filter archetypes org.apache.maven and select maven.archetype.quickstart ➔ Next

Fill GroupId, ArtifactId, Version and Package

  • GroupId – A unique base name of the company or group that created the project. Usually a reverse domain name eg:- com.yahoo, com.google, com.ibm, com.bobbydreamer
  • ArtifactId – A unique name of the project. Eg:- slim-maven
  • Version – By default it starts with 1.0-SNAPSHOT as you make changes increase the version number like 1.1-SNAPSHOT. SNAPSHOT is a build which can be replaced by another build as the name implies it could change any time as it is actively developed. It can also be called as beta but its not. RELEASE is the final build for a verion which does not change 1.9-RELEASE.
  • Package – Package contains the source codes. Say if you set the package to com.foo.bar, the generated maven project will contain a folder com/foo/bar in src/main/java. So think about it. Eg:- com.bobbydreamer.slim_maven

Click Finish


It should look like this now

Ecliipse Maven Project


Adding dependency

Dependency in terms of maven is a packaged piece of classes that your project depends on. It can be jar, war etc. For example, if you want to be able to write JUnit test, you'll have to use JUnit annotations and classes thus you have to declare that your project depends on JUnit.

Here we are going to add dependencies namely,

  • junit
  • log4j-api
  • log4j-core

Adding those 3 dependencies in pom.xml under <dependencies></dependencies> tag, you can get these from mvnrepository or by googling maven library-name

1<dependencies>
2 <dependency>
3 <groupId>junit</groupId>
4 <artifactId>junit</artifactId>
5 <version>4.11</version>
6 <scope>test</scope>
7 </dependency>
8
9 <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
10 <dependency>
11 <groupId>org.apache.logging.log4j</groupId>
12 <artifactId>log4j-api</artifactId>
13 <version>2.14.1</version>
14 </dependency>
15
16 <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
17 <dependency>
18 <groupId>org.apache.logging.log4j</groupId>
19 <artifactId>log4j-core</artifactId>
20 <version>2.14.1</version>
21 </dependency>
22 </dependencies>

When you do Ctrl+S, the dependencies get downloaded to a new folder(symbolic) Maven Dependencies but its actually downloaded to C:\users\Sushanth\.m2\repository\

Setting up log4j configuration

Two things you got to do,

  1. Create a new folder called resources under src/main and src/test - blue box in pic
  2. Create a new folder called logs under the main project - green box in pic

Ecliipse Maven Project

App.java
1package com.bobbydreamer.sllim_maven;
2
3import org.apache.logging.log4j.LogManager;
4import org.apache.logging.log4j.Logger;
5
6/**
7 * Hello world!
8 */
9public class App {
10 private static final Logger logger = LogManager.getLogger(App.class);
11 public static void main( String[] args )
12 {
13 System.out.println( "Hello World!" );
14
15 logger.trace("We've just greeted the user!");
16 logger.debug("We've just greeted the user!");
17 logger.info("We've just greeted the user!");
18 logger.warn("We've just greeted the user!");
19 logger.error("We've just greeted the user!");
20 logger.fatal("We've just greeted the user!");
21 }
22}

Create the below log4j configuration file in src/main/resources folder. Highlighted line mentions where log file will be created during execution.

log4j2.xml
1<?xml version="1.0" encoding="UTF-8"?>
2<Configuration status="INFO">
3 <Appenders>
4 <Console name="ConsoleAppender" target="SYSTEM_OUT">
5 <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
6 </Console>
7 <File name="FileAppender" fileName="logs/application-${date:yyyyMMdd}.log" immediateFlush="false" append="true">
8 <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
9 </File>
10 </Appenders>
11 <Loggers>
12 <Root level="debug">
13 <AppenderRef ref="ConsoleAppender" />
14 <AppenderRef ref="FileAppender"/>
15 </Root>
16 </Loggers>
17</Configuration>

Plugins

Plugins perform tasks for a Maven build. These are not packaged in the application. Any task executed by Maven is performed by plugins.

There are two categories of plugins,

  • Build plugins will be executed during the build and they should be configured in the element from the POM.
  • Reporting plugins will be executed during the site generation and they should be configured in the element from the POM.

According to specific goals specified, a specific lifecyle will be used and a specific set of plugins goals will be executed(eg:- mvn clean, mvn package)

All the plugins mentioned under <build>, most of which are automatically added by eclipse during maven and build.

pom.xml
1<build>
2 <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
3 <plugins>
4 <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
5 <plugin>
6 <artifactId>maven-clean-plugin</artifactId>
7 <version>3.1.0</version>
8 </plugin>
9 <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
10 <plugin>
11 <artifactId>maven-resources-plugin</artifactId>
12 <version>3.0.2</version>
13 </plugin>
14 <plugin>
15 <artifactId>maven-compiler-plugin</artifactId>
16 <version>3.8.0</version>
17 </plugin>
18 <plugin>
19 <artifactId>maven-surefire-plugin</artifactId>
20 <version>2.22.1</version>
21 </plugin>
22
23 <plugin>
24 <artifactId>maven-install-plugin</artifactId>
25 <version>2.5.2</version>
26 </plugin>
27 <plugin>
28 <artifactId>maven-deploy-plugin</artifactId>
29 <version>2.8.2</version>
30 </plugin>
31 <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
32 <plugin>
33 <artifactId>maven-site-plugin</artifactId>
34 <version>3.7.1</version>
35 </plugin>
36 <plugin>
37 <artifactId>maven-project-info-reports-plugin</artifactId>
38 <version>3.0.0</version>
39 </plugin>
40
41 </plugins>
42 </pluginManagement>
43<!-- ... -->

Below are plugins mentioned outside of <pluginManagement> as you want them to execute. Plugins we have here are,

  1. maven-jar-plugin : This plugin provides the capability to build jars
  2. maven-dependency-plugin : The dependency plugin provides the capability to manipulate artifacts. It can copy and/or unpack artifacts from local or remote repositories to a specified location.
  3. maven-resources-plugin : The resources plugin copies files from input resource directories to an output directory.

Do note in maven-jar-plugin we mention the mainClass, if we don't do that, we get error like below,

1no main manifest attribute, in slim_maven-0.0.1-SNAPSHOT.jar

My thoughts are maven-jar-plugin and maven-dependency-plugin should be used together and maven-resources-plugin is optional.

pom.xml
1<!-- ... -->
2 <plugins>
3 <plugin>
4 <artifactId>maven-jar-plugin</artifactId>
5 <version>3.0.2</version>
6 <configuration>
7 <archive>
8 <manifest>
9 <addClasspath>true</addClasspath>
10 <mainClass>com.bobbydreamer.slim_maven.App</mainClass>
11 <classpathPrefix>dependency-jars/</classpathPrefix>
12 </manifest>
13 </archive>
14 </configuration>
15 </plugin>
16
17 <!-- Copy project dependency -->
18 <plugin>
19 <groupId>org.apache.maven.plugins</groupId>
20 <artifactId>maven-dependency-plugin</artifactId>
21 <version>2.5.1</version>
22 <executions>
23 <execution>
24 <id>copy-dependencies</id>
25 <phase>package</phase>
26 <goals>
27 <goal>copy-dependencies</goal>
28 </goals>
29 <configuration>
30 <!-- exclude junit, we need runtime dependency only -->
31 <includeScope>runtime</includeScope>
32 <outputDirectory>${project.build.directory}/dependency-jars/</outputDirectory>
33 </configuration>
34 </execution>
35 </executions>
36 </plugin>
37
38 <plugin>
39 <artifactId>maven-resources-plugin</artifactId>
40 <version>3.0.2</version>
41 <executions>
42 <execution>
43 <id>copy-resources</id>
44 <phase>package</phase>
45 <goals>
46 <goal>copy-resources</goal>
47 </goals>
48 <configuration>
49 <outputDirectory>${project.build.directory}/resources/</outputDirectory>
50 <resources>
51 <resource>
52 <directory>${basedir}</directory> <!-- source directory -->
53 <filtering>true</filtering>
54 <excludes> <!--Those files will be excluded-->
55 <exclude>.project</exclude>
56 </excludes>
57
58 <includes> <!--Only those files will be included-->
59 <include>pom.xml</include>
60 </includes>
61 </resource>
62
63 <resource>
64 <directory>${basedir}/src/main/resources</directory> <!-- source directory -->
65 <filtering>true</filtering>
66 </resource>
67 </resources>
68 </configuration>
69 </execution>
70 </executions>
71 </plugin>
72
73 </plugins>
74 </build>

In the below image, i have highlighted few things to note,

  1. dependency-jars folder contains the log4j jar files
  2. logs folder contains logs written by the application
  3. resources folder contains log4j2.xml and pom.xml
  4. slim_maven-0.0.1-SNAPSHOT.jar is the jar file built by Maven

Java JAR Execution

This is a thin jar solution where all project’s dependencies are copied to a pre-defined folder called dependency-jars. If we extract slim_maven-0.0.1-SNAPSHOT.jar using command tar xvf slim_maven-0.0.1-SNAPSHOT.jarand see the META-INF/MANIFEST.MF, the dependencies are added in the Class-Path.

MANIFEST.MF
1Manifest-Version: 1.0
2Created-By: Apache Maven 3.8.1
3Built-By: Sushanth
4Build-Jdk: 16.0.1
5Class-Path: dependency-jars/log4j-api-2.14.1.jar dependency-jars/log4j-c
6 ore-2.14.1.jar
7Main-Class: com.bobbydreamer.slim_maven.App

References