Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven transitive dependency has scope compile while when dependency has provided scope

In my project I have openejb-core dependency with scope provided. However it has transitive dependency of slf4j and its scope is compile (see screenshot). All other transitive dependencies are provided as expected.

Question: Is it bug or am I missing something?

enter image description here

like image 234
Evgeny Makarov Avatar asked Feb 17 '16 10:02

Evgeny Makarov


People also ask

What is the difference between compile and provided scope in Maven?

compile This is the default scope, used if none is specified. Compile dependencies are available in all classpaths of a project. Furthermore, those dependencies are propagated to dependent projects. provided This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime.

Are compile dependencies transitive?

It is not transitive. This scope indicates that the dependency is not required for compilation, but is for execution. Maven includes a dependency with this scope in the runtime and test classpaths, but not the compile classpath.

What is scope compile in Maven?

Compile. This is the default scope when no other scope is provided. Dependencies with this scope are available on the classpath of the project in all build tasks. They are also propagated to the dependent projects.

What are Maven transitive dependencies?

Maven Dependency Tree Transitive dependency means that if A depends on B and B depends on C, then A depends on both B and C. Sometimes, transitivity brings a very serious problem when different versions of the same artifacts are included by different dependencies. It may cause version mismatch issues in runtime.


1 Answers

In a sample pom I added:

<dependencies>
    <dependency>
        <groupId>org.apache.openejb</groupId>
        <artifactId>openejb-core</artifactId>
        <version>4.7.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Then running:

mvn dependency:tree -Dincludes=org.slf4j

The output is:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ test-junit ---  
[INFO] com.sample:test-sample:jar:0.0.1-SNAPSHOT   
[INFO] \- org.apache.openejb:openejb-core:jar:4.7.0:provided   
[INFO]    +- org.slf4j:slf4j-jdk14:jar:1.7.7:provided   
[INFO]    \- org.slf4j:slf4j-api:jar:1.7.7:provided   

So as you can see Maven is coherent with its official documentation. The issue from your screenshot is probably on your IDE.

The table is the key point on this topic: enter image description here

From it, we can see that what is transitively in scope compile or runtime goes in scope provided, what is in scope provided or test is ignored.

However, if I change my sample pom to:

<dependencies>
    <dependency>
        <groupId>org.apache.openejb</groupId>
        <artifactId>openejb-core</artifactId>
        <version>4.7.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.7</version>
    </dependency>
</dependencies>

And re-run the dependency tree command, the output is as following:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ test-junit ---
[INFO] com.sample:test-sample:jar:0.0.1-SNAPSHOT   
[INFO] +- org.apache.openejb:openejb-core:jar:4.7.0:provided  
[INFO] |  \- org.slf4j:slf4j-jdk14:jar:1.7.7:provided  
[INFO] \- org.slf4j:slf4j-api:jar:1.7.7:compile  

Look now: it comes not as a child of the provided dependency, but at the same level.

Let's keep on.

If on my sample pom I remove the sl4f-api dependency but I add to the pom the following:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.7</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

And re-re-run the dependency tree command, I finally get the same as your screenshot:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ test-junit ---
[INFO] com.sample:test-sample:jar:0.0.1-SNAPSHOT   
[INFO] \- org.apache.openejb:openejb-core:jar:4.7.0:provided   
[INFO]    +- org.slf4j:slf4j-jdk14:jar:1.7.7:provided  
[INFO]    \- org.slf4j:slf4j-api:jar:1.7.7:compile  

Bingo: the dependencyManagement section is overriding the scope of the transitive dependency, affecting also the mediation on provided scope. This is not a bug, it's by design as in this section you define kind of governance concerning your dependencies. The diagram in this case is also correct and not misleading, since the dependency is only introduced by openejb-core which is then affected by the dependencyManagement decision to put sl4f-api in scope compile.

like image 191
A_Di-Matteo Avatar answered Sep 27 '22 15:09

A_Di-Matteo