Tomas,
I realize that you want to allow your modular JARs to be deployed on the
classpath and still enjoy some degree of encapsulation.
However, mapping packages 1:1 to modules isn't the right way to use the
module system. You get to formalize the system structure, and will be
forced to break any legacy cycles between packages, but every module
will export 100% of its packages, so there's no real information hiding.
The maintainer of a module in one subsystem can freely require a module
in another subsystem and access the exported-but-not-really-supported
package of that other subsystem, so over time, a ball of mud will re-emerge.
Having "internal" packages is a _feature_ of modules, not a problem.
It's only a problem if those modules are deployed on the classpath, and
we don't recommend doing that.
On point 3: The requirement that a provider class must be public with a
public ctor comes from the original design of ServiceLoader. This
resulted in providers that were "too public", so we used the module
system to solve that problem: you can take existing providers, "hide"
them in unexported/internal packages of modules, and service consumers
are not impacted at all.
Except for the small addition of "provider methods" as an alternative to
public ctors, we took ServiceLoader in Java 9 as we found it. Evolving
ServiceLoader in Java 23+ to allow providers with very limited
accessibility -- package-access classes / ctors / provider methods -- is
not incompatible with anything in the module system. In fact, keeping
the circle of code that can instantiate providers as tight as possible
is a good thing. However, we haven't heard the request for
package-access providers from many people, and working on that feature
would mean not working on something else, so it's unlikely that the
feature will appear in the foreseeable future.
Alex
On 1/22/2024 3:30 PM, Tomas Langer wrote:
We have a single module/single package approach, so all internal classes
are hidden by visibility (package local) and not by package (as that
cannot be enforced on classpath.
Using more than one package usually results in internal packages and in
requirement to have some methods public, so classes in other packages of
your module can access them (where we can live with package local only...)
Tomas
Zasláno z Outlooku pro Android <https://aka.ms/AAb9ysg>
------------------------------------------------------------------------
*From:* jigsaw-dev <jigsaw-dev-r...@openjdk.org> on behalf of Alex
Buckley <alex.buck...@oracle.com>
*Sent:* Monday, January 22, 2024 9:13:39 PM
*To:* jigsaw-dev@openjdk.org <jigsaw-dev@openjdk.org>
*Subject:* Re: Java extensibility and JPMS (ServiceLoader)
Tomas,
A clarification for point 3:
On 1/19/2024 5:02 AM, Tomas Langer wrote:
*Ad 3 - Provider implementation must be public with public constructor*
-------------------------------------
Details:
Provider implementations are not supposed to be visible to users - they
are not public API of my module (the fact that I provide a service is
part of my public API).
Right now there is only one option to work around this, and it only
works in JPMS, and in my opinion it brings in even more problems - put
the provider implementation in an un-exported package.
The problem with this approach is that now the provider implementation
MUST use only public methods of my module, thus creating even more
public APIs, where if I just put it in my exported package, I can use
package private methods of my other classes to implement the service (so
I pay the price of having one public class with one public constructor
agains multiple public classes and public methods). Also the "hiding" in
unexported package is lost when on classpath anyway...
I don't understand what you mean by "the provider implementation MUST
use only public methods of my module". You have an arrangement of
modules and packages in mind that I simply cannot see -- please share it.
Alex