Java 9 Module系统是否支持可选的依赖项?

时间:2016-10-06 15:48:50

标签: java java-9 jigsaw

背景

在maven中,工件可以使用

声明依赖关系
<optional>true</optional>

表示不需要依赖项,但如果存在则可以使用。

onClose似乎指定模块只能读取它所需的模块。

问题

  • Java 9模块系统确实不支持可选的依赖项吗?
  • 为什么不呢?
  • Java 9模块系统提供了哪些可选依赖项替代方案?

使用案例

我有一个框架,它集成了应用程序可能使用或不使用的各种库。目前,该框架是一个单独的JAR,它反映了类路径以跳过缺少库的集成代码。

我想我们可以将它分成每个配置的单独模块,但这会导致JAR数量的组合爆炸,因为我们不仅需要为每个可选依赖项单独使用JAR,而且还需要为大多数可选依赖项对分开JAR ......

1 个答案:

答案 0 :(得分:19)

是的,optional dependencies are supported。引自the original proposal

  

扩展模块声明的语言,以允许在static指令上使用requires修饰符,具有以下含义:

     
      
  • 在编译时,requires static M表示强制依赖。如果在可观察模块中找不到合适的模块并进行解决,则会出错。

  •   
  • 在编译时间之后的阶段,requires static M表示可选的依赖关系。在解析期间,模块系统不会在可观察模块中搜索合适的模块,但如果生成的模块图包含合适的模块,那么它将在执行通常的解析后完整性检查之前添加适当的可读性边缘。 [...]

  •   
     

因此,形式

的假设模块声明
module joda.beans {
    requires static joda.collect;
    ...
}
     

将确保joda.collect模块在​​编译时可用,以便joda.beans模块中引用joda.collect的代码可以毫不费力地编译。但是,它不能保证joda.collect在链接时或运行时可用。

(与此同时,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将它们包含在模块图中。