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-Name
manifest 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-Name
stabilizes names across versions- Best long-term solution: modularize libraries explicitly
- Migration tools like
jdeps
andmoditect
help 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.