mtitek
  • Cloud
  • Big Data
  • CI
  • Install
  • Samples
  • Java
  • Ubuntu
  • Maven
  • Archive
Maven | Project Dependencies
  1. Direct Dependencies
  2. Transitive Dependencies

  1. Direct Dependencies
    There are three important phases that might be required to build a Maven project:
    • First, the compilation of the source code: this phase is referred to as "compile".
    • Second, the compilation of the test source code: this phase is referred to as "test-compile".
    • Third, the packaging of the project: this phase is referred to as "package".

    Notes:
    • When the command "mvn compile" is run, only the first phase ("compile") will be executed.
    • When the command "mvn test-compile" is run, the first and the second phase ("compile", "test-compile") will be executed.
    • And when the command "mvn package" is run, the three phases ("compile", "test-compile", and "package") will be executed.

    We will focus on these three phases to explain how Maven resolves project dependencies.
    See this introduction about Maven build phases: http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

    So how does a project dependency affect the build of a project?

    When a dependency is added to the "pom.xml" file, its scope is specified.
    Here's an example of a dependency (the project depends on "junit" to execute test code):

    Before Maven starts building a project, Maven will try to resolve all project dependencies.
    For each of the phases "compile", "test-compile", and "package" Maven will decide if the dependency is needed to successfully execute each phase.
    The scope of a dependency will let Maven decide if it is needed to execute a specific phase.

    Here are the four main scopes of a dependency:

    • compile
      This is the default scope if you don't specify a scope for the dependency.
      Dependencies that have the scope "compile" will be needed to successfully execute all the three phases: compile the code, compile the test code, and package the project.
      Dependencies with the scope "compile" will be packaged with the project.

    • test
      Dependencies that have the scope "test" will be needed to successfully execute the phase "test-compile": compile the test code.
      Dependencies with the scope "provided" are not transitive.

    • provided
      Dependencies that have the scope "provided" will be needed to successfully execute the phases "compile" and "test-compile": compile the code and compile the test code.
      Dependencies with the scope "provided" will not be packaged with the project.
      Dependencies with the scope "provided" are not transitive.

    • runtime
      Dependencies that have the scope "runtime" will be needed to successfully execute the phases "test-compile" and "package": compile the test code and package the project.
      Dependencies with the scope "provided" will be packaged with the project.


    Here's a table that summarize the relationship between the dependency scope and the build phases.
    Let's say a project "A" depends on project "B".
    Scope
    Direct Dependency
    ("A" ► "B")
    Related Phases Comment
    compile "compile"
    "test-compile"
    "package"
    If any of these phases ("compile", "test-compile", "package") has to be executed, the build will fail if Maven cannot find "B" in the repository.
    test "test-compile" If the phase "test-compile" has to be executed, the build will fail if Maven cannot find "B" in the repository.

    If the phase "compile" has to be executed, the build will fail if the code (not test code) of "A" refers the code of "B".
    provided "compile"
    "test-compile"
    If any of these phases ("compile", "test-compile") has to be executed, the build will fail if Maven cannot find "B" in the repository.
    runtime "test-compile"
    "package"
    If any of these phases ("test-compile", "package") has to be executed, the build will fail if Maven cannot find "B" in the repository.

    If the phase "compile" has to be executed, the build will fail if the code (not test code) of "A" refers the code of "B".
  2. Transitive Dependencies
    A transitive dependency defines the relationship between two projects that are not linked together by a direct dependency.
    For example: Let's say project "A" has a direct dependency on project "B" and project "B" has a direct dependency on project "C". If project "A" has no direct dependency on project "C", then project "A" has a transitive dependency on project "C".

    In other words: if "A" depends on "B" ("A" ► "B") and "B" depends on "C" ("B" ► "C") then "A" depends on "C" ("A" ► "C").

    What matters is how Maven resolve transitive dependencies.

    The scope of the direct and transitive dependencies will let Maven decide if they are needed to successfully execute a specific phase.

    Let's suppose that project "A" depends on project "B" and project "B" depends on project "C".
    We assume that project "A" has no direct dependency on project "C".
    Instead, project "A" has a transitive dependency on project "C".

    So first we need to define the scope of the direct dependency of project "A" on project "B".
    And second we need to define the scope of the direct dependency of project "B" on project "C".
    And third we can define the scope of the transitive dependency of project "A" on project "C".

    Once the scope of the transitive dependency is known, Maven will use the same rules to decide if the project referred by the transitive dependency is needed to successfully execute a build phase.

    There are three scenarios:

    • compile
      If the scope of the direct dependency of "B" on "C" is "compile", then the scope of the transitive dependency of "A" on "C" is the same scope as the direct dependency of "A" on "B".

    • provided, test
      If the scope of the direct dependency of "B" on "C" is "provided" or "test", then "C" is not visible for "A".
      Maven will throw an error if "A" refers the code (including test code) of "C".

    • runtime
      If the scope of the direct dependency of "B" on "C" is "runtime", then the scope of the transitive dependency of "A" on "C" is the same scope as the direct dependency of "A" on "B". Except the case where the scope of the direct dependency of "A" on "B" is "compile", then the scope of the transitive dependency of "A" on "C" is "runtime".

    Here's a table that summarizes the case when the scope of the direct dependency of "B" on "C" is "compile":

    Scope
    Direct Dependency
    ("B" ► "C")
    Scope
    Direct Dependency
    ("A" ► "B")
    Scope
    Transitive Dependency
    ("A" ► "C")
    Related Phases Comment
    compile compile compile "compile"
    "test-compile"
    "package"
    If any of these phases ("compile", "test-compile", "package") has to be executed, the build will fail if Maven cannot find "C" in the repository.
    compile test test "test-compile" If the phase "test-compile" has to be executed, the build will fail if Maven cannot find "C" in the repository.

    If the phase "compile" has to be executed, the build will fail if the code (not test code) of "A" refers the code of "C".
    compile provided provided "compile"
    "test-compile"
    If any of these phases ("compile", "test-compile") has to be executed, the build will fail if Maven cannot find "C" in the repository.
    compile runtime runtime "test-compile"
    "package"
    If any of these phases ("test-compile", "package") has to be executed, the build will fail if Maven cannot find "C" in the repository.

    If the phase "compile" has to be executed, the build will fail if the code (not test code) of "A" refers the code of "C".

    Here's a table that summarize the case when the scope of the direct dependency of "B" on "C" is "runtime":

    Scope
    Direct Dependency
    ("B" ► "C")
    Scope
    Direct Dependency
    ("A" ► "B")
    Scope
    Transitive Dependency
    ("A" ► "C")
    Related Phases Comment
    runtime compile runtime "test-compile"
    "package"
    If any of these phases ("test-compile", "package") has to be executed, the build will fail if Maven cannot find "C" in the repository.

    If the phase "compile" has to be executed, the build will fail if the code (not test code) of "A" refers the code of "C".
    runtime test test "test-compile" If the phase "test-compile" has to be executed, the build will fail if Maven cannot find "C" in the repository.

    If the phase "compile" has to be executed, the build will fail if the code (not test code) of "A" refers the code of "C".
    runtime provided provided "compile"
    "test-compile"
    If any of these phases ("compile", "test-compile") has to be executed, the build will fail if Maven cannot find "C" in the repository.
    runtime runtime runtime "test-compile"
    "package"
    If any of these phases ("test-compile", "package") has to be executed, the build will fail if Maven cannot find "C" in the repository.

    If the phase "compile" has to be executed, the build will fail if the code (not test code) of "A" refers the code of "C".
© 2020  mtitek