ChatGPT解决这个技术问题 Extra ChatGPT

How do I tell Maven to use the latest version of a dependency?

In Maven, dependencies are usually set up like this:

<dependency>
  <groupId>wonderful-inc</groupId>
  <artifactId>dream-library</artifactId>
  <version>1.2.3</version>
</dependency>

Now, if you are working with libraries that have frequent releases, constantly updating the tag can be somewhat annoying. Is there any way to tell Maven to always use the latest available version (from the repository)?

@Martin I am aware of the x.y.z-SNAPSHOT convention, but I was thinking about libraries that are released in final versions to the repository (i.e. going from dream-library-1.2.3.jar to dream-library-1.2.4.jar, and so on).
I really don't recommend this practice (nor using version ranges) for the sake of build reproducibility. A build that starts to suddenly fail for an unknown reason is way more annoying than updating manually a version number.
@PascalThivent Manually updating a release number in a pom is a pain if you are doing continuous releases. I use the versions plugin combined with the scm plugin to get past this (see my answer).
@PascalThivent Both are annoying, but in a different way. I'd like to choose between both dependent on my situation and not be forced to use one because somebody else decided this one would be better.
The guava library is a good example of the newest version having classes removed from earlier versions, which then breaks the build. The Maven mindset is that any newer version can replace any earlier, which does not hold in practice.

n
nmatt

NOTE:

The mentioned LATEST and RELEASE metaversions have been dropped for plugin dependencies in Maven 3 "for the sake of reproducible builds", over 6 years ago. (They still work perfectly fine for regular dependencies.) For plugin dependencies please refer to this Maven 3 compliant solution.

If you always want to use the newest version, Maven has two keywords you can use as an alternative to version ranges. You should use these options with care as you are no longer in control of the plugins/dependencies you are using.

When you depend on a plugin or a dependency, you can use the a version value of LATEST or RELEASE. LATEST refers to the latest released or snapshot version of a particular artifact, the most recently deployed artifact in a particular repository. RELEASE refers to the last non-snapshot release in the repository. In general, it is not a best practice to design software which depends on a non-specific version of an artifact. If you are developing software, you might want to use RELEASE or LATEST as a convenience so that you don't have to update version numbers when a new release of a third-party library is released. When you release software, you should always make sure that your project depends on specific versions to reduce the chances of your build or your project being affected by a software release not under your control. Use LATEST and RELEASE with caution, if at all.

See the POM Syntax section of the Maven book for more details. Or see this doc on Dependency Version Ranges, where:

A square bracket ( [ & ] ) means "closed" (inclusive).

A parenthesis ( ( & ) ) means "open" (exclusive).

Here's an example illustrating the various options. In the Maven repository, com.foo:my-foo has the following metadata:

<?xml version="1.0" encoding="UTF-8"?><metadata>
  <groupId>com.foo</groupId>
  <artifactId>my-foo</artifactId>
  <version>2.0.0</version>
  <versioning>
    <release>1.1.1</release>
    <versions>
      <version>1.0</version>
      <version>1.0.1</version>
      <version>1.1</version>
      <version>1.1.1</version>
      <version>2.0.0</version>
    </versions>
    <lastUpdated>20090722140000</lastUpdated>
  </versioning>
</metadata>

If a dependency on that artifact is required, you have the following options (other version ranges can be specified of course, just showing the relevant ones here):

Declare an exact version (will always resolve to 1.0.1):

<version>[1.0.1]</version>

Declare an explicit version (will always resolve to 1.0.1 unless a collision occurs, when Maven will select a matching version):

<version>1.0.1</version>

Declare a version range for all 1.x (will currently resolve to 1.1.1):

<version>[1.0.0,2.0.0)</version>

Declare an open-ended version range (will resolve to 2.0.0):

<version>[1.0.0,)</version>

Declare the version as LATEST (will resolve to 2.0.0) (removed from maven 3.x)

<version>LATEST</version>

Declare the version as RELEASE (will resolve to 1.1.1) (removed from maven 3.x):

<version>RELEASE</version>

Note that by default your own deployments will update the "latest" entry in the Maven metadata, but to update the "release" entry, you need to activate the "release-profile" from the Maven super POM. You can do this with either "-Prelease-profile" or "-DperformRelease=true"

It's worth emphasising that any approach that allows Maven to pick the dependency versions (LATEST, RELEASE, and version ranges) can leave you open to build time issues, as later versions can have different behaviour (for example the dependency plugin has previously switched a default value from true to false, with confusing results).

