After updating to Maven 3.8.3, we have several warnings regarding the relocation of artifacts in our Maven builds. See for example the output of using Maven’s dependency plugin to analyze the dependency usage of an empty Maven project:
$ mvn dependency:analyze [INFO] --- maven-dependency-plugin:2.8:analyze (default-cli) @ relocation-messages --- [WARNING] The artifact xml-apis:xml-apis:jar:2.0.2 has been relocated to xml-apis:xml-apis:jar:1.0.b2 [INFO] No dependency problems found
Having zero warnings in build output
We do our best to have zero warnings in our build output. A warning log line signals that something is not right, and should probably be acted on. We want to resolve all warnings. If we can’t resolve a warning, then we try to disable it by hiding them from the log output. Then and only then will new, real warnings stand out in your build output, so you can recognize them and act on them.
A plugin that assists with finding warnings in our Jenkins CI system is the Maven Warnings Next Generation plugin. It will report any warnings or errors in your build and will notify the culprits. You can also configure the plugin to ignore certain warnings that you can’t fix. An example from our build: we use Maven’s multi-threading system (--threads
flag). When you use that flag, Maven requires all plugins to be thread safe, printing an warning on each plugin that is not. Some plugins are not marked as thread-safe, but work fine in our multi-threaded build. So we ignore those warnings.
Investigating the new warning
Back to the new warnings that Maven 3.8.3 produces. The warning informs us that a library has been relocated. The relocation system offers library maintainers a way to inform users if their packages move to different Maven coordinates. Or if a version was released under an incorrect version number, it can direct users to the correctly versioned artifact. In the case of xml-apis: version 2.0.2 is an incorrect version, and users should use xml-apis version 1.0.b2 instead. The relocation system has been in Maven for a long while, but only since version 3.8.3 these warnings have become more prevalent in projects.
Having the warning in our project is odd. Our project is an empty Maven project without Maven dependencies, as shown by printing the dependency tree, which only lists the example project itself:
$ mvn dependency:tree [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ relocation-messages --- [WARNING] The artifact xml-apis:xml-apis:jar:2.0.2 has been relocated to xml-apis:xml-apis:jar:1.0.b2 [INFO] com.topdesk.maven.test:relocation-messages:jar:0.0.1-SNAPSHOT
So where does this xml-apis dependency come from? Maybe the Maven dependency plugin uses it internally? The Maven dependency plugin can also print all dependencies of plugins. Let’s search in that (pretty long) output for xml-apis:
$ mvn dependency:resolve-plugins | grep xml-apis [WARNING] The artifact xml-apis:xml-apis:jar:2.0.2 has been relocated to xml-apis:xml-apis:jar:1.0.b2
The only result from the grep
command is the warning itself, so apparently the dependency plugin does not use the xml-apis either. In Maven everything is a Maven plugin with dependencies, even the internals of Maven itself. Let’s look at Maven’s debug output, maybe something inside Maven uses xml-apis:
$ mvn dependency:analyze --debug | grep --before 27 xml-apis [DEBUG] org.apache.maven.plugins:maven-dependency-plugin:jar:2.8 [DEBUG] org.apache.maven.reporting:maven-reporting-impl:jar:2.0.5:compile [DEBUG] commons-validator:commons-validator:jar:1.2.0:compile [DEBUG] xml-apis:xml-apis:jar:1.0.b2:compile
So xml-apis is a transitive dependency of the Maven dependency plugin after all! Version 2.8 of the maven-dependency-plugin does not print the transitive dependencies of the dependencies of a plugin when calling resolve-plugins
. This is a bug that no longer occurs in more recent versions.
However it does look like we already use version 1.0.b2 of the xml-apis. But if we take a look online at the declared compile dependencies of commons-validator:commons-validator:jar:1.2.0
we can see that it actually has a dependency declared on xml-apis:xml-apis:2.0.2
. I think that Maven automatically decided to use the relocated artifact internally.
The cause
The beauty of open source projects is that it allows you to look at the code and see why certain things are happening. I looked at the release notes, commits and merge requests between Maven version 3.8.2 (which did not print this warning) and 3.8.3 (which introduced the warning). I found one merge request related to relocations: MNG-7253 Display relocation message defined in model. Observing the differences, I conclude that instead of only checking for relocations when considering the dependencies of a project, the check is now done for ANY artifact that is used during a Maven build.
The solution
Version 2.8 of the maven-dependency-plugin
depends on org.apache.maven.reporting:maven-reporting-impl:2.0.5
, which depends on commons-validator:commons-validator:1.2.0
which depends on xml-apis:xml-apis:2.0.2
. To solve this issue, commons-validator has to update or remove its dependency on the wrong xml-apis. Then the maven-reporting-impl
needs to depend on this new, fixed commons-validator
version. And lastly the maven-dependency-plugin
needs to update its dependency on the new, fixed maven-reporting-impl
. This is a lot of work and it may take a while for these updates make their way up the transitive dependency chain.
By default Maven uses version 2.8 of the maven-dependency-plugin
as defined in Maven’s Super POM. Luckily there is already a version 3.2.0 of the maven-dependency-plugin
, which depends on maven-reporting-impl:3.0.0
, which no longer depends on commons-validator. So the solution in this case is to update the offending plugin in your project.
The workaround
Unfortunately, not all plugins have been updated to not contain relocations yet. Our current workaround is to configure Maven’s logging to not log the warnings. We do that by passing the following Java property when calling mvn
:
-Dorg.slf4j.simpleLogger.log.org.apache.maven.repository.internal.DefaultArtifactDescriptorReader=error
The downside of this approach is that it also silences any genuine relocation errors in the dependencies of our projects. So we are currently waiting for all our plugins to implement the proper solution, after which we can remove our workaround. Next to that we also filed an issue for the Maven maintainers, because they might consider reverting the change that introduced this warning.
Conclusion
The cause of most warnings we see in our build are older Maven plugins. And some of those warnings have already been fixed in new versions of their dependencies. But as mentioned before, it can take a while for those changes to propagate through the entire transitive dependency trees. If they will end up in a new version of the plugin at all, since some plugins no longer have active maintainers.
In all cases, keeping your dependencies and plugins up to date will help you prevent and quickly remedy these kinds of issues. Managing dependencies can be tedious, but automation can help. Use tools like Dependabot and renovate to take away the burden of keeping your dependencies up to date.