Do maven plugins need dependencies? - maven

Does Maven install the necessary dependencies when adding a plugin to the pom file?
For example, when adding the following code to a pom file, does maven download the necessary dependencies for that plugin?
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>2.7</version>
</plugin>

Yes to both questions. Sub-dependencies are called Transitive Dependencies and are handled natively in Maven 2.0. You can read about it more on the Maven website.
Specifically:
Transitive dependencies are a new feature in Maven 2.0. This allows
you to avoid needing to discover and specify the libraries that your
own dependencies require, and including them automatically.
This feature is facilitated by reading the project files of your
dependencies from the remote repositories specified. In general, all
dependencies of those projects are used in your project, as are any
that the project inherits from its parents, or from its dependencies,
and so on.
There is no limit to the number of levels that dependencies can be
gathered from, and will only cause a problem if a cyclic dependency is
discovered.
With transitive dependencies, the graph of included libraries can
quickly grow quite large. For this reason, there are some additional
features that will limit which dependencies are included:
Dependency mediation - this determines what version of a dependency will be used when multiple versions of an artifact are
encountered. Currently, Maven 2.0 only supports using the "nearest
definition" which means that it will use the version of the closest
dependency to your project in the tree of dependencies. You can always
guarantee a version by declaring it explicitly in your project's POM.
Note that if two dependency versions are at the same depth in the
dependency tree, until Maven 2.0.8 it was not defined which one would
win, but since Maven 2.0.9 it's the order in the declaration that
counts: the first declaration wins.
"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies, eg. if
dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A
-> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter. You could explicitly add a
dependency to D 2.0 in A to force the use of D 2.0
Dependency management - this allows project authors to directly specify the versions of artifacts to be used when they are encountered
in transitive dependencies or in dependencies where no version has
been specified. In the example in the preceding section a dependency
was directly added to A even though it is not directly used by A.
Instead, A can include D as a dependency in its dependencyManagement
section and directly control which version of D is used when, or if,
it is ever referenced.
Dependency scope - this allows you to only include dependencies appropriate for the current stage of the build. This is described in
more detail below.
Excluded dependencies - If project X depends on project Y, and project Y depends on project Z, the owner of project X can explicitly
exclude project Z as a dependency, using the "exclusion" element.
Optional dependencies - If project Y depends on project Z, the owner
of project Y can mark project Z as an optional dependency, using the
"optional" element. When project X depends on project Y, X will depend
only on Y and not on Y's optional dependency Z. The owner of project X
may then explicitly add a dependency on Z, at her option. (It may be
helpful to think of optional dependencies as "excluded by default.")

If you take a look at the plugin pom
http://repo1.maven.org/maven2/org/codehaus/sonar/sonar-maven-plugin/2.7/sonar-maven-plugin-2.7.pom
Maven will pull all relevant dependencies for the plugin according to
<dependencies>
section of the plugin pom

Related

Depedency version inheritance more than one level

I've the following project structure A --> B --> C. I've given all dependent jars in dependencyManagement of Project A POM and version of those jars are maintained using property project.version. I was able to access the versions using property ${project.version} in B. But I'm not able to get the dependency version in Project C. Is there a way to inherit the dependency version in project C from project A?

What is the point of an exclusion of a dependency's dependency and re-declaring it?

I've noticed some pattern in projects's poms. There is a dependency graph like this: your Project A -> some other Project B -> B's dependency Project C. Project B is declared as a dependency in A's pom and B's dependency C excluded from B and re-declared as a direct dependency of project A. What is the point of this exclusion if Maven docs openly says it takes the "nearest" dependency, so if you declare it directly then Maven uses that version instead any of transitive ones?
You normally do this to change the version or scope of the dependency.
So you may exclude dependency to C from dependency to B, which leaves you without dependency to C. Now you add a direct dependency to C in A, with another version.
The documentation is still right, every artifact should declare what it directly needs. But in cases of conflicts the above pattern is the rescue.

How to exclude an artifact, which is used as transitive by several other dependencies, in one place

