【问题标题】:How to get a Java 9 ModuleReference for an unnamed module [duplicate]如何为未命名的模块获取 Java 9 ModuleReference [重复]
【发布时间】:2017-12-24 08:47:51
【问题描述】:

更新:我在这里回答了我自己的问题:

Scanning classpath/modulepath in runtime in Java 9

--

[老问题——过时:]

在 Java 9 中仅给定 Module 对象,获取 ModuleReference 的正确方法是什么?

考虑这两种引用java.base的方法:

Module mod = ModuleLayer.boot().findModule("java.base").orElse(null);
ModuleReference modRef = ModuleFinder.ofSystem().find("java.base").orElse(null);

mod有一个方法Set<String> getPackages(),但是你只能得到包的名字,不能列出每个包中的资源。

modRef 有一个方法ModuleReader open()ModuleReader 有一个方法Stream<String> list() 列出模块中的资源,这是我需要做的。

但是,对于通过将非模块 jarfile 添加到类路径中生成的自动(因此未命名)模块,您无法从 ModuleFinder.ofSystem().find(String name)ModuleFinder.ofSystem().findAll() 获得 ModuleReference - 您只能获得 Module来自getClass().getModule()的参考。

我找不到任何方法来获取自动模块的ModuleReference。我也找不到从Module 对象获取ModuleReference 的方法,这意味着如果模块是自动和/或未命名的,我无法在Module 中列出资源。

肯定有办法为给定(已加载)Module 获取ModuleReference

【问题讨论】:

  • 您能否使用可重现的代码示例更新问题并分享您获得的configuration.modules() 的输出。

标签: java classpath java-9 java-module


【解决方案1】:

首先要从问题中弄清楚,句子中的推理是不正确的-

用于自动(因此未命名)模块,通过将非模块 jar 文件添加到类路径来生成

Automatic modules 是在模块路径中找到的命名模块。另一方面,the unnamed module 是模块系统的成员,它支持从类路径加载类型,其包未在任何已知(命名)模块中定义。


用于加载类型本身的ClassLoader 可用于获取Module(未命名)。我也尝试在How many unnamed modules are created in Java 9? 的答案中解释这一点。链接到precise documentation 也可以回答未命名模块与哪个类加载器相关联?

事实证明,每个类加载器都有自己独特的未命名模块, 由新的ClassLoader::getUnnamedModule 方法返回......

ClassLoader cl = getClass().getClassLoader();// returns the class loader for the class
Module yourClassLoaderUnnamedModule = cl.getUnnamedModule();

进一步移动文档以获取类型为未命名模块加载的模块::

.. 类型被认为在该加载程序的未命名模块中,即, 类型的 Class 对象的 getModule 方法将返回其 loader 的未命名模块。

最终等价于:

Module yourClassUnnamedModule = getClass().getModule(); // from the type itself

主要是在访问未命名模块的资源方面,尽管我同意当前没有可见的 API 可访问未命名模块的资源等。然而,由于通过此模块加载的 Class 对象的类型将始终来自类路径,可以获取正在使用的类路径的所有资源,或者相反,您可以检查正在使用的资源是从类路径还是模块路径访问。我能想到的一种方法是使用上述两个功能进行验证:

yourClassLoaderUnnamedModule.equals(yourClassUnnamedModule)//true if resource is loaded via classpath

【讨论】:

    【解决方案2】:

    ModuleFinder.ofSystem() 返回的模块查找器是一个定位系统模块的模块,这些模块是内置在运行应用程序的 JRE 环境中的模块。

    如果文件系统上自动模块的位置已知,您可以尝试使用目录检索模块查找器,即使用ModuleFinder.of(path)。另一种方法是使用模块层的配置来解析模块引用:

    Optional<ResolvedModule> resolvedModule = ModuleLayer.boot().configuration().findModule(name);
    Optional<ModuleReference> moduleReference = resolvedModule.map(ResolvedModule::reference);
    

    要回答有关仅从 Module 获取模块引用的一般问题,一种方法是:

    Optional<ModuleReference> moduleReference
         = module.getLayer().configuration()
               .findModule(module.getName())
               .map(ResolvedModule::reference);
    

    对于未命名的模块,我的猜测是您无法为其检索到ModuleReference,但至少可以尝试调用 configuration().modules() 并查看它们是否包含未命名的模块。

    【讨论】:

    • 谢谢,@manouti。在你的第一点——在你的代码中通过路径手动解析模块违背了拥有类路径/模块路径的目的。对于您提供的两个代码示例,这需要一个模块有一个名称——我的意思是我正在尝试为自动模块执行此操作。如果这些模块来自传统的类路径,则自动模块没有名称(getClass().getModule().getName() 返回 null)。如果您将它们添加到模块路径而不是类路径(然后有一个从 jarfile 名称产生的模块名称),它们只有名称(据我所知)。
    • 一个自动模块实际上是一个命名的模块;只有未命名的模块没有名称。因此,根据您的描述,getClass().getModule().getName() 返回 null 是因为运行此代码的当前类属于未命名模块,而不是自动模块的一部分。将非模块 JAR 添加到类路径中会使它们成为未命名模块的一部分,而自动模块会添加到模块路径中。
    • 我不确定在这种情况下是否有办法获得ModuleReference,但我会尝试调用boot().configuration().modules(),看看它们是否包含未命名的模块。
    • 是的,你是对的,所以我只谈论未命名的(类路径)模块,而不是命名的自动(模块路径)模块。不,该调用不会返回未命名的模块。在我发给 jigsaw-dev 的电子邮件中有更多关于为什么这是一个问题的详细信息:mail.openjdk.java.net/pipermail/jigsaw-dev/2017-December/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多