I usually put a <dependencyManagement> section in parent-project/pom.xml. This <dependencyManagement> section contains declaration and version for all dependencies of my children modules like this (i.e. without the <scope> element):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
</dependencyManagement>
In all children modules (i.e. moduleX/pom.xml), I have:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Obviously, in this example I'm repeating the <scope>test</scope> multiple times for the same dependency (once in every child module needing junit).
My question is:
What are the best practices regarding <scope> declaration?
Is it better to put it in the <dependencyManagement>?
Or is it better to put it in the <dependencies> section of the child module (like in this post)? And why?
Is there any definitive answer to this question?
A little late to the party, but I'll add my two cents.
I recently ran into a very difficult to debug issue.
I have a parent pom for managing dependencies across multiple projects. I had it set with all the dependencies common amongst them and included groupId, artifactId, version and the most common scope.
My thinking would be that I would not have to include scope in the actual dependency section in each project if it fell in line with that most common scope.
The problem occurred when some of those dependencies showed up as transitive dependencies. For example, if:
A depends on B at compile scope.
B depends on C at compile scope.
C is set to provided in dependencyManagement of parent.
Then A's transitive dependency on C is determined to be provided. I'm not really sure if that makes sense or not, but it certainly is confusing.
Anyway, save yourself the hassle, and leave scope out of your dependencyManagement.
dependencyManagement is just here to define dependencies version for all project submodules, the only pertinent scope in this section is import for BOMs.
Scope must be defined in dependencies section.
(For a given dependency it determines the usage context. It allows to include the dependency only when it is required for execution. For example an ear will not be packaged with Java-ee dependencies (scope provided) as it will find them on the target server.)
[edit]
The first statement has an exception, the scope provided in dependencyManagement section will override defined scope in dependencies sections. see DependencyManagement to force scope
As with other answers, best practice is to exclude scope from dependencyManagement and explicitly specify it when defining the dependency. It is a rare case that you would want a different version of the same dependency in different scopes, e.g., one version when compiling your app and a different when running it -- the only case I can think of is you want to explicitly run your tests against a different version of a library in case users use that version instead of the one you specify.
If you define scope in dependencyManagement, it restricts the use of that version to ONLY the defined scope -- so any other scopes will pick up a random version of the dependency. I ran into this yesterday when we had defined junit 4.12 in dependencyManagement with test scope, but our common test framework module used junit with compile scope, so it picked up version 4.8.2 instead.
There is no gain in adding a single dependency to the dependency management, for any scope. All you have is the duplication. If you want to have the version configurable, add a property and use it in your dependency:
<properties>
<junit.version>4.10</junit.version>
...
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
However, there are cases where the dependency management shines - when you are using boms in order to orchestrate the versions for a larger collections of artifacts, like using a certain version of a Java EE implementation:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.bom</groupId>
<artifactId>jboss-javaee-6.0-with-tools</artifactId>
<version>${javaee6.with.tools.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
....
super late to the party, but the latest maven has very clear documentation on the transitive dependency scope and dependencyManagement details, including one example.
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#dependency-scope
from the documentation we can see:
when transitive scopes are different, there are precedence rules governing which one will be applied. At the first glance the rules table is complicated, but it makes common sense for most cases.
the documentation specifically has an example of dependency scope and dependencyManagement combined case. ultimately it follows the rules specified in 1.
As a conclusion, it's recommended to include scope in the most 'common' ways. If there are transitive, conflicting or cornered cases, we need to carefully check the precedence rules.
Related
i am interested in understanding maven scopes during build life cycle.
i understood that working with a dependency, like this one :
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
the javax.servlet-api jar will not be included in the final executable jar,
because the server is supposed to already possess the dependency.
ok, but how does it work ?
where is physically the util jar ? (javax.servlet-api.jar)
last question :
when we build a jar, how can we be sure the dependency can be tagged as provided scope,
so that the server already has it, for the run ?
It is actually up to you to make that sure. Maven does not know about it.
So if you know that your server provides certain dependencies (e.g. because you read the server manual), then you can mark them as provided.
I want to use a library that has the following dependency:
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>2.0.3</version>
</dependency>
I read that FindBugs is for static analysis of Java code, so I though it isn't necessary to include in application. Is it safe to exclude the jar with <scope>provided</scope> or with an <exclusion>...</exclusion>?
One reason to exclude it is that there is a company policy against (L)GPL licence.
Yes, you can safely exclude this library. It contains only annotations which do not need to be present at runtime. Take care to have them available for the FindBugs analysis, though.
Note that you should also list jsr305.jar, like this:
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>3.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
<scope>provided</scope>
</dependency>
Both JARs are required to make these annotations work.
Check the most recent findbugs version in Maven Central.
FindBugs is provided under the LGPL, so there should not be any problems for your company. Also, you are merely using FindBugs; you are not developing something derived from FindBugs.
In theory, it should be entirely safe (as defined in the OP's clarifying comment) to exclude the Findbugs transitive dependency. If used correctly, Findbugs should only be used when building the library, not using it. It's likely that someone forgot to add <scope>test</scope> to the Findbugs dependency.
So - go ahead and try the exclusion. Run the application. Do you get classpath errors, application functionality related to the library that doesn't work, or see messages in the logs that seem to be due to not having Findbugs available? If the answer is yes I personally would rethink using this particular library in my application, and would try to find an alternative.
Also, congratulations on doing the classpath check up front! As a general practice, it is a great idea to do what you have done every time you include a library in your application: add the library, then check what other transitive dependencies it brings, and do any necessary classpath clean-up at the start. When I do this I find it makes my debugging sessions much shorter.
I have an Ancestor dependency has dependent scoped as provided, I need to propagate that scoping to anything that depends on my project.
For example, say I have SomeProjectA which depends on SomeLibraryB. I need to scope SomeLibraryB has provided.
Currently to compile anything that depends on SomeProjectA, has to also set SomeLibraryB has provided. I would rather propagate that scoping, then have any project that depend on mine deal with my project's dependents..
I dont think that is possible. Each project should declare provided dependencies on its own. Propagating that scope would be wrong since you would make an assumption about the deployment that you cant make since you are not responsible for the deployment. The user of your library does that..
Simple hack
This can be achieved by a simple hack.
You can exclude SomeLibraryB and SomeLibraryC inside your direct dependency tag.
Below is the dependency tag for your SomeProjectA.
<dependency>
<groupId>org.direct.dependency</groupId>
<artifactId>SomeProjectA</artifactId>
<exclusions>
<exclusion>
<groupId>org.some</groupId>
<artifactId>SomeLibraryB</artifactId>
</exclusion>
<exclusion>
<groupId>org.some</groupId>
<artifactId>SomeLibraryC</artifactId>
</exclusion>
</exclusions>
</dependency>
But if you have this configuration, your tests and compilation other validations will starts to fail. Therefore, you can put direct dependencies to those libraries with <scope>test</scope>.
<dependency>
<groupId>org.some</groupId>
<artifactId>SomeLibraryB</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.some</groupId>
<artifactId>SomeLibraryC</artifactId>
<scope>test</scope>
</dependency>
As you can see from the Maven documentation, the provided scope doesn't influence compilation, but runtime. In general you should only need to specify the provided scope in the dependencies for a packaging project, such as a project of type war. For this reason it doesn't usually matter much that it isn't transitive.
In other words, if you add a dependency to a jar project without explicitly specifying its scope, that dependency will be made available during compilation and so will that dependency's dependencies. If you then explicitly declare that dependency to have provided scope, this does not change.
I have a dependency that I want to use in test scope (so that it is in the classpath when I am running unit tests), and in runtime scope (so that I can contain that in WAR/EAR/other packaging for deployment, but not affecting transitive dependency lookup for dependent artifacts).
A real life example is SLF4J's implementation JARs (e.g. Logback). I want it to exist in the classpath when I am running tests, and I want it to be included in my WAR/EAR, but I don't want project depending on my project to include that in transitive dependency lookup.
I tried to use <scope>test,runtime</scope> but Maven 3 produces a warning:
[WARNING] 'dependencies.dependency.scope' for org.slf4j:jcl-over-slf4j:jar
must be one of [provided, compile, runtime, test, system] but is 'test,runtime'.
What is the right way for declaring the dependency scope in such a case?
The runtime scope also makes the artifact available on the test classpath. Just use runtime. (See the Maven documentation.)
To avoid having the dependency resolved transitively, also make it optional with <optional>true</optional>:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback</artifactId>
<version>0.5</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
You can only define one scope value per <scope/> tag.
I'm afraid what you'd like to do cannot be achieved by merely using a scope. If you define a scope of test, it will only be available during tests; if you define a scope of provided, that would mean that you would expect that dependency for your project to be resolved and used during both compilation and tests, but it will not be included in your WAR file. Either way, it's not what you would want.
Therefore, I would recommend you have a look at the maven-assembly-plugin, with which you can achieve it, but it will still require some playing around.
Not sure if this would still help someone who is still looking for a simple way to do this - https://howtodoinjava.com/maven/maven-dependency-scopes/ this link helped me add the correct scope. Here is the summary of mapping of scopes and the phases where we need the dependencies.
compile - build, test and run
provided - build and test
runtime - test and run
test - compile and test
So, when I needed the dependency during test and runtime, I gave the scope as "runtime" and it worked as expected.
Declaring a dependency with a scope of runtime ensures that the library is not available during compile time.
Declaring the dependency as optional causes a break in the dependency resolution process; projects depending on your libraries will need to explicitly include the dependencies themselves.
So the correct way to declare this would be:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.13</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
In eclipse I've installed m2e plugin. I am trying to understand how do you know the names of properties for dependencies to add to pom file?
Say for instance how do you know which artifact id to use?
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
why here say aspectjrt in artifact id?
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
and here same as group id ??
is there any pattern?
say my project is missing
org.hibernate.Query;
org.hibernate.Session;
org.hibernate.SessionFactory;
and in maven dependencies folder I have hibernate-core-3.6.0.Final.jar which effectively contains everything except those 3.
Do you write these .pom yourself?
I am betting that for student project I will have to stick with manually adding hundreds of libraries... otherwise I will fail trying to learn it :-)
You know what groupId:artifactId:version (we call these coordinates) to use by which artifact you want. Most often, you find out which artifact you want by reading it in the project's documentation, especially for projects with a large number of artifacts, some of which might contain optional addons.
aspectjrt is short for AspectJ RunTime.
GroupId and artifactId are defined by the creators of the library in question. There's no universal pattern because there's no one central coordinator. There are some conventions that have evolved, though. Generally, the groupId is at least partly the reversed domain name, like the first part of a Java package name is: org.hibernate, org.apache, org.springframework... The artifactId distinctly identifies the role of that particular artifact in the group it belongs to, like spring-core, spring-tx, spring-jms, etc. You can get an idea of what groupId's and artifactId's look like by searching Maven Central for some of the libraries you know.
If you're missing org.hibernate.SessionFactory, then you don't have hibernate-core-3.6.0.Final on your classpath. If you have that on your classpath, then you're not missing the SessionFactory class. Those three classes you mentioned are most definitely in that artifact, as you can see from searching for the class in Central. If you still doubt, do a jar -tf hibernate-core-3.6.0.Final.jar and check out the contents yourself. I promise it has those classes.