Our project has migrated from log4j to log4j2. However, other projects, which our project depends on, are still using log4j.
If I want to exclude log4j with exclusions, I need to add more than 10 exclusions on a single pom.xml and it is not practical.
Question: is there any way to say, it does not matter, from where it comes, exclude log4j from my project. It is like the exact opposite of adding dependency.
This not possible at POM level, as stated by official documentation
Why exclusions are made on a per-dependency basis, rather than at the POM level
This is mainly done to be sure the dependency graph is predictable, and to keep inheritance effects from excluding a dependency that should not be excluded. If you get to the method of last resort and have to put in an exclusion, you should be absolutely certain which of your dependencies is bringing in that unwanted transitive dependency.
If you have control over the other projects you depend on, then the concerned dependency should be declared as optional.
<dependency>
<groupId>com.sample</groupId>
<artifactId>project</artifactId>
<version>1.0</version>
<optional>true</optional>
</dependency>
Optional doesn't affect the project itself (it will keep on having this dependency) but it will not be considered as transitive dependency by dependent projects (hence, you will have the choice to ignore it or to re-declare it, if needed).
As from official documentation
Optional dependencies - If project Y depends on project Z, the owner of project Y can mark project Z as an optional dependency, using the "optional" element. When project X depends on project Y, X will depend only on Y and not on Y's optional dependency Z. The owner of project X may then explicitly add a dependency on Z, at her option. (It may be helpful to think of optional dependencies as "excluded by default.").
Afterwards, if you really want to make sure that the concerned dependency is not brought in by any dependency transitively, you could configure your build to ban it (the build would fail whenever the concerned dependency appears) using the Maven Enforcer Plugin and its bannedDependencies rule.

Maven build modules out of order

I am trying to build a maven project that has several modules. So I expect them to be built in the order given in the pom.xml ,but It can be seen that the order of the modules in build is not same as the order mentioned in the pom.xml file. What can be the reason for that ?
My Maven version : Apache Maven 3.0.4
Maven decides the order based on the dependencies. So if you have 3 submodules: A, B an C, you need to go into each submodule and make the dependency explicit. For example, if you go to the pom.xml of B and declare that it depends on A and C, maven will build A and C in some random order, and will build B at the end.
Order that you mentioned in the parent pom file is also relevant in the case when there is no dependency crash between modules , that means if any module present above in the list and it depends on the module that is below it , then in this case order mentioned in POM file won't be used , Maven will use his brain and first build all the modules that are going to need by some other modules to build.
For more on build order , please have a look at this question and Maven Spec on same.
From the specs :
Reactor Sorting
Because modules within a multi-module build can depend on each other,
it is important that The reactor sorts all the projects in a way that
guarantees any project is built before it is required.
The following relationships are honoured when sorting projects:
1. project dependency on another module in the build
2. plugin declaration where the plugin is another modules in the build
3. plugin dependency on another module in the build
4. build extension declaration on another module in the build
5. the order declared in the modules element (if no other rule applies)
Note that only "instantiated" references are used - dependencyManagement
and pluginManagement elements will not cause a change to the reactor
sort order.

Force transitive dependency version in Gradle

I'm playing around with gradle trying to port my maven project and here's my problem:
In maven we have the <dependencyManagement> which provides a common (default) version for certain dependencies (which is used only when in a sub-pom this artifact is used without a version number). It also, from what I understand, forces a certain version for all transitive dependencies. So if I understand correctly even if artifact B which we have as a dependency has a dependency on artifact C version 1.0 then we will still use a version of artifact C defined in the <dependencyManagement> (so it might be 2.0). Is that correct?
If so then is there a way to do something similar in Gradle? I know that a common way of replacing the <dependencyManagement> is to simply create a Groovy map in one of the build scripts. But how can I force the transitive dependency version? If I use Gradle's "force" won't it affect all (not only transitive) dependencies (which is obviously not what I want)?
In Gradle, forcing a version (e.g. with Configuration.resolutionStrategy.force) will force it for all dependencies of the configuration, direct and transitive. There is no first-class feature that forces a version only for transitive dependencies. Do you have a valid use case for this? At the end of the day, both Gradle and Maven will select a single version for a dependency anyway, no matter where and how often it appears in the dependency tree.
There is a ResolutionStrategy feature that allows forcing artifacts versions including transitive dependencies: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html
It is also possible to configure dependencies constraints: https://docs.gradle.org/current/userguide/dependency_constraints.html

Resources