如何访问未导出的Java模块? 长答案

问题描述

我需要本地化JavaFX内置控件。在拼图之前,有很多方法可以实现这一点:

  1. 必须将其他properties file放入com.sun.javafx...包装中
  2. 通过反射API,如显示here

这两种方法均与Java模块不兼容,因为com/sun/javafx/scene/control/*不是公共API的一部分,并且即使它们属于不同的项目,也无法创建两个具有相同名称的包。 / p>

是否有机会破解此问题以访问内部软件包?更具体地说,是ControlResources类加载器。

相关问题:

Localizing JavaFx Controls

解决方法

好吧,我整天都在研究这个话题。

简短的回答:是不可能的。

长答案

您可以使用add-exportsadd-opens来访问com.sun.javafx.scene.control.skin.resources,但这仅在不使用命名模块的情况下才有效,换句话说,您的应用不得模块化。

<plugin>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-maven-plugin</artifactId>
    <configuration>
        <mainClass>${bld.mainClass}</mainClass>
        <executable>${java.home}/bin/java</executable>
        <options>
            <option>--add-exports</option>
            <option>javafx.controls/com.sun.javafx.scene.control.skin.resources=app.module</option>
            <option>--add-opens</option>
            <option>javafx.controls/com.sun.javafx.scene.control.skin.resources=app.module</option>
        </options>
    </configuration>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <compilerArgs>
            <arg>--add-exports</arg>
            <arg>javafx.controls/com.sun.javafx.scene.control.skin.resources=app.module</arg>
            <arg>--add-opens</arg>
            <arg>javafx.controls/com.sun.javafx.scene.control.skin.resources=app.module</arg>
        </compilerArgs>
    </configuration>
</plugin>

如果您的应用是模块化的,您会得到的。

Caused by: java.lang.UnsupportedOperationException: ResourceBundle.Control not supported in named modules
    at java.base/java.util.ResourceBundle.checkNamedModule(ResourceBundle.java:1547)
    at java.base/java.util.ResourceBundle.getBundle(ResourceBundle.java:1508)

这是因为访问另一模块中资源的唯一方法是SPI(docs here)。 OpenJFX没有实现ResourceBundleProvider来提供对控件国际化的访问,因为它是内部API的一部分。

因此,只有OpenJFX开发人员才能解决此问题,但是从最近的OpenJFX变更日志来看,他们高度专注于修正错别字,而不是功能。