The full picture
- Mechanics:
module-info.javadeclaresrequires(dependencies),exports(public API packages),opens(deep-reflection permission — what Spring/Hibernate need),provides/uses(ServiceLoader). - What it fixes: 'public means everyone' — pre-JPMS, internal packages were public-by-necessity; modules make internals invisible even to reflection unless opened.
- Why adoption stalled in apps: automatic modules are leaky, split packages across jars are fatal errors, many libraries lacked descriptors for years, and Maven/Gradle already gave 'good enough' boundaries. Gradle/Maven enforcement plugins or ArchUnit deliver architectural boundaries with less friction.
- Where it matters to you anyway: JDK internals are locked (
--add-opens java.base/java.lang=ALL-UNNAMEDin every legacy startup script), jlink can cut a 300MB JRE to ~50MB for containers, and library authors should ship at least anAutomatic-Module-Name.