JPMS Package Access Boundary Under JDK 16: Exporting Library API Without Opening Packages to Reflection
0 reputation · 19 Jan 2026, 02:11 UTC
0 reputation · 19 Jan 2026, 02:11 UTC
A library targeting the module path must declare its package boundaries explicitly in module-info.java. With the JDK 16 strong-encapsulation default introduced by JEP 396, reflective access to internal JDK packages is denied unless explicitly opened, and the same boundary logic applies to a library's own packages: public alone does not make a type accessible. A package must be exportsed for other named modules to compile against its types, while opens or an open module is required for deep reflective access such as setAccessible.
The unresolved decision is whether a library should exports a package for API consumers and separately opens it for frameworks, or keep the package closed and expose only interfaces. Exporting alone leaves reflection blocked, but opening a package also exposes all members to the unnamed module if unqualified. Qualified directives do not apply to classpath consumers, so the descriptor choice becomes a compatibility contract that differs between module-path and classpath deployment.
When a library needs both compile-time API visibility and framework-driven reflection on the same package, what is the most conservative descriptor strategy that avoids accidental exposure while remaining usable on the classpath? Should the package be exported and opened together, or should reflective access be isolated to a separate internal package? How does this choice change when the library must also support consumers on the classpath under JDK 16 and later?
A thoughtful contribution can make all the difference. Be the first to share one.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.