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

huangapple go评论82阅读模式
英文:

How to get access to unexported Java module?

问题

我需要本地化 JavaFX 内置控件。在 Jigsaw 之前,有两种方法可以实现这一点:

  1. 通过额外的属性文件,该文件必须放置在 com.sun.javafx... 包中。
  2. 通过反射 API,就像这里所示的方式2

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

有没有办法绕过这个问题,以便访问内部包?更具体地说,是 ControlResources 类加载器。

相关问题:

https://stackoverflow.com/questions/25791416/localizing-javafx-controls/25794018#25794018

英文:

I need to localize JavaFX built-in controls. Prior to Jigsaw there were to ways to achieve this:

  1. Via additional properties file which has to be placed into com.sun.javafx... package
  2. Via reflection API, like shown here

Both methods aren't compatible with Java modules, because com/sun/javafx/scene/control/* isn't the part of the public API and there is no way to create two packages with identical name even if they belong to the different projects.

Any chance to hack this issue to get access to the internal package? More specifically ControlResources classloader.

Related questions:

https://stackoverflow.com/questions/25791416/localizing-javafx-controls/25794018#25794018

答案1

得分: 1

好的,以下是您要翻译的内容:

好的,我已经花了一整天的时间来研究这个主题。

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

长篇回答

您可以使用 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(文档在此)。 OpenJFX 没有实现 ResourceBundleProvider 来提供对控件国际化的访问,因为它是内部 API 的一部分。

因此,这个问题只能由 OpenJFX 的开发人员来解决,但是根据最近的 OpenJFX 更新日志来看,他们主要集中在修复拼写错误,而不是功能。

英文:

Ok, I've lost the whole day digging this topic.

Short answer: it's not possible.

Long answer

You can use add-exports and add-opens to get access to the com.sun.javafx.scene.control.skin.resources, but it will only work if you are not using named modules, in other words, your app must not be modularized.

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

If your app is modularized, you'll get this.

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)

This is because the only way to get access to the resources that are located in another module is SPI (docs here). OpenJFX doesn't implement ResourceBundleProvider to provide access to controls internationalization, because it's a part of internal API.

So, this problem can only be solved by OpenJFX devs, but judging to the last OpenJFX changelogs, they're highly concentrated on fixing typos, not features.

huangapple
  • 本文由 发表于 2020年8月27日 19:29:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/63615052.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定