'Limiting a transitive dependency to runtime scope in Maven
I've got 2 projects using Maven. The first one is a library containing utility classes and methods. The second project is an actual application that has the library as a dependency. My library uses internally a third-party library.
So these are the dependencies:
- My library: depends on the third-party library
- My application: depends on my library
However, I don't want the third-party library classes to be available at compile time in my application. This is because the application is supported by a large team and I want to prevent people from accidentally using methods from the third-party library in the application given that some class names and some method names are similar between the two. Of course the third-par ty library will have to be available in my application at runtime.
If the scope for all my dependencies was compile, it wouldn't achieve my goal. Is there a way to achieve this in Maven 3?
Solution 1:[1]
Very good question and unfortunately you can't do this using Maven 3, or 2, or any other version, because of its fundamental design. What you're asking about is actually a desired and ideal behaviour since in fact any artifact's compile
dependencies should be transitive with runtime
scope. However, design like this leads to some problems. As you can read at Maven's Introduction to the Dependency Mechanism about compile
scope:
It is intended that [transitive dependencies of a compile dependency which are themselves compile dependencies should be considered] runtime scope instead, so that all compile dependencies must be explicitly listed - however, there is the case where the library you depend on extends a class from another library, forcing you to have available at compile time. For this reason, compile time dependencies remain as compile scope even when they are transitive.
So, as you see, what you require is actually the proper design of this behaviour which is unfortunately impossible to implement.
Solution 2:[2]
Nothing has changed during the last three years, so Michal's answer is still correct: There is no way to limit transitive visibility in Maven.
However, you should consider redesigning your library to split it in an api-artifact that is necessary as compile time dependency and which itself does not depend on the third party library and an implementation artifact which is only needed as runtime-dependency and which depends on the third party library.
Solution 3:[3]
In your application, you can declare an explicit dependency on the third-party library using "runtime" scope.
This prevents the third-party library from being seen at compile time and thus no direct usages can sneak in. However, it will still be present at run time (since it is needed by your library).
This works, but is awkward and deserves an explanatory XML comment in the pom.
Solution 4:[4]
The other answers are correct. Besides working around around a missing crucial feature in maven by splitting out an artificial API-only module, you also have these alternatives:
- exclude the transitive dependencies, then depend on them directly (you have to manage the version numbers yourself)
- Use checkstyle import control, and CI. That way team members may use the transitives, but then maven verify will fail
- Use gradle. This is a solution to many limitations of Maven
Solution 5:[5]
What seems to work is use <dependencyManagement>
section in the pom.
You will want to check for any side effects, since it works project wide. And you have to specify each library specifically.
Following code sample allowed me to force guava (which was smurfed in the project by google guice as a compile time transitive dependency) to a runtime dependency everywhere.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
Solution 6:[6]
You can analyze dependencies with: mvn dependency:analyze
or have the dependencies analyzed as part of the verify lifecycle phase:
https://maven.apache.org/plugins/maven-dependency-plugin/examples/failing-the-build-on-dependency-analysis-warnings.html
Solution 7:[7]
You can try like that:
#My application pom.xml
<dependencies>
<dependency>
<groupId>My groupId</groupId>
<artifactId>My library</artifactId>
<version>${version}</version>
<exclusions>
<exclusion>
<groupId>third-party library</groupId>
<artifactId> third-party library</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>third-party library</groupId>
<artifactId> third-party library</artifactId>
<version>${version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | xdhmoore |
Solution 2 | Reto Gmür |
Solution 3 | Sam Brow |
Solution 4 | tkruse |
Solution 5 | rolve |
Solution 6 | Eduardo |
Solution 7 | Sk C |