Search code examples
javajavafxjava-platform-module-system

How to get access to unexported Java module?


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:

Localizing JavaFx Controls


Solution

  • 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.

    <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>
    

    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.