What's New in Maven 4

Recently, the Maven community decided to push forward and start working towards a 4.0.0 release. The first question after this announcement is of course: what can we expect Maven 4 to bring us? A lot - and in this post, we want to highlight some of the features that we are particularly excited about.

So without further ado, let’s dive into some of the new features that will ship with Maven 4. This post highlights a few, but the complete list is a lot longer and even more impressive.

Improved behaviour of reactor command-line arguments

The first thing that will be making a lot of impact on the day-to-day use of Maven is a group of big improvements in the “Reactor”. It may be a part of Maven that you’re not aware of as an end-user, but it’s actually very important. When you invoke Maven, it’s the Reactors job to build the project structure, make sure all modules are built in the correct order and eventually build those projects. The Reactor made its way into Maven 3, which was a great improvement in the way Maven worked on multi-module projects.

As such, the improvements to this part of Maven are most relevant to those that use multi-module projects. A recent poll we did during our J-Fall 2020 talk shows that this feature is now wide-spread.

Almost 75% of Maven users work with multi-module projects
Almost 75% of Maven users work with multi-module projects

In the following paragraphs, let’s assume we have a Maven project with three modules: common, client and app. The modules depend on each other:

Example project structure
Example project structure

Use --also-make together with --resume-from

The first improvement in the Reactor is a bug fix. Previously, if your project build failed on the client module, you would get a hint to resume the build with --resume-from :client. But if you did that, the build would break again: this time because Maven couldn’t find the common module. You might think that adding --also-make (or -am) would address this, but it wouldn’t. This long-standing bug is no longer there. If you combine --resume-from :client with --also-make, the Reactor will find all modules in your project and continue the build as you requested.

Automatically resume from the last point of failure

But chances are you will not notice. The thing with --resume-from :client is that it makes you think more than necessary. With Maven 4, you can make your life even easier and use --resume, or -r for short. It will automatically resume the build from the module that last failed.

But there’s more! Maybe you are using parallel builds. One sequence of modules was successfully built, while the build of another sequence of modules broke. In that scenario, using -r will skip the modules that were successful in the previous build.

The combination of these two features may well improve the time you need to build your large, enterprise software project!

Root-reactor aware subfolder builds

Imagine the app module in our earlier example is a web application. With Maven 3, when you wanted to start it to see if it works, you might use for example mvn jetty:run. But if you run that from the root project, it will run jetty:run in client and common as well. Since those modules do not contain a web application, it will fail.

Running mvn jetty:run inside the app module didn’t work either, because Maven would not be able to resolve the client and common modules. That’s why many people got into the bad habit of running mvn install first, as a workaround, so Maven would resolve client and common from the local repository. The same was true for selecting the project to build with mvn -f app/pom.xml - again, Maven would not be able to resolve the client and common modules.

This four-year-old improvement made it into Maven 4 as well. There are two ways in which you can use it:

  1. Run mvn jetty:run inside the app module. When you navigate to the module with the web app and run mvn jetty:run, Maven will resolve the client and common modules from your workspace, just as you would expect.
  2. Run mvn -f app/pom.xml jetty:run from the project root. In this scenario, Maven too will resolve the client and common modules from your workspace, just as you would expect.

Note that this requires a .mvn folder to be present in the root of your project. This folder does not have to contain any files, as long as it’s there.

Add --non-recursive option

This option is particularly interesting if your multi-module project is more than one or two levels deep. Take the Quarkus project as an example: each extension has at least two subprojects, deployment and runtime.

Earlier, if you wanted to build only the gRPC module and its five children, you would have needed something like mvn -pl extensions/grpc/codegen,extensions/grpc/deployment - and the list would go on and on… With Maven 4, you can use -pl extensions/grpc and build the grpc module plus all its child-modules in one go. So a “recursive” approach is now the default. If you don’t want this to happen, add --non-recursive to get back the old behaviour.

Detect errorless or warningless builds

But there’s more, not related to the Reactor and multi-module builds!

A warning is an error in the making.
– unknown author

Many tools send warnings to their users to, indeed, warn them about potential problems. Sometimes the developers of the tool use this to introduce stricter checks without breaking every project. So we prefer to have a build that does not contain any warnings - one day, they may become an error.

That’s why we are happy that with Maven 4, you can specify the --fail-on-severity or -fos parameter. By adding -fos WARN, the Maven build will break as soon as Maven itself or any plugin logs a warning message.

Consistent timestamp in multi-module builds

A recent improvement had to deal with a timestamp that Maven uses internally. That timestamp would end up in packaged archives, but in a multi-module build, each module would have a different timestamp. That’s a bit odd, and it can become annoying when determining when a bug was introduced.

Long story short: with Maven 4, all modules in the build have the same timestamp.

Automatic builds on GitHub actions

No matter whether you’re a veteran Maven contributor or somebody who passes by to fix a minor bug, the first thing you want to know is whether you broke something. The usual process was to pull the contribution to the Maven source code repository hosted at the Apache Software Foundation. There, it would be built with Jenkins and tested on various Windows and Linux versions. If you aren’t a Maven contributor yourself, you would need a “committer” on the project to do this for you. In our first experiences, before we became committers ourselves, this process could take a while.

But now, if you submit a pull request on GitHub, you don’t need to wait that long to have feedback. We’ve added GitHub Actions that perform a build and then test your changes in various environments. These provide you with instant feedback on the quality of your contribution - no human work involved.

As a bonus, those tests also run on macOS - this even showed a failing test that previously went undercover as it only failed on macOS.

But wait, there’s more!

Maven 4 will contain so much more, it’s too much to write in one article. To mention a few other things:

  • Update the default plugin versions for the POM, JAR, EJB, WAR, EAR, RAR and Maven Plugin packaging types.
  • If a downloaded file fails the checksum check, the build will break. This was previously a warning - see why we like -fos?
  • Some of the current warnings will break your build. Again, see why we like -fos? You most like will need to fix your pom for these.
  • Build/consumer implementation, explained in great detail in this video chat.
  • Maven wrapper, just like Gradle has had for quite some time. There used to be a wrapper for a long time, but that was not part of the official Maven distribution. Now it is, and it will continue to be part of Maven.
  • Automatic parent/dependency versioning

The full release notes contain all details, however big or small.

Wrapping up

We are truly happy to see a few major improvements coming with this new Maven release. Both of us have contributed some of them in time that our employer, Info Support, provided us with. We’re grateful for that time and we hope we used it to make Maven an even better tool than it already was.

If you want to give a try and you are working on macOS or Linux, there’s some good news for you. Using Brew, you can install the very latest bits and pieces of Maven 4.0 using this “tap”.

brew tap mthmulders/maven-snapshot
brew install maven-snapshot
Maven 4.0.0-alpha-1-SNAPSHOT 🎉
Maven 4.0.0-alpha-1-SNAPSHOT 🎉

Your previously installed Maven is not gone if you do this. Using Brew, you can switch back & forth:

brew unlink maven && brew link maven-snapshot
brew unlink maven-snapshot && brew link maven

Take care though: these are really the latest bits, and they may or may not work. Those builds are not an official distribution of Maven and they are not supported in any way. But of course, they pass the extensive integration test suite.

Please try these builds! We appreciate early feedback on the quality and usability of Maven 4.0.0-alpha-1. You can submit a bug in JIRA (requires login, but you can create one in seconds).