I have a maven (3) project with multiple submodules. One on of them, I want it to explicitly depend on a dependency, without depending on its transitive dependencies. To do this, I'm using the folloing:
<dependency>
<groupId>org.example</groupId>
<artifactId>foo</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
This works as itended. During runtime, the transitive dependencies of "foo" will already be in the classpath, so everything goes well.
However, I need "foo"'s transitive dependencies for test. I tried to also declare a dependency of "foo" with scope test, but it seems that it conflicts with the one that excludes everything. It either works as expected in tests but fails in runtime, or vice-versa.
Do you known if something like this is possible with maven?
Of course it's possible, you need to declare 2 different maven profiles holding your dependencies.
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
Different dependencies for different build profiles in maven
You should check out Maven's <scope>import</scope> dependencies. Create a <profile/> for testing and define a dependency to a pom which contains these test dependencies you're interested in. (This might require some re-working of your pom.xml-s, but would be a good approach).
Check here for more details.
Related
When I look at my local Maven cache (~/.m2/repository/) I see 10-20 versions of certain artifacts, some of which are being used for only a single specific build (project). I would like to get rid of this duplication (true, they are different versions, but I'd still think a depending project would be able to tolerate a micro or minor version difference) and to somehow ask Maven to resort to the closest available version during dependency resolution, if a specific artifact version is missing in the local repository.
For example, if I have versions 1.0.0, 1.1.2, 1.4.0 and 2.0.0 of a foo:bar artifact in my local cache, I would like Maven to:
use 1.1.2 for a build requiring 1.1.0
use 1.4.0 for a build requiring 1.4.10
use 2.0.0 for a build requiring 2.5.0
without having to manually change the pom of the specific build(s).
I am fairly aware of the risks associated with switching dependency versions without proper analysis, and I'm only asking for a mechanism to be utilized for non-critical builds (such as a tool/library that I just cloned off a VCS, and would like to run and try out), preferably activated only when a particular flag is provided.
Is there something out there, like a Maven extension or plugin (that can be applied on a system-wide scale, and activated on demand with a flag), that can help me achieve my goal?
P.S.: Since the definition of "closest" could be ambiguous (given the fact that Maven may not know which of 1.4.0 and 2.0.0 is closer to 1.5.0 depending on the actual release versions lying between them), it would even be sufficient if I can specify the version on the build command (e.g. mvn package -Dfoo:bar=1.4.0), still without making any manual pom changes. (While this may already be possible for versions that have been specified as <properties> entries, I would like a generic solution where even hard-coded versions in transitive dependencies could be overridden.)
P.P.S.: Please note tht the project(s) that would be built would not have been authored/composed by me, so I don't really have control/authority over their actual pom files. What I'm looking for is a way to override dependency versions in their pom files without doing any manual modifications at source level.
In order to change a transitive dependency, you need to exclude the transitive dependency in your direct dependency, then add a direct dependency in your pom.
For example, if you have a dependency on foo.jar (which depends on xyz.jar version 1.3) and on bar.jar (which depends on xyz.jar version 1.4), you can have these two sections in your pom:
<!-- Define the version(s) that you allow your dependencies to depend on. -->
<dependencyManagement>
<dependency>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
<version>[1.0,2.0)</version>
</dependency>
<dependency>
<groupId>projectFoo</groupId>
<artifactId>foo</artifactId>
<version>1</version>
<exclusions>
<exclusion>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>projectBar</groupId>
<artifactId>bar</artifactId>
<version>5</version>
<exclusions>
<exclusion>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencyManagement>
...
<!-- Declare your dependencies but don't allow them to suck in their transitive dependencies. -->
<dependencies>
<dependency>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</dependency>
<dependency>
<groupId>projectFoo</groupId>
<artifactId>foo</artifactId>
</dependency>
<dependency>
<groupId>projectBar</groupId>
<artifactId>bar</artifactId>
</dependency>
</dependencies>
...
This will pick up the most recent version of xyz.jar that it can, and that will be the only version used. When foo and bar use xyz, they'll have the version that you've allowed into your project.
The best thing to do is to use a parent pom (or bom: bill of materials) with a well-defined and well-maintained dependencyManagement section. Stick with a single version of everything, just share that "everything" between all projects. You can override versions in projects if you need to.
If you'd rather define versions in each project, then version ranges will work. For the three examples you gave, you would use things like:
[1.1.0, 1.2)
[1.4.0, 1.5)
[2.0.0,)
(Open to correction here.. I haven't used version ranges in almost 10 years.)
Finally, to get it to use versions that are already available, rather than download the best ones, all you can do is to use a local artifact repository as your central maven repository, and turn off access to maven central and bintray.
Closest thing I found so far: https://github.com/jboss/maven-dependency-management-extension/blob/master/README.md
It can be dropped into ${MAVEN_HOME}/lib/ext and utilized for overriding versions of specific dependencies, e.g. mvn install -Dversion:junit:junit=4.10. While it doesn't offer the suggested "intelligent version derivation" approach, it's a good-enough solution.
I have a large Maven project with many modules and many pom.xml files. The project has changed and I suspect the pom's contain some unnecessary dependencies. Is there is a command which removes any unused dependencies from a pom?
The Maven Dependency Plugin will help, especially the dependency:analyze goal:
dependency:analyze analyzes the dependencies of this project and determines which are: used and declared; used and undeclared; unused and declared.
Another thing that might help to do some cleanup is the Dependency Convergence report from the Maven Project Info Reports Plugin.
You can use dependency:analyze -DignoreNonCompile.
This will print a list of "used undeclared" and "unused declared" dependencies (while ignoring runtime/provided/test/system scopes for unused dependency analysis.)
But be careful while using this:
As some libraries used at runtime are considered unused!
For more details refer to this link
As others have said, you can use the dependency:analyze goal to find which dependencies are used and declared, used and undeclared, or unused and declared. You may also find dependency:analyze-dep-mgt useful to look for mismatches in your dependencyManagement section.
You can simply remove unwanted direct dependencies from your POM, but if they are introduced by third-party jars, you can use the <exclusions> tags in a dependency to exclude the third-party jars (see the section titled Dependency Exclusions for details and some discussion). Here is an example excluding commons-logging from the Spring dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.5</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
Have you looked at the Maven Dependency Plugin ? That won't remove stuff for you but has tools to allow you to do the analysis yourself. I'm thinking particularly of
mvn dependency:tree
I had similar kind of problem and decided to write a script that removes dependencies for me. Using that I got over half of the dependencies away rather easily.
http://samulisiivonen.blogspot.com/2012/01/cleanin-up-maven-dependencies.html
You can use DepClean https://github.com/castor-software/depclean/
DepClean is a tool to automatically remove dependencies that are included in your Java dependency tree but are not actually used in the project's code.
You can use dependency_cleaner https://github.com/junaidbs/dependency_cleaner
This jar will help to identify and remove unwanted dependency from pom.
It will automate the process of Removing a dependency and run then check whether the dependency needful
If you are using eclipse, right-click on the jar in Maven Dependencies:
Select Maven -> Exclude Maven Artifact...
I thought that the order of Maven dependencies doesn't matter before and regard this as a pro of it. And this is my old pom.xml's dependencies:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.19</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.19</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.19</version>
</dependency>
</dependencies>
It works well, and today I wanna move spring dependency to the bottom so that those jersey related can be together. However then I can no longer make it working, my Jetty complains:
[ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.3.0.M1:run (default-cli) on project mtest: Execution default-cli of goal org.eclipse.jetty:jetty-maven-plugin:9.3.0.M1:run failed: A required class was missing while executing org.eclipse.jetty:jetty-maven-plugin:9.3.0.M1:run: org/apache/commons/logging/LogFactory
That is really confusing, so do I have to concern about dependencies order? How do I know the correct order?
The order of dependencies does matter because of how Maven resolves transitive dependencies, starting with version 2.0.9. Excerpt from the documentation:
(...) this determines what version of a dependency will be used when multiple versions of an artifact are encountered. (...) You can always guarantee a version by declaring it explicitly in your project's POM. (...) since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins.
To expand upon the other answer (which states that the declaration order affects Maven's dependency mediation for transitive dependencies), there are a few tools you can use:
mvn dependency:tree [-Dscope=[runtime|test]] will show you what dependencies will be available for the selected scope. See here for details
mvn dependency:build-classpath gives you order in which dependencies are available on your classpath (if two or more classpath entries have the same class, the earlier one wins). See here for details
I don't know much about your situation, but it's often the case that you wind up with the wrong version of 1 or more jars at compile/runtime. Declaring your own version of the library in question or locking down the version with <dependencyManagement> are options here.
Now to answer your other question - how do you know what the right order is when declaring dependencies?
My suggestion - the right declaration order is the one that gets you the versions of the dependencies you want, in the order you want them in. Use the tools above to check your dependencies, and tweak the declared order if necessary.
Note that most jars contain disjointedly-named classes, so the exact order in which jars appear on your classpath is usually not that important. The only exception I've noticed is some jars in SLF4J which intentionally shadow classes from the other logger libraries it's intended to replace.
I'm declaring a test dependency on powermock with easymock bundled in.
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<version>1.4.12</version>
<type>pom</type>
<scope>test</scope>
</dependency>
When I run mvn test, the test src claims to be able to find org.powermock but not org.easymock, despite it being included in the above dependency.
I wondered whether it was a problem due to transitivity of the test scope, so i tried compile scope also (as the documentation http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html mentions that the compile dependencies are available at test time) without any luck.
I've also tried using a bundled jar instead of pom, to no avail. I realise i could declare the dependencies separately (ie separate dependencies for powermock and easymock) but for my purposes i'm restricted to having just the one dependency including all necessary test libs.
Tracing this back to the powermock parent pom I see that the easymock dependency is marked "provided."
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.1</version>
<scope>provided</scope>
</dependency>
Looks like powermock is expecting its clients (you in this case) to supply the easymock jars.
According to the powermock-easymock-release-full POM, it does not depend on easymock (ie easymock does not appear in the powermock-easymock-release-full dependencies). So you'll have to add another dependency to easymock, dependending on the test engine you're using (JUnit or TestNG): http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.powermock%22%20AND%20%22easymock%22
I have a large Maven project with many modules and many pom.xml files. The project has changed and I suspect the pom's contain some unnecessary dependencies. Is there is a command which removes any unused dependencies from a pom?
The Maven Dependency Plugin will help, especially the dependency:analyze goal:
dependency:analyze analyzes the dependencies of this project and determines which are: used and declared; used and undeclared; unused and declared.
Another thing that might help to do some cleanup is the Dependency Convergence report from the Maven Project Info Reports Plugin.
You can use dependency:analyze -DignoreNonCompile.
This will print a list of "used undeclared" and "unused declared" dependencies (while ignoring runtime/provided/test/system scopes for unused dependency analysis.)
But be careful while using this:
As some libraries used at runtime are considered unused!
For more details refer to this link
As others have said, you can use the dependency:analyze goal to find which dependencies are used and declared, used and undeclared, or unused and declared. You may also find dependency:analyze-dep-mgt useful to look for mismatches in your dependencyManagement section.
You can simply remove unwanted direct dependencies from your POM, but if they are introduced by third-party jars, you can use the <exclusions> tags in a dependency to exclude the third-party jars (see the section titled Dependency Exclusions for details and some discussion). Here is an example excluding commons-logging from the Spring dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.5</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
Have you looked at the Maven Dependency Plugin ? That won't remove stuff for you but has tools to allow you to do the analysis yourself. I'm thinking particularly of
mvn dependency:tree
I had similar kind of problem and decided to write a script that removes dependencies for me. Using that I got over half of the dependencies away rather easily.
http://samulisiivonen.blogspot.com/2012/01/cleanin-up-maven-dependencies.html
You can use DepClean https://github.com/castor-software/depclean/
DepClean is a tool to automatically remove dependencies that are included in your Java dependency tree but are not actually used in the project's code.
You can use dependency_cleaner https://github.com/junaidbs/dependency_cleaner
This jar will help to identify and remove unwanted dependency from pom.
It will automate the process of Removing a dependency and run then check whether the dependency needful
If you are using eclipse, right-click on the jar in Maven Dependencies:
Select Maven -> Exclude Maven Artifact...