背景
在Maven中,工件可以使用
<optional>true</optional>
这意味着该依赖性不是必需的,但可以使用(如果存在)。
The State of the Module System似乎指定一个模块只能读取其所需的模块。
问题
用例
我有一个框架,该框架集成了应用程序可能使用或可能不使用的各种库。当前,该框架是单个JAR,可反射(reflect)类路径以跳过缺少库的集成代码。
我想我们可以针对每种配置将其拆分为一个单独的模块,但这会导致JAR数量的爆炸性增长,因为我们不仅需要为每个可选依赖项使用一个单独的JAR,而且对于大多数对还需要一个单独的JAR可选依赖项...
最佳答案
是的,optional dependencies are supported。引用the original proposal:
(同时,official documentation was created for that feature。)
我为此写了a demo。有趣的花样是声明可选依赖项的模块的module-info.java
...
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;
}
...,以及同一模块中要从其可选依赖项访问类型的代码。它必须写成这样,如果不存在
ChocolateFactory
和/或QuoteFactory
类型,它就会优雅地失败: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();
}
}
最后,命令行可用于定义应用启动的模块:
$java \
--add-modules org.codefx.demo.advent.factory.chocolate,org.codefx.demo.advent.factory.quote \
-p mods -m org.codefx.demo.advent
当然,其他模块也可能非必需地要求它们,这迫使JVM将它们包括在模块图中。