Hello Thorsten

Le 02/08/2023 à 11:47, Thorsten Heit a écrit :

I see your point, but we're not living in a fully modularized Java world: If you insist on having a Jar reside on the module path only, this prevents others from using it on applications that are not fully modularized or that cannot be modularized (yet).

No, an application does not need to be modularized for putting dependencies on the module-path. This is what I tried to explain in my yesterday's email. All applications, modularized or not, are already using dependencies on the module path: the JDK itself. We can test that with the following code:

   System.out.println(String.class.getModule().getName());

The idea that a non-modularized application must put all its dependencies on the class-path seems to be a widely-spread misunderstanding of how JPMS works. Putting a library on the module-path does not force an application to be modularized. Admittedly there is some cases where a developer way want to use the class-path anyway, but it should be under developer's control.


Furthermore I don't really see a problem of duplication. Normally you don't have tons of service provider implementations in one Jar (IMO) so this shouldn't be too much hassle to have a few lines in your module descriptor AND in the provider configuration file under META-INF/services...

In Apache SIS, there are 76 providers for coordinate operations (e.g. map projections) alone, not counting other services. This is not huge, but the risk of inconsistency exists. Furthermore, as explained yesterday, it blocks us from providing singletons, so we have to workaround with wrappers. Finally, contrarily to module-info, META-INF/services/ files get no compile-time verification. JUnit tests does not always help in discovering for example that a META-INF/services/ file was in the wrong module (a mistake that we discovered precisely thanks to the migration to module-info).


To be compatible with fully-modular applications and those that aren't I'd extract the necessary parts from the provider implementation into a singleton class and use that one instead. In this case you still could have multiple instances of your provider implementation, and all of them internally use a singleton for configuration data or whatever...

Yes this is the above-mentioned wrapper pattern. But things become more complicated when some providers may implement more than one public interface and we don't want to block advanced users from accessing those additional API if they need to.


Can you show an example that depends on such methods? I personally don't see a reason why a library should behave different if it is on the module path or class path...

There is 167 occurrences of the @CallerSensitive annotation in OpenJDK source code as of today. Not all of them are module-related, but many are, especially in tasks involving reflections. When a modularized library is put on the module-path, encapsulation is enforced. So for example a call to the following code:

   InputStream in = Foo.class.getResourceAsStream("Something.properties");

returns a non-null value (assuming the file exists) when the library invoking above code is on the class-path, but a null value if the same library is on the module-path and Foo is a class declared in a non-exported package of another module. The same restriction applies to all variants such as ClassLoader.getResource(String), there is no way to bypass the encapsulation. It may look likes a regression, but the key point is that the behavior is not the same and a library could very well depend on encapsulation being enforced. Other methods annotated with @CallerSensitive are some logging methods. I didn't tested but I see that the source code uses module information, so I would not be surprised if logging messages are formatted differently.


IMHO a library is buggy if it's *behavior* depends on whether it is being used on the module path or on the classpath.

With 167 OpenJDK methods annotated with @CallerSensitive, there is plenty of room for behavioral differences even if the library developers where very careful. I think it is okay for a library to said "I have been designed for working as a module, please put me on the module-path". As said above, it does not force applications to be themselves modularized. There is possibly different opinions about what is best (and it may depend on the library), but the current problem is that Maven imposes its black magic on everyone with no way I can see to specify what we need.

    Martin

Reply via email to