You have just tried creating a simple project in maven, you will now learn the maven core concepts. As you have seen in the previous page, pom.xml
is the heart and soul of a maven project. Pom.xml – project object model file has all the information about a given project.
1. Maven repositories
When you run maven generate
, mvn compile
or any other command, maven downloads a lot of files from maven central repo. These files are plugins and transitive dependencies that your project needs.
i. Maven central repository
All artifacts in a project get downloaded from maven central repository. Unless you specify a custom repo in ~/.m2/settings.xml.
- Maven Central Repository Search – https://search.maven.org/
- Maven Central Repository URL – https://repo.maven.apache.org/maven2
ii. Custom maven remote repository
Quite often you will need to use libraries that are not hosted in the maven central repository, but hosted in a different repo. You need to specify these remote repositories in the pom.xml
. You can also specify them in ~/.m2/settings.xml
as well, but this will not be covered here.
<project ....> ... <repositories> <repository> <id>jcenter-snapshots</id> <name>jcenter</name> <url>https://jcenter.bintray.com/</url> </repository> </repositories> ...
iii. Maven local repository (.m2)
Maven downloads dependencies (jar, war, pom files, and plugins) from remote or central repositories and caches them in the local machine. The place where it shows is .m2/repository
. I don’t recommend customizing the default location of the local repo.
The exact location of .m2
in your system is
Unix/Mac OS X – ~/.m2/repository
Windows – C:\Users\{your-username}.m2\repository
You can use the command below to find the exact location of .m2
.
mvn help:evaluate -Dexpression=settings.localRepository
mvn help:evaluate -Dexpression=settings.localRepository [INFO] Scanning for projects... Downloading: https://repo.backbase.com/repo/org/codehaus/mojo/maven-metadata.xml Downloading: https://repo.backbase.com/repo/org/apache/maven/plugins/maven-metadata.xml Downloaded: https://repo.backbase.com/repo/org/apache/maven/plugins/maven-metadata.xml (10 KB at 1.7 KB/sec) Downloaded: https://repo.backbase.com/repo/org/codehaus/mojo/maven-metadata.xml (27 KB at 3.6 KB/sec) Downloading: https://repo.backbase.com/repo/org/apache/maven/plugins/maven-help-plugin/maven-metadata.xml Downloaded: https://repo.backbase.com/repo/org/apache/maven/plugins/maven-help-plugin/maven-metadata.xml (679 B at 0.2 KB/sec) [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Stub Project (No POM) 1 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-help-plugin:3.2.0:evaluate (default-cli) @ standalone-pom --- [INFO] No artifact parameter specified, using 'org.apache.maven:standalone-pom:pom:1' as project. [INFO] /Users/bikramkundu/.m2/repository [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 11.416 s [INFO] Finished at: 2019-07-26T15:56:03+05:30 [INFO] Final Memory: 13M/184M
2. Dependency Management in Maven
Dependency management is a core feature of maven. It is powerful enough to manage dependencies from a simple single project to a complex multi-module project. There are basically 2 types of dependencies that maven manages, direct and transitive dependencies.
What are direct dependencies?
Dependencies that are directly declared in pom.xml
are known as direct dependencies. For example, to use undertow, I need to add it’s dependencies in pom.xml.
<dependencies> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-core</artifactId> <version>${undertow.version}</version> </dependency> ...
What are transitive dependencies?
Even though you only added undertow-core
in the pom.xml
, but the undertow-core has dependencies on several other dependencies. Maven resolves dependencies of dependencies, this is known as transitive dependencies.
... <dependencies> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-parser-generator</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging-processor</artifactId> <scope>provided</scope> </dependency> ...
3. Dependency scope in maven
Dependency scope is used to limit the transitivity of a dependency, and also to affect the classpath used for various build tasks. This is an important maven core concept. There are 6 scopes available:
<dependency> <groupId>org.jboss.xnio</groupId> <artifactId>xnio-api</artifactId> <!-- <scope>compile</scope> --> </dependency> <dependency> <groupId>org.jboss.xnio</groupId> <artifactId>xnio-nio</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.eclipse.jetty.alpn</groupId> <artifactId>alpn-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <scope>test</scope> </dependency>
- compile – Default scope, used if none is specified. Compile dependencies are available in all classpaths of a project and propagated to dependent projects.
- provided – Similar to compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For web-app you use Servlet API and scope to provided because the web container like tomcat will provide it in runtime. This scope is not transitive.
- runtime – Indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
- test – This scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and test execution phases. This scope is not transitive.
- system –
This scope is similar toprovidedexcept that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.I don’t encourage using this. - import – This scope is only supported on a dependency of type
pom
in the<dependencyManagement>
section. It indicates the dependency to be replaced with the effective list of dependencies in the specified POM’s<dependencyManagement>
section.import
do not actually participate in limiting the transitivity of a dependency.
4. Maven dependency tree
Use mvn dependency:tree
command to view the list of all dependencies in your project – transitively. Transitive dependency means that if project-A depends on project-B and project-B depends on project-C, then project-A depends on both B and C.
mvn dependency:tree
[INFO] --- maven-dependency-plugin:3.0.0:tree (default-cli) @ resource --- [INFO] com.jstobigdata.web.api:resource:jar:b0 [INFO] +- com.jstobigdata.commons:configuration:jar:b0:compile [INFO] | +- org.apache.activemq:activemq-client:jar:5.14.5:compile [INFO] | | +- org.apache.geronimo.specs:geronimo-jms_1.1_spec:jar:1.1.1:compile [INFO] | | +- org.fusesource.hawtbuf:hawtbuf:jar:1.11:compile [INFO] | | \- org.apache.geronimo.specs:geronimo-j2ee-management_1.1_spec:jar:1.0.1:compile [INFO] | +- org.hibernate:hibernate-core:jar:5.1.0.Final:compile [INFO] | | +- org.jboss.logging:jboss-logging:jar:3.3.1.Final:compile [INFO] | | +- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:jar:1.0.0.Final:compile [INFO] | | +- org.javassist:javassist:jar:3.20.0-GA:compile [INFO] | | +- antlr:antlr:jar:2.7.7:compile [INFO] | | +- org.apache.geronimo.specs:geronimo-jta_1.1_spec:jar:1.1.1:compile [INFO] | | +- org.jboss:jandex:jar:2.0.0.Final:compile [INFO] | | +- com.fasterxml:classmate:jar:1.4.0:compile [INFO] | | +- dom4j:dom4j:jar:1.6.1:compile [INFO] | | | \- xml-apis:xml-apis:jar:1.4.01:compile [INFO] | | \- org.hibernate.common:hibernate-commons-annotations:jar:5.0.1.Final:compile [INFO] | +- com.zaxxer:HikariCP:jar:2.7.4:compile [INFO] | +- javax.jms:javax.jms-api:jar:2.0.1:compile [INFO] | +- com.jstobigdata.cxp.portal.commons:portal-commons:jar:b0:compile [INFO] | +- org.yaml:snakeyaml:jar:1.23:compile [INFO] | +- com.jstobigdata.bb:spring-boot-configuration-adapter:jar:0.0.1:compile [INFO] | +- org.springframework.boot:spring-boot-starter-actuator:jar:2.1.4.RELEASE:compile [INFO] | | +- org.springframework.boot:spring-boot-actuator-autoconfigure:jar:2.1.4.RELEASE:compile [INFO] | | | \- org.springframework.boot:spring-boot-actuator:jar:2.1.4.RELEASE:compile [INFO] | | \- io.micrometer:micrometer-core:jar:1.1.4:compile
That is how a real-world example may look like, as shown in the above example.
Transitivity brings a serious problem when different versions of the same artifacts are included by different dependencies. It often causes version mismatch issue in runtime,
dependency:tree
works as a swiss-knife in such case.
5. Maven dependency exclusion
There are several possible reasons why you may like to exclude a specific dependency (artifacts) from the transitive dependencies list. One obvious reason is version mismatch, another one is the choice of artifacts, etc.
I will explain a practical use case. Spring-boot comes with tomcat as the default embedded servlet container, but I want to use jboss-undertow
. Therefore, I have to exclude tomcat
from the spring-boot dependency list and include undertow related artifacts.
<dependencies> <!-- Use Undertow instead of tomcat --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> .... </dependencies>
You have understood the maven core concepts and dependency management. In the next part of the tutorial, will be focusing on the lifecycle of the maven project, and will understand maven plugins.