Direct Dependency & Transitive Dependency
There’re two types of dependencies in Maven:
- direct
- transitive
Direct dependencies are the ones that are explicitly included in the project. These can be included in the project using <dependency> tags:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>Transitive dependencies, on the other hand, are dependencies required by our direct dependencies. Required transitive dependencies are automatically included in our project by Maven.
We can list all dependencies including transitive dependencies in the project using:
mvn dependency:tree
Dependency Scopes
the scope element refers to the classpath of the task at hand (compiling and runtime, testing, etc.) as well as how to limit the transitivity of a dependency
maven has 6 default dependency scopes
- default scope when no other scope is provided
- dependencies with this scope are available on all classpaths
- dependencies with this scope are transitive
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
- used to mark dependencies that should be provided at runtime by JDK or a container
- dependencies with this scope are available only at compile and test classpaths (not runtime)
- dependencies with this scope are NOT transitive
A good use case for this scope would be a web application deployed in some container, where the container already provides some libraries itself.
For example, a web server that already provides the Servlet API at runtime, thus in our project, those dependencies can be defined with the provided scope
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
- indicates that the dependency is not required for compilation, but is for execution
- dependencies with this scope are available only at runtime and test classpaths (not compile)
A good example of dependencies that should use the runtime scope is a JDBC driver
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
<scope>runtime</scope>
</dependency>
- indicates that the dependency is not required at standard runtime of the application, but is used only for test purposes
- dependencies with this scope are only available for test-compilation and test-execution classpaths
- dependencies with this scope are NOT transitive
The standard use case for this scope is adding test library like JUnit to our application:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
- system scope is much similar to the provided scope
- the main difference between those two scopes is that system requires us to directly point to specific jar on the system
The important thing to remember is that building the project with system scope dependencies may fail on different machines if dependencies aren’t present or are located in a different place than the one systemPath points to:
<dependency>
<groupId>com.marcuschiu</groupId>
<artifactId>custom-dependency</artifactId>
<version>1.3.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/custom-dependency-1.3.2.jar</systemPath>
</dependency>
- This scope was added in Maven 2.0.9 and it’s only available for the dependency type pom
- Import indicates that this dependency should be replaced with all effective dependencies declared in it’s POM
<dependency>
<groupId>com.marcuschiu</groupId>
<artifactId>custom-project</artifactId>
<version>1.3.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Scope & Transitivity
a project’s dependency that is marked:
compilescope, then:- all dependencies with
runtimescope will be pulled in withruntimescope in the project - all dependencies with
compilescope will be pulled in withcompilescope in the project
- all dependencies with
providedscope, then bothruntimeandcompilescope dependencies will be pulled in with theprovidedscope in the projecttestscope, then bothruntimeandcompilescope transitive dependencies will be pulled in with thetestscope in the projectruntimescope, then bothruntimeandcompilescope transitive dependencies will be pulled in with theruntimescope in the project
NOTE: a project with dependencies that contains dependencies with scopes provided and test will never be included in the project