Hello all
MNG-7855 [1] is a quasi-blocker issue (at least a major impediment) for
migration to JPMS. I can try to provide a patch, but I'm not familiar
with Maven internal and would need guidance. Another issue is that
fixing this bug probably requires the addition of a new option, which
would require discussion.
The bug is in the way that dependencies are dispatched between
class-path and module-path. It is based on the wrong assumption that if
an application is not modularized, then all its dependencies must be on
the class-path. This is not true. An application can be classical
(non-modularized) and still have some or all its dependencies on the
module-path. For the application, it may make no visible difference.
However for the dependency itself, the fact that it was declared on the
class-path or on the module-path can make a big difference. This is
explained in the issue [1] and a "hello-world" project demonstrating
that is at [2].
On the Maven discussion mailing list, it has been suggested that the
workaround is easy (duplicate module-info information into
META-INF/services/) and that if a library behaves differently depending
on whether it was specified on the class-path or on the module-path, it
would be a library bug. I question those claims:
* A module can declare a lot of service providers (~70 in my case),
and being forced to keep module-info and META-INF/services/ in sync
is a risk of inconsistency.
* META-INF/services/ is not always equivalent to module-info. In some
cases, there is no easy way to reproduce the same effect (e.g.
singleton provider instances).
* Reflection methods do not behave in the same way depending on
whether the library was declared on the class-path or module-path.
More generally, the OpenJDK API contains between 100 and 200
caller-sensitive methods. There is plenty of room for unforeseen
behavioral differences.
* If the library wants to load external JAR files dynamically (after
JVM startup), the ways to do that are totally different: with
URLClassLoader in a class-path world, but with ModuleLayer in a
module-path world. The differences are too large for making
practical to support both.
So workarounds for MNG-7855 are practical only in simple cases, and
MNG-7855 can become a blocker issue in more complex applications. A
quick and I think "behaviorally correct" fix would be to drop the check
about whether the project is modularized or not, i.e. check only if the
_dependency_ is modularized. This approach was discussed in Gradle as
well [3]. But because this fix may be backward incompatible if some
projects rely on the current behavior, we may need to make this change
an opt-in. So we may need to discuss for a new option.
A better long-term fix would be to allow developers to specify in their
<dependency> block whether they want the dependency to be on the
class-path or module-path. But that would require a POM model change, so
for now I would like to contribute to a shorter-term fix with a new
option if possible.
Thanks,
Martin
[1]https://issues.apache.org/jira/browse/MNG-7855
[2]https://github.com/Geomatys/MavenModulepathBug
[3]https://github.com/gradle/gradle/issues/25954