Eliminate silent dependencies was: Mandatory service requirement

Jesse Glick jesse.glick at oracle.com
Tue Feb 21 16:31:37 PST 2012


Alan Bateman wrote:
> "requires service S" means >= 1 implementations of S required.

But there is a difference between saying "you must somehow provide an implementation of S if this module is to be used or the system will report an error", which can 
arguably be useful (in my experience rarely); and actually going out and silently picking one from the repository when none was provided, which is not obviously implied 
by the above declaration and might be bad.

> "requires optional service S" means >= 0 implementations of S required.

Which means nothing at all :-) as I noted at the end of my original post "Mandatory service requirement" - there is no reason why you should have to declare that you 
might load a service, if you can gracefully handle zero implementations.


Jaroslav Tulach wrote:
> is your suggestion to force the my.corp.app module to always have a direct
> dependency on explicit implementation of a parser (e.g. saxon)?

Exactly. If Saxon works, why would you want the app to run with something else? If you do, just change the dep (and retest the app). Here "the app" can just be a shell 
module that assembles all the reusable pieces it needs, so it is really just a module configuration.

(There are cases mainly arising I think in the Java Platform where there is just one implementation of an API available for a given system and this depends on the host 
operating system or the Java vendor; but these situations exist even without ServiceLoader, in fact more commonly, and would probably be handled via module aliases.)

For large apps with a user-level plugin system, I would expect Jigsaw to offer reflective APIs so you could build a UI to load named modules and make their services 
available.

> Otherwise others, reusing jaxp or my.corp.wsparser will find out
> only during runtime that the execution environment is insufficient.

Yes, but compared to other problems this is a very simple one to solve - add the desired implementation. It would just be part of the documentation of an API that calling 
it (or a certain subset of it!) presumes an implementation of a particular service, and what happens if no implementation is present.

> we simplified the usage of that API a lot by replacing this with
>
> module org.netbeans.projectuiapi {
>    requires service optional org.netbeans.project.uiapi.ActionsFactory; ...
> }

This is misleading because there is no equivalent in NB APIs to "requires service optional" ("requires optional service"?): if you do not really "require" it then there 
is nothing to declare (see discussion above). Rather, what we _had_ was like a (mandatory) "requires service", which made unit tests painful and also forced you to turn 
on projectui (the impl module) even when none of the above services were to be called in a particular application. That is why I removed the token requirement and wrote 
no-op fallback implementations of these services.


David M. Lloyd wrote:
> use its own class loader to locate it

Agreed that there are a lot of different variants. However we should not advocate using old-style ClassLoader hacks (especially Thread.contextClassLoader), which can 
break in all sorts of tricky ways and do not compose well - part of the justification for an official module system in Java is to simplify this kind of thing in the 
future. I think plain ServiceLoader.load(Class), understood to search in all modules in the loaded configuration, can work for all of the cases where available services 
must be discovered; if you need to discriminate among implementations, call some method on each (e.g. String[] supportedDigestImplementations()).

Or ask your own caller to pass in an implementation in dependency injection style. Unfortunately it seems that Jigsaw offers no integration point for DI frameworks.



More information about the jigsaw-dev mailing list