I have a base project (common) and several projects (P1, P2, ...) dependent on common. All projects have some common dependencies such as JUnit. To avoid replicating the common dependencies, I put them in the common pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
P1 POM depends on common
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
When I add a JUnit test case to P1, eclipse shows "The import org.junit cannot be resolved". However, when I remove the "test" scope in common pom.xml for junit, the error is resolved.
Why doesn't maven handle the recursive dependencies correctly? What am I missing? Is there a better way to handle the common dependencies?
test scoped dependencies are never tranistive.
What you can do is split your common-dependencies into common-dependencies and common-test-dependencies.
Both contain all their dependencies in the compile (default) scope.
Now you include both dependency-helpers, but the test-dependencies themselves in test scope.
<dependency>
<groupId>com.example</groupId>
<artifactId>common-dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>common-test-dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>test</test>
</dependency>
A compile->test dependency chain resolves to a test dependency for the tranisitive dependency, so you are good to go.
The same technique can be used for the other scopes as well, if needed.
Two points of style:
if common includes own code as well, consider splitting it into the dependencies part and the common code part
If you use dependency-only pom projects, call them always *-dependencies, so they are easier to understand without looking into them
You can also use different approach using dependencyManagement:
(blackbuild's answer is certainly true, but not the only way to approach it and some people, like me, don't like to create separate module just to manage dependencies).
In root pom you define:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
...
</dependencies>
</dependencyManagement>
and in all sub-modules you refer to this dependency (version and scope are taken from parent pom.xml):
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
Related
According to the maven docs Dependency management
is a mechanism for centralizing dependency information.
and from this question here SO Question, many people suggested to use Dependency managmement instead of dependencies when we have a common jar file for all children.
as in dependency management , dependencies are propogated only when children request for it but incase of dependencies the dependecies are propogated even when not required.
but wouldn't it be a better approch when the jar file is common to all children ,i.e when all the children inherit the same jar file
for example (rewritten example taken from maven docs)
child a
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
</dependency>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
</dependency>
</dependencies>
child b
<dependencies>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
</dependency>
</dependencies>
parent of both a and b
<dependencyManagement>
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
but wouldn't this yeild the same result ??
parent of both a and b
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
child a
<dependencies>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
</dependency>
</dependencies>
child b
<dependencies>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
</dependency>
</dependencies>
or did i misunderstand them??
and which one should i use and in what conditions ??
Dependency management section in the parent pom is managing versions and only versions of these libraries, when you are using them in the child projects.
Dependency section on the contrary ENFORCES all child modules to have these dependencies, regardless child modules need them or not.
If you are sure ALL your child modules will use group-a:module-a:version, then feel free to declare it in parent dependencies section.
If you have at least one child module in the project, where such enforced dependency is unnecessary, then dependencyManagement better suites your need.
I am fairly new to maven's capabilities..
I have seen that in pom.xml where dependencies are put, at times, only groupID and artifact id are mentioned and version is skipped. why is this?
For example the below dependency is from springsource website http://spring.io/guides/gs/authenticating-ldap/
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-server-jndi</artifactId>
<version>1.5.5</version>
</dependency>
</dependencies>
But elsewhere in stackoverflow it was also mentioned that version is not optional. I would be glad if someone could explain this.
Yes, version is not optional.
Consider a multimodule application which has 10 modules, say module1, module2.. module10.Assume that all of these 10 projects use the spring-boot-starter-web. In case these 10 modules are interdependent, you might want to use the same version of the spring-boot-starter-web in each of these 10.
Now just imagine how complicated it would be if you were to maintain the same version number in all of these 10 pom files and then update all of them when you want to use a newer version of spring-boot-starter-web. Wouldn't it be better if this information can be managed centrally?
Maven has got something known a <dependencyManagement/> tag to get around this and centralize dependency information.
For the example which you have provided, below set of links will help you understand how the version number is resolved even though it's not present in the pom which you are looking at.
Look at the parent tag of the pom you are looking at (https://github.com/spring-guides/gs-authenticating-ldap/blob/master/complete/pom.xml)
Now lets go to that parent and see if the versions are specified in the dependencyManagement section of that pom(https://github.com/spring-projects/spring-boot/blob/master/spring-boot-starters/spring-boot-starter-parent/pom.xml). No it's not defined there as well. Now lets look at the parent of parent. https://github.com/spring-projects/spring-boot/blob/master/spring-boot-dependencies/pom.xml. Oh yea, we have got the version numbers there.
Similar to dependencyManagement, plugins can be managed in the pluginManagement section of the pom.
Hope that explains it.
Refer : dependencyManagement, pluginManagement
A few additions to the excellent answer by coderplus:
In a multi-module project, it is considered to be a good practice to configure the artifacts used by the project in the dependencyManagement of the root pom.xml so that you don't have to write versions in child module pom.xmls (like in some dependencies in your example).
It is also considered to be a good practice to declare versions of the external libraries that you use as properties and then use these properties in dependencyManagement/dependencies/dependency/version. This is more or less done here:
<properties>
<logback.version>1.1.2</logback.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
In a multi-module project, you should also declare your own artifacts in dependencyManagement.
But please do not write the version explicitly (like Spring people do here), use ${project.version} instead.
So it would have been better to write:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${project.version}</version>
</dependency>
instead of
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>1.2.0.BUILD-SNAPSHOT</version>
</dependency>
here.
The whole purpose is DRY, don't repeat yourself. The more redundant declarations you have in your POMs, the harder they can hit. Hunting for the obsolete dependencies is so much fun.
If the <version> isn't specified then the <version> of <parent> is used. If there is no <version> in the <parent> then the <version> in the <parent> of the <parent> is used. etc.
I'm working on a multi-module maven project called acme-platform, with the modules set up like so:
acme-admin
acme-common
acme-global
acme-services
acme-client
acme-registration
acme-properties
acme-test
(They are listed in this order in the acme-platform pom.)
In some of the modules, I have been able to use Spring's ReflectionTestUtils class. However, in the last module, acme-test, where I really want to use it, I am unable to. There was no dependency section in the acme-test pom, so I added one. Here is the pom:
<?xml version="1.0" encoding="UTF-8"?>
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>acme-platform</artifactId>
<groupId>com.awesomeness.acme</groupId>
<version>1.21.0</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>acme-test</artifactId>
<version>1.21.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
Before adding the dependency lines, I couldn't import any of Spring's api into my classes. After importing these lines, I was able to access most of the classes, but not all of them, and in particular not ReflectionTestUtils, even though it is part of the spring-test module (as can be verified here).
I am using Intellij. I have looked at answers to other questions (such as this one) to make sure I'm updating my dependencies correctly. To no avail.
Does anyone have any idea as to why I can't import org.springframework.test.util.ReflectionTestUtils into acme-test?
Let me know if you need any aditional information.
EDIT
The version information of the dependencies are not in any of the module poms, but they are specified in the root pom (acme-platform). Again, I can import ReflectionTest in the other modules, just not in acme-test. So I deduce from this that as long as the dependency is declared with a specified version in the root pom, it doesn't need a version specified in any of the module poms. (If I'm wrong on this, please correct me.)
ADDITIONAL EDIT
By the way, I can't import junit either.
You need to set the Maven scope to test for both the spring-test and junit dependencies.
For example:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
I'm declaring quite a few dependencies within one package in a Maven pom.xml, and the document is getting very long and difficult to maintain as is, even without a separate dependency block for each referenced artifact. Instead of doing this:
<dependencies>
<dependency>
<groupId>com.test.foo</groupId>
<artifactId>bar1</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.test.foo</groupId>
<artifactId>bar2</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.test.foo</groupId>
<artifactId>bar3</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>war</type>
</dependency>
</dependencies>
Is it possible (and I'd be willing to work with a plugin, if necessary) to do something like this:
<dependencies>
<dependency>
<groupId>com.test.foo</groupId>
<artifactId>bar1</artifactId>
<artifactId>bar2</artifactId>
<artifactId>bar3</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>war</type>
</dependency>
</dependencies>
No. But if you own those dependencies (I assume from your code that you do) you can have a module aggregating all those dependencies, then you can depend on that module. Or if working in a multi module project you can create a parent pom to define the dependencies from your project so you don't repeat it everywhere.
Well, I'm not talking about the well-known commons-logging problem, I know I can disable it by setting the 99.0-does-not-exist version.
My problems is, some packages are contained in different dependencies, say, aspectjlib is contained both in org.aspectj:aspectjlib and aspectj:aspectjlib. In some cases, transitive dependencies may introduce the two jars at the same time, while of different versions, e.g., org.aspectj:aspectjlib:1.7.3, aspectj:aspectjlib:1.6.1. And mis-loading aspectj:aspectjlib:1.6.1 accidentally is not my intention. So is there a way like commons-logging that I can disable aspectj:aspectjlib completely?
I tried the same trick using 99.0-does-not-exist, only to find an error from maven:
[ERROR] Failed to execute goal on project XXX: Could not resolve
dependencies for project XXX:jar:1.0.0-SNAPSHOT: The following
artifacts could not be resolved:
aspectj:aspectjlib:jar:99.0-does-not-exist,
aspectj:aspectjrt:jar:99.0-does-not-exist,
aspectj:aspectjweaver:jar:99.0-does-not-exist: Could not find artifact
aspectj:aspectjlib:jar:99.0-does-not-exist in tbmirror
(http://mvnrepo.taobao.ali.com/mvn/repository) -> [Help 1]
Well, although some repositories do provide 99.0-does-not-exist for logging system dependencies like log4j, slf4j-log4j, commons-logging, etc., this is not a universal solution.
I find a solution to do this: use 'provided' scope.
To clarify, in my example above, I have two conflicting dependencies: org.aspectj:aspectjlib:1.7.3, aspectj:aspectjlib:1.6.1, I want to disable aspectj:aspectjlib:1.6.1, I only need to put this in top-level pom:
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjlib</artifactId>
<version>1.6.1</version>
<scope>provided</scope>
</dependency>
in this way, aspectj:aspectjlib:1.6.1 will never appear in the final built lib.
You can use Maven's dependency exclusions to eliminate the version you don't want. Using your example:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>includes-new-aspectj</groupId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>includes-old-aspectj</groupId>
<exclusions>
<exclusion>
<groupId>org.aspectj<groupId>
<artifactId>aspectjlib</artifactId>
<exclusion>
</exclusions>
</dependency>
</dependencies>
Alternatively, you can simply pin the version you desire using dependency management:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjlib</artifactId>
<version>1.7.3</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>includes-new-aspectj</groupId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>includes-old-aspectj</groupId>
</dependency>
</dependencies>
If you are not sure which dependencies include which versions, you can use this to discover that info:
mvn dependency:tree -Dincludes='org.aspectj:aspectjlib'
There is no 99.0 version for aspectj:aspectjlib, your project is configured to use wrong version, check for 99.0 in your pom.xml