It is therefore generally a good idea to define exact versions in releases. As Tim's answer points out, the maven-versions-plugin is a handy tool for updating dependency versions, particularly the versions:use-latest-versions and versions:use-latest-releases goals.


I think that LATEST/RELEASE is very important for plugins which provide deploy functionality. For example we use plugin which deploy new version of artifacts to the our servers. If servers will change we release new version of plugin and all projects that use this plugin must by manually updated to use new version of deploy plugin.
@RichSeller hey Rich; I spent a bit of time on this before I figured out this is not available in Maven 3.0 anymore ;) Would you consider editing the answer so it starts with an update stating the Maven 3.0 depreaction? Thanks a bunch!
I believe a good balance would be to lock the major version but get the latest minor (or patch) version (whichever is used for bug-fixes only in the artifcat you are depending on). With the current syntax this appears to be only possible with a range like (note: starts with brackets and ends with parens): [1.1,2.0)
FWIW... updated link to Maven3 Compatibility Notes: cwiki.apache.org/confluence/display/MAVEN/…
Worth to note that [1.0.0, 2.0.0] range does not include 1.0-SNAPSHOT but does include 2.0-SNAPSHOT.
T
Tim

Now I know this topic is old, but reading the question and the OP supplied answer it seems the Maven Versions Plugin might have actually been a better answer to his question:

In particular the following goals could be of use:

versions:use-latest-versions searches the pom for all versions which have been a newer version and replaces them with the latest version.

versions:use-latest-releases searches the pom for all non-SNAPSHOT versions which have been a newer release and replaces them with the latest release version.

versions:update-properties updates properties defined in a project so that they correspond to the latest available version of specific dependencies. This can be useful if a suite of dependencies must all be locked to one version.

The following other goals are also provided:

versions:display-dependency-updates scans a project's dependencies and produces a report of those dependencies which have newer versions available.

versions:display-plugin-updates scans a project's plugins and produces a report of those plugins which have newer versions available.

versions:update-parent updates the parent section of a project so that it references the newest available version. For example, if you use a corporate root POM, this goal can be helpful if you need to ensure you are using the latest version of the corporate root POM.

versions:update-child-modules updates the parent section of the child modules of a project so the version matches the version of the current project. For example, if you have an aggregator pom that is also the parent for the projects that it aggregates and the children and parent versions get out of sync, this mojo can help fix the versions of the child modules. (Note you may need to invoke Maven with the -N option in order to run this goal if your project is broken so badly that it cannot build because of the version mis-match).

versions:lock-snapshots searches the pom for all -SNAPSHOT versions and replaces them with the current timestamp version of that -SNAPSHOT, e.g. -20090327.172306-4

versions:unlock-snapshots searches the pom for all timestamp locked snapshot versions and replaces them with -SNAPSHOT.

versions:resolve-ranges finds dependencies using version ranges and resolves the range to the specific version being used.

versions:use-releases searches the pom for all -SNAPSHOT versions which have been released and replaces them with the corresponding release version.

versions:use-next-releases searches the pom for all non-SNAPSHOT versions which have been a newer release and replaces them with the next release version.

versions:use-next-versions searches the pom for all versions which have been a newer version and replaces them with the next version.

versions:commit removes the pom.xml.versionsBackup files. Forms one half of the built-in "Poor Man's SCM".

versions:revert restores the pom.xml files from the pom.xml.versionsBackup files. Forms one half of the built-in "Poor Man's SCM".

Just thought I'd include it for any future reference.


In this context, what's the difference between "release" and "version".
@BenNoland, I believe the difference in this case is that the next version may not need be a release artifact. E.g. given an artifact versioned 1.0.0-SNAPSHOT, 1.0.0, and 1.0.1-SNAPSHOT, and a pom reference to 1.0.0-SNAPSHOT, versions:next-versions and versions:next-releases will resolve to 1.0.0, whereas versions:latest-versions and versions:latest-releases will resolve to 1.0.1-SNAPSHOT and 1.0.0 respectfully.
Printing all possible and unrelated goals is not helpful.
What I'm looking for is something that will do the reverse of versions:resolve-ranges. I have a pom that has been resolved that I want to open back up to newer versions (i.e. go from 1.2.3-4 to [1.2,).
I would think versions:use-latest-versions solves most of the OP's problems.
S
Simon Forsberg

