One of the biggest hurdles teams face when adopting the Java Platform Module System (JPMS) is integrating third-party libraries that lack module-info.java. Many developers assume such libraries cannot work with JPMS, leading to confusion and delays in migration projects.
The reality is that non-modular JARs can still be used—either through the classpath, as automatic modules, or by repackaging them with explicit modular metadata. Each approach has trade-offs, especially in large-scale enterprise systems where frameworks like Spring, Hibernate, or custom JDBC drivers are common.
Think of non-modular JARs as contractors in a company. They can work alongside employees (modular code), but without contracts (module-info.java), their responsibilities aren’t well-defined. JPMS provides mechanisms to manage them, but careful governance is required.
Approaches to Using Non-Modular JARs
1. Keep Them on the Classpath
- Simplest approach
- Works with both modular and non-modular apps
- Loses modularity benefits (no strong encapsulation or reliable configuration)
Example:
java -cp lib/mylib.jar:mods -m com.example/com.example.Main
2. Use Automatic Modules
- Place JAR on the module path → becomes an automatic module
- Exports all packages and requires all others
- Module name derived from JAR filename
java --module-path mods:lib -m com.example/com.example.Main
mylib-1.0.jar → module mylib
In module-info.java:
module com.example {
requires mylib;
}
3. Add Automatic-Module-Name to MANIFEST
- Stabilizes module names across versions
- Recommended for libraries not yet modularized
Manifest entry:
Automatic-Module-Name: com.example.mylib
4. Repackage with Explicit module-info.java
- Create a modular JAR manually or with tools like
moditect - Provides full JPMS benefits (encapsulation, dependency management)
Example:
module com.example.mylib {
exports com.example.mylib.api;
}
Pitfalls
❌ Relying on automatic module names (unstable, may change per release)
❌ Overusing ALL-UNNAMED or --add-opens (bypasses modular security)
❌ Mixing classpath and module path (causes visibility issues)
❌ Ignoring migration path for libraries (technical debt grows)
Best Practices
✅ Prefer libraries that publish modular JARs
✅ If unavoidable, use Automatic-Module-Name for stability
✅ Use jdeps to analyze dependencies
✅ Gradually migrate critical libraries with explicit module-info.java
✅ Keep classpath use minimal in modular projects
Example: Mixed Modular and Non-Modular App
Project Structure
mods/com.example.app
lib/legacy-lib.jar
Command
java --module-path mods:lib -m com.example.app/com.example.app.Main
Here, legacy-lib.jar is treated as an automatic module.
What's New in Java Versions?
- Java 5–8 → N/A (no modules)
- Java 9 → JPMS introduced, non-modular JARs supported via automatic modules
- Java 11 → Common use of
Automatic-Module-Namemanifest entry - Java 17 → Ecosystem shift: more libraries shipping modular JARs
- Java 21 → No significant updates across Java versions for this feature
Real-World Analogy
Non-modular JARs are like freelancers without contracts. They can still work, but roles and boundaries are unclear. Defining contracts (module-info.java) ensures stability and accountability in large teams.
Summary & Key Takeaways
- Non-modular JARs can be used with JPMS via classpath, automatic modules, or repackaging
- Automatic modules export everything and require everything—use carefully
Automatic-Module-Namestabilizes names across versions- Best long-term solution: modularize libraries explicitly
- Migration tools like
jdepsandmoditecthelp accelerate the process
FAQ: Non-Modular JARs and JPMS
1. What is the difference between classpath and module path?
Classpath loads everything blindly; module path enforces explicit dependencies.
2. Why do I get “package is not visible” errors?
Because the library isn’t modularized or properly opened to reflection.
3. What is the purpose of requires transitive?
It lets downstream modules inherit dependencies but should be used sparingly.
4. How do open and opens differ for non-modular JARs?
Non-modular JARs on classpath are open by default; automatic modules behave as open too.
5. What are automatic modules, and should I use them?
They let non-modular JARs act as modules. Use them temporarily, not as a long-term solution.
6. How does JPMS improve security compared to classpath?
It prevents accidental use of internal APIs by enforcing encapsulation.
7. Should I use jlink or jmod with non-modular JARs?
Prefer modular JARs. Non-modular ones may limit custom runtime optimizations.
8. Can I migrate legacy projects incrementally with non-modular JARs?
Yes, start with automatic modules, then modularize step by step.
9. How do I handle third-party libraries that aren’t modularized?
Use automatic modules or repackage with module-info.java.
10. Do frameworks like Spring and Hibernate fully support JPMS?
Yes, but they may require --add-opens for reflection-heavy features.