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

Reply via email to