【问题标题】:How to specify java Manifest Add-Exports for named modules如何为命名模块指定 java Manifest Add-Exports
【发布时间】:2021-12-18 19:58:31
【问题描述】:

我有一个 named 模块,它在编译时使用了一些 --add-exports。 如何在运行命令行中不手动指定该指令来暗示该指令?

命名模块的编译

javac --add-exports java.base/sun.security.x509=mymodule --module-source-path src -d bin --module mymodule

打包为 JAR

jar -c --file=mymodule.jar --main-class=mymodule.Main -C bin/mymodule

运行

java --module-path . --module mymodule/mymodule.Main

原因:

无法访问类 sun.security.x509.AlgorithmId(在模块 java.base 中),因为模块 java.base 不会将 sun.security.x509 导出到模块 mymodule

  • 如果为运行指定--add-exports,则运行正常 java --add-exports java.base/sun.security.x509=mymodule --module-path . --module mymodule/mymodule.Main
  • 如果在 MANIFEST.MF 中指定了 Add-Exports并且 jar 作为未命名的模块运行,它应该可以正常运行 java -jar mymodule.jar,但不会。这曾经在 JRE 11 中工作,现在在 JRE 17 中失败(在撰写本文时最新)

无法访问类 sun.security.x509.AlgorithmId(在模块 java.base 中),因为模块 java.base 不会将 sun.security.x509 导出到未命名模块 @0x53bd815b

http://openjdk.java.net/jeps/261 状态:

Add-Exports 属性值中的模块/包对与命令行选项 --add-exports module/package=ALL-UNNAMED 的含义相同

如何指定导出不是ALL-UNNAMED 而是mymodule?如何真正让它发挥作用?

如果 mymodule 不是主类而是使用更深的库,那么我必须为所有可能的模块指定所有导出,我有时可能会直接从命令行使用这些模块?

【问题讨论】:

    标签: java java-module manifest.mf


    【解决方案1】:

    在现阶段(JRE 17)看来,这是不可能的。

    仅在 2 种情况下执行导出:

    1. 当以命令行参数--add-exports开始时(显然)

    2. 当使用-jar 选项启动程序时,它会检查MANIFEST.MF 中的Add-Exports 指令。这是迄今为止检查清单的唯一案例。

    这意味着以java -cp my.jar my.Main 开头的将不会检查jar 文件的清单。

    这意味着以java --module my.module 开头的也不会检查清单。

    我的看法

    这很可悲,因为它破坏了 java 模块系统。如果您的依赖模块之一需要这些导出,您需要在命令行参数中设置它们并且您需要提前知道它。这通常是那些sun.* 类的情况,这些类没有人应该使用,但每个人都可以使用。 @Oracle:因此,要么公开它(因此无需添加导出),要么如果我们无论如何都无法使用它,请将其从 JRE 中完全删除...

    解决方法

    在运行时自己使用URLClassLoader 动态加载依赖模块并自己进行导出(丑陋)。

    String exports = jarFile.getManifest().getMainAttributes().getValue("Add-Exports");
    if( exports != null )
    {
        for (String moduleAndPackage : exports.split(" "))
        {
            String[] s = moduleAndPackage.trim().split("/");
            if (s.length != 2) continue;
            jdk.internal.module.Modules.addExports(ModuleLayer.boot().findModule(s[0]).orElseThrow(), s[1]);
        }
    }
    

    猜猜看,为了做到这一点,您需要使用受限的java.base/jdk.internal.module 包...如果您的程序可以使用-jar 启动,您现在可以使用清单选项将其导出一次。

    因此,这可以防止在命令行中手动添加所有导出(您可能不知道)。

    【讨论】:

      猜你喜欢
      • 2021-11-12
      • 2017-10-18
      • 2013-12-20
      • 1970-01-01
      • 1970-01-01
      • 2023-01-17
      • 2023-02-17
      • 1970-01-01
      • 2016-11-14
      相关资源
      最近更新 更多