Yes, optional dependencies are supported. Quoting from the original proposal:
Extend the language of module declarations to allow the static
modifier to be used on a requires
directive, with the following meanings:
At compile time, requires static M
expresses a mandatory dependence. It is an error if a suitable module cannot be found amongst the observable modules and resolved.
In phases after compile time, requires static M
expresses an optional dependence. The module system will not search the observable modules for a suitable module during resolution, but if the resulting module graph contains a suitable module then it will add the appropriate readability edge prior to doing the usual post-resolution sanity checks. [...]
Thus a hypothetical module declaration of the form
module joda.beans {
requires static joda.collect;
...
}
would ensure that the joda.collect
module is available at compile time, so that code in the joda.beans
module that refers to joda.collect
can be compiled without any fuss. It would not, however, guarantee that joda.collect
is available at link time or run time.
(In the meantime, official documentation was created for that feature.)
I wrote a demo for this. The interesting tidbits are the module-info.java
of the module declaring the optional dependencies...
module org.codefx.demo.advent {
// list the required modules
requires org.codefx.demo.advent.calendar;
// with 'static' the factories are only required at compile time;
// to be present at run time either other modules most require them
// or they must be added with the '--add-modules' command line option
requires static org.codefx.demo.advent.factory.chocolate;
requires static org.codefx.demo.advent.factory.quote;
}
... and the code within the same module that wants to access types from its optional dependencies. It has to written so that it fails graciously if the types ChocolateFactory
and/or QuoteFactory
are absent:
private static List<SurpriseFactory> createSurpriseFactories() {
return Stream.of(
createChocolateFactoryIfAccessible(),
createQuoteFactoryIfAccessible())
.flatMap(Optional::stream)
.collect(toList());
}
private static Optional<SurpriseFactory> createChocolateFactoryIfAccessible() {
try {
return Optional.of(new ChocolateFactory());
} catch (NoClassDefFoundError er) {
return Optional.empty();
}
}
private static Optional<SurpriseFactory> createQuoteFactoryIfAccessible() {
try {
return Optional.of(new QuoteFactory());
} catch (NoClassDefFoundError er) {
return Optional.empty();
}
}
Finally, the command line can be used to define which modules the app launches with:
$java \
--add-modules org.codefx.demo.advent.factory.chocolate,org.codefx.demo.advent.factory.quote \
-p mods -m org.codefx.demo.advent
It is of course also possible that other modules require them non-optionally, which forces the JVM to include them into the module graph.