Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven dependency within dependency with different scope

Tags:

java

maven-2

Say I have two Maven dependencies defined in a project like below.

    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.3.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mycompany.library</groupId>
        <artifactId>mylibrary</artifactId>
        <version>1.0.1</version>
        <scope>compile</scope>
    </dependency>

Then, within mylibrary, I also have a dependency defined as below.

    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.3.1</version>
        <scope>compile</scope>
    </dependency>

When I package my project, I don't see xstream packaged within it. I think the project's xstream dependency scope, 'test' is overriding the mylibrary's xstream dependency scope, 'compile'.

In this kind of situation, what's the best way to include the xstream for the whole project so the submodule can have access to it when packaged within the project?

I've read Apache Maven website's explanation on Transitive dependencies, but I'm struggling to understand what it means, and also to find out the best practice in this situation.

like image 754
tim_wonil Avatar asked Sep 08 '09 23:09

tim_wonil


People also ask

Does Maven support different dependency scopes?

Maven has six default dependency scopes. And it's important to understand that each scope — except for import — has an impact on transitive dependencies.

What are transitive dependencies in Maven?

Transitive Dependencies. Maven avoids the need to discover and specify the libraries that your own dependencies require by including transitive dependencies automatically. This feature is facilitated by reading the project files of your dependencies from the remote repositories specified.

What is the use of scope in Maven dependency?

This scope indicates that dependency is to be provided by JDK or web-Server/Container at runtime. This scope indicates that dependency is not required for compilation, but is required during execution. This scope indicates that the dependency is only available for the test compilation and execution phases.


2 Answers

This feels really odd to me, and if it's "feature", I think it is a really dangerous one. Anyway, it's not a Maven bug and it's in the maven documentation here.

Regarding best practices on this issue, I haven't heard of any, but the safest way to proceed ought to be to entirely remove xstream from your pom, relying on the transitive dependency. Doing this will result in a build failure if the dependency to mylibrary is removed. This will act as a notification to you that you need to fix something. You won't silently loose required dependencies, and you won't silently have dependencies you no longer need.

On a side note, mvn dependency:analyze can be used to check for dependencies that are included but not used.

like image 195
Buhb Avatar answered Sep 28 '22 10:09

Buhb


As mattb's answer says, declaring the dependency as test scope overrides the transitive compile-scoped dependency declaration, and as a result the dependency is not included in your packaged war.

If you only need the dependency in your tests because 'mylibrary' needs it to execute, you shouldn't declare the dependency at all in your project's pom. Let the transitive dependency resolution process handle it.

If your project does use the xstream jar directly, you can still rely on the transitive dependency, as you will need a compatible version for your project and 'mylibrary' to both run against the xstream jar. You should have unit tests that exercise the functionality, and if mylibrary changes version of xstream to an incompatible version, your builds should fail, and you can address the issue at that point.

In general I'd say you should try to avoid declaring dependency versions directly in multi-module projects. I declare the versions in a dependencyManagement section of a parent POM so that the child need only declare the groupId/artifactId. Alternatively, from Maven 2.0.9 onwards there is an additional dependency scope of import:

This scope is only used on a dependency of type pom in the section. It indicates that the specified POM should be replaced with the dependencies in that POM's section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.

So using import scope you can define your common dependency versions in a single POM, import the dependencies of that POM into your dependencyManagement section, and just declare the groupId/artifactId of the dependency in your other POMs.

like image 24
Rich Seller Avatar answered Sep 28 '22 08:09

Rich Seller