Coarse‑grained auto‑export vs. manual module‑info.java for Ceylon JPMS
0 reputation · 11 Oct 2022, 10:56 UTC
0 reputation · 11 Oct 2022, 10:56 UTC
Goal: enable fine‑grained control over which Ceylon packages are exported as JPMS modules when the module is consumed from Java 9+ without leaking internal APIs.
Constraint: the Ceylon 1.3.4 compiler generates a module‑info.class that exports every package containing a shared declaration, treating internal shared packages as public exports; there is no language annotation to distinguish JPMS visibility, and editing module‑info.java after compilation breaks reproducible builds.
Uncertainty: whether to introduce a new visibility qualifier (e.g., shared java) or rely on external tooling to patch the module descriptor, and what the impact on build reproducibility and toolchain would be.
Should the Ceylon compiler support a qualifier that maps shared declarations to JPMS exports selectively?
Is it acceptable to require manual module‑info.java editing after compilation to achieve precise encapsulation?
34775 reputation · 11 Oct 2022, 22:18 UTC
No. With Ceylon 1.3.4 you cannot add a selective JPMS export qualifier, and manual module-info.java editing after compilation is not acceptable for reproducible builds.
The compiler is archived and will not gain a new visibility qualifier. The only build-safe options are to accept coarse exports, split internal APIs into separate Ceylon modules, or apply a deterministic build-time rewrite of the generated module descriptor.
shared declaration to an exports clause in the generated module-info.class. There is no language annotation to distinguish Ceylon-internal visibility from JPMS export visibility.shared for inter-module visibility. JPMS descriptor generation is a separate coarse-grained pass that treats all shared packages as public exports.shared java or similar qualifier, and no ecosystem tooling updates will follow.It is likely that the original design treated shared as public API for both Ceylon and Java consumers. The uncertainty is whether a qualifier would be useful: it would require a compiler fork, spec change, IDE and build plugin updates, and would still need to be back-ported to a dead toolchain. That cost is not justified.
Manual module-info.java editing is technically possible but not acceptable for CI/CD that requires bit-for-bit reproducibility. Editing after compilation means source no longer matches binary and hashes diverge on every build.
jdeps --print-module-deps your-module.jar
javap -verbose -module -cp your-module.jar module-info
Confirm every shared package appears in exports.
Compile twice and compare hashes of the final artifact. If you use a rewrite, ensure the rewrite is deterministic and its inputs are versioned.
Are the internal shared packages also imported by other Ceylon modules you ship? If yes, splitting into a separate module is more invasive and a deterministic build-time rewrite is the more practical path. If no, module split is the cleanest encapsulation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.