Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the Java 9 Module system support optional dependencies?

Background

In maven, an artifact can declare a dependency with

<optional>true</optional> 

which means that the dependency is not required, but can be used if present.

The State of the Module System seems to specify that a module can only read modules it has required.

Questions

  • Does the Java 9 module system indeed not support optional dependencies?
  • Why not?
  • What alternatives to optional dependencies does the Java 9 module system provide?

Use Case

I have a framework that integrates various libraries that may or may not be used by an application. Currently, this framework is a single JAR that reflects upon the classpath to skip integration code for absent libraries.

I guess we could split this into a separate module for each configuration, but this would cause a combinatorial explosion in the number of JARs, because we'd not only need a separate JAR for each optional dependency, but also a separate JAR for most pairs of optional dependencies ...

like image 875
meriton Avatar asked Oct 06 '16 15:10

meriton


People also ask

Which of the following is correct about module system in Java 9?

Q 7 - Which of the following is correct about Module System in Java 9? A - javac, jlink, and java have additional options to specify module paths, which further locate definitions of modules.

What are modules in Java 9?

Defining the Java 9 module. A module is a collection of code, data, and resources. It is a set of related packages and types (classes, abstract classes, interfaces, and more) with code, data files, and some static resources. For example, the module descriptor module-info.

What are the main goals of Java 9?

The main goals for Java 9 are to: Make the Java Standard Edition platform, and the JDK, more navigable to scale down for small computing devices. Improve the overall security and maintain not only the JDK but the Java Implementations in general. Allow overall improved application performance.

What are Java modules used for?

A Java module is a packaging mechanism that enables you to package a Java application or Java API as a separate Java module. A Java module is packaged as a modular JAR file. A Java module can specify which of the Java packages it contains that should be visible to other Java modules which uses this module.


1 Answers

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.

like image 184
Nicolai Parlog Avatar answered Sep 20 '22 13:09

Nicolai Parlog