Skip to content

fix: generate correct module-info requires for JavaFX //MODULE scripts#2525

Open
koppor wants to merge 3 commits into
jbangdev:mainfrom
koppor:fix/module-javafx
Open

fix: generate correct module-info requires for JavaFX //MODULE scripts#2525
koppor wants to merge 3 commits into
jbangdev:mainfrom
koppor:fix/module-javafx

Conversation

@koppor

@koppor koppor commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #2520

Problem

A //MODULE script that depends on JavaFX fails to compile:

//MODULE app
//DEPS org.openjfx:javafx-base:21.0.2
package app;
import javafx.collections.FXCollections;
public class app {
    public static void main(String... args) {
        System.out.println(FXCollections.observableArrayList("hi"));
    }
}
error: package javafx.collections is not visible

Root cause

JavaFX publishes two artifacts per module:

artifact module
javafx-base.jar (no classifier, empty placeholder) javafx.baseEmpty
javafx-base-<os>.jar (platform classifier, real classes) javafx.base

ModuleUtil.generateModuleInfo matched resolved artifacts to root dependencies by the full management key, which includes the classifier (getManagementKey()groupId:artifactId:type[:classifier]). So the root dep org.openjfx:javafx-base (key …:jar) matched only the unclassified empty placeholder and emitted:

requires javafx.baseEmpty;

leaving javafx.collections (which lives in the real javafx.base) invisible to the generated module.

Fix

In generateModuleInfo:

  1. Match root dependencies ignoring the classifier, so the platform artifact carrying the real module is considered too.
  2. Skip the *Empty placeholder modules, so the real module (javafx.base) is required.
requires javafx.base;

This only changes which module names land in the generated module-info.java; the launch path (-p <classpath> + -m) is untouched.

Verification

  • Real CLI run (GraalVM 25): the //MODULE + JavaFX script above now compiles and runs.
  • Non-JavaFX //MODULE scripts (e.g. picocli) are unaffected.
  • New TestModule.testModuleJavaFX asserts the generated module-info requires javafx.base and not javafx.baseEmpty, and actually compiles the script.
  • TestModule and DependencyResolverTest suites pass; spotless clean.

Note on the test: it pins JavaFX to 11.0.2. The test toolchain defaults to Java 11 (build.gradle), whose ModuleFinder cannot read JavaFX 21+ module descriptors (it throws FindException, so the module name resolves to null). JavaFX 11.0.2's descriptor is Java 11-readable — the same reason the existing testResolveJavaModules uses 11.0.2.

🤖 Generated with Claude Code

A `//MODULE` script depending on JavaFX failed to compile with
"package javafx.collections is not visible". JavaFX publishes an empty
placeholder jar without a classifier (`javafx-base.jar`, module
`javafx.baseEmpty`) next to the platform jar that carries the real
`javafx.base` module (`javafx-base-<os>.jar`). generateModuleInfo matched
resolved artifacts to root dependencies by the full management key, which
includes the classifier, so it only matched the empty placeholder and
emitted `requires javafx.baseEmpty;` - leaving `javafx.collections`
invisible.

Match root dependencies ignoring the classifier so the platform artifact
that holds the real module is considered too, and skip the `*Empty`
placeholder modules so the real module (e.g. `javafx.base`) is required.

Add a //MODULE + JavaFX regression test (pinned to JavaFX 11.0.2 so the
module descriptor is readable by the Java 11 test toolchain).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • ai-review

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 43d1191e-e997-4baa-ae43-7fbf20085392

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@quintesse quintesse left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general LGTM except for that one remark.

Comment thread src/main/java/dev/jbang/util/ModuleUtil.java Outdated
Addresses review feedback: matching root dependencies while ignoring the
classifier is enough to require the real module, so there is no need to
special-case JavaFX's empty placeholder by its `*Empty` name. The empty
placeholder module simply ends up required next to the real one, which is
harmless and verified to compile and run. This avoids relying on a naming
convention that other libraries may not follow and that JavaFX could change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@quintesse quintesse left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants