A problem that relates to basic maven concepts:
Once released I would like to have a guarantee that the project build is fully reproducible. So all project and plugin dependencies, including transitive one, should be always resolved the same way.
Unfortunately it is not the case, if dependencies are expressed in terms of version ranges. It can happen that even though direct dependencies of a project are set (using versions:use-releases), the transitive dependencies can still be resolved in some other way in the future.
How to address the problem? Is there a known solution?
I was thinking (just an idea), about creating a plugin, which on release time would dump all dependencies of the project to a separate file, and then once building in the future, the dependencies read from the file would take precedence over the standard way maven uses to resolve dependencies. But I'm afraid that there is no plugin api for that. So it would require some hacking, which I would like to avoid. Is there another way?
Thanks,
Lukasz
Freeze artifacts versions using <dependencyManagement>. Even if you don't use version ranges (as you said), but rather 3rd party libs (your dependencies) do, your <dependencyManagement> will have higher priority in specifying version of any artifacts.
The simple solution is: Do not use version-ranges. This is bad practice cause it will result in the described problems.
Related
I'm looking for information about Gradle dependencies, similar to this question:
What is the Gradle artifact dependency graph command?
but with a narrower scope. I'm wondering about functionality that Maven has for analyzing dependencies, and whether or not Gradle includes something similar. Specifically, Maven can scan your source code and then compare that to your declared dependencies, and determine (roughly) if you have dependencies declared that you aren't using and/or if you're using dependencies that you haven't declared (due to issues related to Turing completeness, this analysis may include false positives/negatives, but I generally find it to be incredibly useful regardless). Does Gradle have anything similar? So far I haven't been able to find anything.
Such a thing is not shipped with Gradle at least as far as I know.
You best bet is to search through Google and / or plugins.gradle.org for finding a plugin that does what you want.
I for a short period did this for you and found this one which might be what you want: https://plugins.gradle.org/plugin/com.intershop.gradle.dependencyanalysis
I have no idea about its quality or anything, I just searched through plugins.gradle.org, I don't know or ever used that plugin.
I understand Maven's behavior whenever it finds more than one version of the same dependency is to choose the one closer to the dependency root. If more than one are same as close, then it will choose the first one it finds.
Is there a way to change this behavior and make it simply pick the highest version?
The versions plugin can do some of the work for you, by rewriting your POM, but I highly recommend avoiding using it. Explicitly managing dependencies as gogstad and Michael stated is the recommended path.
Add a dependency management section and pick the version you actually want to use. You should always be setting versions so you're getting repeatable builds.
No, it's not possible to change the maven dependency mechanism to anything other than nearest definition.
If you experience that maven chooses the wrong dependency, the only way to fix it is to explicitly depend on that dependency in your application (maven will of course not allow two different versions of the same dependency in the clasdpath at the same time). The dependency you define will be used in any transitive dependencies for the same artifact.
The project I'm working on has dependencies on a few well known and big libraries. Things are working well, the transitive dependencies are playing nice with each other, for now. But unfortunately the total bundle size is around 100 megs.
I'm not sure if this is too large or not, but is there a way in maven to effectively remove dependencies, without making pom.xml very verbose and long?
And pointers to help me in the right direction would be awesome!
You can remove dependencies by declaring exclusions. The question I would post to first though is .. why do you want to remove them?
Unless you know that the dependencies are not needed, it might not make sense to try to remove them. Especially not if there are no issues e.g. in terms of application performance or startup times.
The Maven Dependency Plugin as well as the Eclipse integration have tools that allow you to understand the dependencies better with tools like the dependency:tree goal or the Dependnecy Hierarchy view of the POM.
Don't try to fix something that is not broken.
BUT ..
if you really know what is needed at runtime and use the tooling from Maven and M2e you can potentially remove a lot of bulk of your final artifact. However you will have to configure it in the pom using dependency exclusions. Newer Maven versions even allow patterns being used.
Another thing you can do is use a tool like proguard that removes all unused classes from the final artifact. This can be considerably complex but also VERY effective.
It will really be up to you to find the right balance between effort and benefit of outcome.
I had a situation in my project where two dependencies relied on a different version of a jar. Just showing the dependency tree only showed the newer version and where it was used, so I ended up going through the POM files (I had an idea where it might be) to find the source.
My question: is it possible to get a dependency tree that includes these dependencies that were removed (showing why they were removed). I seem to recall the m2eclipse plugin can do it, but I'd prefer a command line tool (since I'm not using eclipse).
edit:
Specifically, I already tried the dependency tree, including running with full debug output (-X). As far as I could tell, it doesn't show when it's masking these dependencies.
Just try the maven-dependency-plugin use the tree goal to look at the tree of dependencies. But it might be a good idea to use Eclipse via m2e plugin for such problems.
When there is a conflict in the dependency tree (same artifact but different versions) then, AFAIK, Maven will resolve the conflict by selecting the highest version of the dependency and will omit the 'old' ones.
However, when the newer version is a SNAPSHOT then apparently it will choose the older stable version over the SNAPSHOT.
In my case: some-artifact: 0.5.0-SNAPSHOTS (omitted for conflict with 0.4.0) => version 0.4.0 is picked over the wanted 0.5.0-SNAPSHOT.
I assume this functions as designed but I don't understand the reason why. Next to that, any idea if there is a way to tell Maven to take the SNAPSHOT over the stable version?
Your assumption about Maven's always selecting the highest version isn't accurate. Artifacts are chosen based on a number of factors including depth of the dependency in the tree, order in the tree, whether the dependency is a snapshot or a release, and dependency management, which pretty much overrides everything else.
Unfortunately, I don't know of any one, definitive source of information on Maven's dependency resolution algorithms. You'll find bits and pieces of it scattered all over. A few handy references:
Introduction to the Dependency Mechanism gives an overview of the topic with a good, if short, section on Transitive Dependencies and how they're selected from a dependency tree.
The Sonatype Maven book has a more thorough section on Project Dependencies in general that will add a lot to your knowledge about the subject.
An earlier section of that same book discusses Project Versions, which is strongly related to this problem and has a good section on SNAPSHOT versions, though not as much as I could wish on how they play into dependency resolution.
Project Relationships talks about the coordinate system and how project inheritance affects what dependencies get included.
Finally, the POM Reference is a good jumping-off point for almost anything to do with the pom. There's at least a brief description of every pom element that can help you understand enough to be able to begin searching for more info effectively.
As for some practical advice, the output of mvn dependency:tree is highly useful in discovering why a particular version of a dependency was chosen. It'll often even tell you something like "foo:bar:1.2 (was 1.1)". Once you figure out where the errant version is coming from, there are a number of ways to ensure a specific dependency version is used for a project:
Exclude wrongly-versioned dependencies from other dependencies that are causing them to be included in the build.
Add an explicit top-level dependency to your pom instead of relying on a transitive dependency.
List the dependency in the dependencyManagement section of your pom (scroll down a bit from this link) to force the dependency to have the specified characteristics, regardless of what level of transitive dependency it is. Use this option with care, as dependencyManagement is viral, in that other projects depending on your project will be "infected" with your dependency management. There's also a good section on dependency management in the pom reference.
If the 0.4.0 version is being pulled in as a transitive dependency via another dependency in your POM, then you should be able to exclude it. The dependency:tree goal should help you see if this is what's happening.
Maven is designed to favor release versions over snapshot versions. I'm not sure why you would have two dependencies in the same POM and not be able to resolve a conflict by removing one, so I will assume that one of the dependencies is inherited from a parent pom. In this case you can set the inherited dependency as <optional>true</optional> and I THINK it should allow the child POMs to override it, even with a lower version.
bad/hacky solution for if that doesn't work - edit your local repository in such a way that it doesn't realize the 0.5.0 version is a snapshot (or even edit your private nexus repo if you have the ability)