Please take a look at this page (section "Dependency Version Ranges"). What you might want to do is something like

<version>[1.2.3,)</version>

These version ranges are implemented in Maven2.


You may want to have a closer look at how Maven compare version numbers - if you do not conform to a strict pattern Maven compares as strings and not numbers.
That page is on Codehaus, and describes itself as things "that have not yet been implemented for Maven 2.0"... The Maven documentation itself doesn't say anything about version ranges. Am I missing something? When were version ranges introduced? Where are they described in the official documentation?
You are wrong, version range means that all versions are OK from 1.2.3 to higher. This is not the latest version at all.
M
Miss Chanandler Bong

Unlike others I think there are many reasons why you might always want the latest version. Particularly if you are doing continuous deployment (we sometimes have like 5 releases in a day) and don't want to do a multi-module project.

What I do is make Hudson/Jenkins do the following for every build:

mvn clean versions:use-latest-versions scm:checkin deploy -Dmessage="update versions" -DperformRelease=true

That is I use the versions plugin and scm plugin to update the dependencies and then check it in to source control. Yes I let my CI do SCM checkins (which you have to do anyway for the maven release plugin).

You'll want to setup the versions plugin to only update what you want:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>versions-maven-plugin</artifactId>
    <version>1.2</version>
    <configuration>
        <includesList>com.snaphop</includesList>
        <generateBackupPoms>false</generateBackupPoms>
        <allowSnapshots>true</allowSnapshots>
    </configuration>
</plugin>

I use the release plugin to do the release which takes care of -SNAPSHOT and validates that there is a release version of -SNAPSHOT (which is important).

If you do what I do you will get the latest version for all snapshot builds and the latest release version for release builds. Your builds will also be reproducible.

Update

I noticed some comments asking some specifics of this workflow. I will say we don't use this method anymore and the big reason why is the maven versions plugin is buggy and in general is inherently flawed.

It is flawed because to run the versions plugin to adjust versions all the existing versions need to exist for the pom to run correctly. That is the versions plugin cannot update to the latest version of anything if it can't find the version referenced in the pom. This is actually rather annoying as we often cleanup old versions for disk space reasons.

Really you need a separate tool from maven to adjust the versions (so you don't depend on the pom file to run correctly). I have written such a tool in the the lowly language that is Bash. The script will update the versions like the version plugin and check the pom back into source control. It also runs like 100x faster than the mvn versions plugin. Unfortunately it isn't written in a manner for public usage but if people are interested I could make it so and put it in a gist or github.

Going back to workflow as some comments asked about that this is what we do:

We have 20 or so projects in their own repositories with their own jenkins jobs When we release the maven release plugin is used. The workflow of that is covered in the plugin's documentation. The maven release plugin sort of sucks (and I'm being kind) but it does work. One day we plan on replacing this method with something more optimal. When one of the projects gets released jenkins then runs a special job we will call the update all versions job (how jenkins knows its a release is a complicated manner in part because the maven jenkins release plugin is pretty crappy as well). The update all versions job knows about all the 20 projects. It is actually an aggregator pom to be specific with all the projects in the modules section in dependency order. Jenkins runs our magic groovy/bash foo that will pull all the projects update the versions to the latest and then checkin the poms (again done in dependency order based on the modules section). For each project if the pom has changed (because of a version change in some dependency) it is checked in and then we immediately ping jenkins to run the corresponding job for that project (this is to preserve build dependency order otherwise you are at the mercy of the SCM Poll scheduler).

At this point I'm of the opinion it is a good thing to have the release and auto version a separate tool from your general build anyway.

Now you might think maven sort of sucks because of the problems listed above but this actually would be fairly difficult with a build tool that does not have a declarative easy to parse extendable syntax (aka XML).

