Use gradle dependency locking & version ranges in local library - java

I just started using dependency locking with version ranges (e.g. latest.release, 2.+, etc.) in one of my Java projects. To simplify, let’s say it has a structure like this:
:root:lib1
:root:project1
:root:project2
where lib1 is shared by the other 2 subprojects.
I started using dependency locking in :root:project1 and everything works as intended. :smiling_face_with_three_hearts:
Then I started using dependency locking with version ranges in :root:lib1. e.g. I would define a dependency like so: implementation software.amazon.awssdk:sqs:latest.release and then lock it to a version, say 1.0.0. This works fine with the first project since I generate a separate lockfile for that project, which constrains the version of the library to whatever value is in that file.
However, in project2, I have not yet switched to dependency locking, and I see that it’s pulling in transitive dependencies as version latest.release instead of 1.0.0 (the value in the lockfile for the library), which resolves to different version day to day.
project2 declares a dependency on lib1 using the project annotation
implementation project(':root:lib1')
Do I need to publish the lib1 jar and consume a specific version of it in order to get the locked transitive dependencies? Or is there a way to transitively bring the locked versions from lib1 instead of the latest.release value? Any help is much appreciated :slight_smile:
Currently using Gradle version 7.4.2

Related

How to update package version in external libraries

I want to update this package's version, but I didn't find this package in my pom file under root directory
How can I update this package's version? Do I need to do it directly in the pom file under the Maven package?
This is my dependency tree, and I want to upgrade to 1.31
If you don’t use it directly, then it is coming from one of your dependencies. You can check which one using
mvn dependency:tree
With IntelliJ IDEA, you can also open the Maven view, then right-click the project and select “Analyze Dependencies…” to get the same information.
Ideally, you should keep it as a transitive dependency, otherwise you will have to take care of its upgrade every time you upgrade the library that actually depends on it. Moreover, there can be issues if you upgrade only the transitive dependency and not the intermediate one (e.g. for Spring).
The best solution would thus be to upgrade that intermediate dependency, assuming that they have released a new version of it (SnakeYAML 1.29 being affected by CVE-2022-25857, there are good chances).
Only if you can’t do that, you should add the dependency in the <dependencyManagement> section of your pom.xml, but don’t forget tot maintain it from now on (and remove it once the intermediate dependency is upgraded).
If you can't find it in your pom then it means it's a transitive dependency pulled in by one of your other dependencies. You can just redefine this as a normal dependency in your pom and it will override the version to be whatever you like.

Maven pull an old version of a transitive dependency

I've written a library I've written that depends upon Guava version 20.0 (the last version that is compatible with JDK 1.7)
I've then written an application that uses that library and also uk.org.lidalia:slf4j-test:1.2.0 (with test scope). slf4j-test has a dependency on version 14.0.1 of Guava.
My problem is that my application is seeing two different versions of Guava as transitive dependencies and picks the OLDER version. Now when I call certain methods in my Library I get Class or Method not found exceptions.
I can (and have) excluded Guava as a dependency of slf4j-test, which fixes the problem for now, but the problem will return if I introduce another dependency which uses Guava.
So my question is: Why would Maven pick the older version of a dependency and how do I always make it pick the latest versions.
You cannot force Maven to always pick the latest version. But there are several things you can do:
If you declare the dependency in your own pom, this version always wins. So if you have a dependency on guava 20.0 in your pom, you will get exactly this.
If this is not suitable, you can put an entry into dependencyManagement which sets the version for guava. This will overwrite all transitively set versions (like the 14.0.1 in your example).
The Maven enforcer plugin has a rule that makes sure that all dependencies are evaluated to the latest version - but it does not pick that latest version, it only fails the build if it was not chosen. Then you need to choose it yourself by applying method (1) or (2) above.

Specify highest/lowest version for maven dependency

Using the following versioning logic
major.minor.build
is there any way to specify that my project depends on a specific major version, the highest minor and the lowest build number?
I need to do this because I'm using the maven-dependency-plugin to copy all the dependencies of our multiple WAR files into a common folder, so that it can be sent to the client the latest version, but at the same time keep the numbers of packages to a minimum.
No, it is not possible. When Maven encounters multiple matches for a version reference, it uses the highest matching version. Here you can find good explanation how to work with version ranges in maven.
I can suggest other solution for your original task:
Create new maven module.
Add all projects that you need as a dependencies to this module.
Use maven-dependency-plugin to copy dependencies of this module.
Maven guarantees that one and only one version of each (groupId:artifactId) is used. You can check resolved versions using mvn dependency:tree.

