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