In fact we add custom XML attributes through namespaces to help hint bash/groovy scripts (e.g. don't update this version).


Thanks for including a motivation (continuous deployment) in your answer.
I think the important point here it that builds are reproducible with this method, whereas, when using version ranges or -LATEST, they are not!
I would like to second the solution using an external tool making changes to project pom before running build. We are also using this approach as version-range-plugin is inherently bugged for example taking to account dates and not only versions.
Could any one help that I met with the same issue as stackoverflow.com/questions/45179530/…. I set in as an execution during build with validate phase. I can see the version update, but the real build still used the old value...
m
mkobit

The dependencies syntax is located at the Dependency Version Requirement Specification documentation. Here it is is for completeness:

Dependencies' version element define version requirements, used to compute effective dependency version. Version requirements have the following syntax: 1.0: "Soft" requirement on 1.0 (just a recommendation, if it matches all other ranges for the dependency) [1.0]: "Hard" requirement on 1.0 (,1.0]: x <= 1.0 [1.2,1.3]: 1.2 <= x <= 1.3 [1.0,2.0): 1.0 <= x < 2.0 [1.5,): x >= 1.5 (,1.0],[1.2,): x <= 1.0 or x >= 1.2; multiple sets are comma-separated (,1.1),(1.1,): this excludes 1.1 (for example if it is known not to work in combination with this library)

In your case, you could do something like <version>[1.2.3,)</version>


M
Martin Klinke

Are you possibly depending on development versions that obviously change a lot during development?

Instead of incrementing the version of development releases, you could just use a snapshot version that you overwrite when necessary, which means you wouldn't have to change the version tag on every minor change. Something like 1.0-SNAPSHOT...

But maybe you are trying to achieve something else ;)


t
trung

Who ever is using LATEST, please make sure you have -U otherwise the latest snapshot won't be pulled.

mvn -U dependency:copy -Dartifact=com.foo:my-foo:LATEST
// pull the latest snapshot for my-foo from all repositories

This does not pulls latest snapshot from local m2 repo
V
Verhagen

The truth is even in 3.x it still works, surprisingly the projects builds and deploys. But the LATEST/RELEASE keyword causing problems in m2e and eclipse all over the place, ALSO projects depends on the dependency which deployed through the LATEST/RELEASE fail to recognize the version.

It will also causing problem if you are try to define the version as property, and reference it else where.

So the conclusion is use the versions-maven-plugin if you can.


K
Kalle Richter

By the time this question was posed there were some kinks with version ranges in maven, but these have been resolved in newer versions of maven. This article captures very well how version ranges work and best practices to better understand how maven understands versions: https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855


Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
M
Markon

Sometimes you don't want to use version ranges, because it seems that they are "slow" to resolve your dependencies, especially when there is continuous delivery in place and there are tons of versions - mainly during heavy development.

One workaround would be to use the versions-maven-plugin. For example, you can declare a property:

<properties>
    <myname.version>1.1.1</myname.version>
</properties>

and add the versions-maven-plugin to your pom file:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>versions-maven-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <properties>
                    <property>
                        <name>myname.version</name>
                        <dependencies>
                            <dependency>
                                <groupId>group-id</groupId>
                                <artifactId>artifact-id</artifactId>
                                <version>latest</version>
                            </dependency>
                        </dependencies>
                    </property>
                </properties>
            </configuration>
        </plugin>
    </plugins>
</build>

Then, in order to update the dependency, you have to execute the goals:

mvn versions:update-properties validate

If there is a version newer than 1.1.1, it will tell you:

[INFO] Updated ${myname.version} from 1.1.1 to 1.3.2

A
Arayan Singh

If you want Maven should use the latest version of a dependency, then you can use Versions Maven Plugin and how to use this plugin, Tim has already given a good answer, follow his answer.

But as a developer, I will not recommend this type of practices. WHY?

answer to why is already given by Pascal Thivent in the comment of the question

I really don't recommend this practice (nor using version ranges) for the sake of build reproducibility. A build that starts to suddenly fail for an unknown reason is way more annoying than updating manually a version number.

I will recommend this type of practice:

<properties>
    <spring.version>3.1.2.RELEASE</spring.version>
</properties>

<dependencies>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

</dependencies>

it is easy to maintain and easy to debug. You can update your POM in no time.


if you use versions-maven-plugin, the build is still reproducible. Updating the maven version can be done in a separate commit (as you can see from my answer, you have to specify a separate goal, it just doesn't happen magically in the build).
y
yilin

MY solution in maven 3.5.4 ,use nexus, in eclipse:

<dependency>
    <groupId>yilin.sheng</groupId>
    <artifactId>webspherecore</artifactId>
    <version>LATEST</version> 
</dependency>

then in eclipse: atl + F5, and choose the force update of snapshots/release

it works for me.


Wont work at the command line though for reasons ably stated above in various posts. Many of us have to conform to automated builds and so our POMs have to work when run at the command line, not just in Eclipse.