Strip version number from dependency based on group ID in maven

I have a project that has 3rd party dependencies, as well as dependencies on internal projects. I need to strip the version numbers from the dependent artifacts that are developed in-house.
For example: spring-2.5.6.jar should be in the final output as spring-2.5.6.jar but MyInternalProject-1.0.17.jar needs to be changed to MyInternalProject.jar.
I can identify the internal dependencies easily enough by their group ID (they are all something like com.mycompany.*). The maven-dependency-plugin has a stripVersion option, but it does not seem to be selective enough. Is there a way to do this, short of explicitly naming each dependency and what their final name should be?
Phrased another way:
I would like to have different outputFileNameMappings for the maven-assembly-plugin for artifacts based on group ID. Is there a way to do this?
I think you can using the following recipe:
First, in your aggregator pom use the dependency:copy-dependencies goal to copy your jars to some intermediate location. You will need two executions, one with <stripVersion>true</stripVersion> for your internal dependencies; and one with <stripVersion>false</stripVersion> for 3rd party libraries. You may include/exclude artifacts based on GroupId, see http://maven.apache.org/plugins/maven-dependency-plugin/copy-dependencies-mojo.html for full details.
Then it should be a simple task to build a .zip using the maven-assembly-plugin!
Based on the comments, I would re-evaluate your approach here. Generally checking jars into source control is not a good idea, especially unversioned jars. Imagine if I just had a project that referenced someArtifact.jar and I was trying to debug it - how would I know which version it used?
Tools like artifactory and nexus were built for storing versions of your jars, both internal and 3rd party (they can also proxy public repositories like maven central). In order to keep builds reproducible, I would check your binaries into a tool designed for that, and then you can reference them by version. During development, you can reference SNAPSHOT versions of your jars to get the latest, and then when you do a release, you can reference stable versions of your binaries.
Source control systems were meant for storing source, not binaries.

Preferring the latest jar in a sea of dependencies (java)

I have a large Ivy project, and Ive noticed that my code, which run well in eclipse, cause a compile error when run in ant. I've narrowed the problem down to the following line :
FileUtils.write(...).
This line fails - during compilation --- the method is simply not found. Obviously, my code is dependant on apache's commons-io library. And its quite clear that the current commons-io has this method.
http://commons.apache.org/io/apidocs/org/apache/commons/io/FileUtils.html
So what gives ?
I am pretty sure this is related to my ivy.xml -> the eclipse compiler is luckily (or smartly) using the newest possible version of commons-io , whereas my ivy.xml is using an older version which lacks this method.
Most important of all to not here is that ant is clearly using a different version of this jar.
So - my question is :
1) How can I tell ant / ivy to preferentially compile my code with the latest versions of libraries i specify ? I'm assuming that some of the dependencies in my lib/ may depend on older versions of commons-io .....
Also :
2) In this context, any hints about what to worry about regarding the how the classloader deals with duplicates in a multi-jar-dependent project would also be helpful to me ...
Dependency Reporting
I would suggest that you first add the generation of an ivy dependency report into your build, using the report task.
An example of this task is included in the following answer:
What is the Ivy equivalent of Maven's versions:display-dependency-updates?
This will tell you what versions of what jars are being used. Normally, ivy will use the version you specify in the ivy.xml file, however, another module might depend on a more recent version. Ivy's default behaviour is to always favour the most recent version of a Maven module.
Retrieve the latest dependency
If you want ivy to always prefer the latest version of a particular library then declare the dependency as follows:
<dependency org="commons-io" name="commons-io" rev="latest.release"/>
Ivy has a feature called Fixed and Dynamic Revisions.
You can set the version/revision of any artifact to latest-status like
rev="latest.integration" --> for development released
rev="latest.release" --> for released versions
Ivy takes the version with the highest version(you have specified) and omits all libraries with lower versions, so that you only have one lib in the ivy classpath (have a look at the resolution report, run ant -v (verbose mode))., which avoids having duplicate jars with conflicting versions.
This might be worth checking out, maybe you just have an old version defined in one of your ivy files.
As to the second point:
The classloader takes the class, that happens to be first in the classpath(or the jar that is first in the classpath). So mixed versions of the same lib, could behave differently on any system, depending on how the classpath is constructed.

Categories

Resources