Understanding JDK Modules: java.base, java.sql, and More

Illustration for Understanding JDK Modules: java.base, java.sql, and More
By Last updated:

One of the first surprises developers encounter when working with the Java Platform Module System (JPMS) is that even the JDK itself is modularized. Many mistakenly assume that all JDK classes are automatically available. In reality, every program depends on java.base implicitly, but other modules like java.sql, java.xml, or java.desktop must be explicitly required in module-info.java.

This misunderstanding often leads to “package not found” or “package not visible” errors when migrating code from classpath to module path. Understanding how JDK modules are structured is critical for writing modular applications, whether for enterprise systems, microservices, or cloud-native apps.

Think of JDK modules as departments in a company headquarters. The java.base department provides essentials (like HR, accounting, and security) that everyone uses. But specialized departments like java.sql (databases) or java.desktop (UI) must be explicitly consulted if your project needs them.


Core JDK Modules

1. java.base

  • Always available (implicitly required by all modules)
  • Contains fundamental APIs: java.lang, java.util, java.io, java.net, java.time

Example:

module com.example.app {
    // no need to declare requires java.base;
}

2. java.sql

  • Provides JDBC APIs for database access
  • Must be explicitly declared if using JDBC
module com.example.dbapp {
    requires java.sql;
}

3. java.xml

  • APIs for XML parsing (DOM, SAX, StAX, XPath)
  • Useful in web services and data integration
module com.example.xmlapp {
    requires java.xml;
}

4. java.desktop

  • Swing and AWT APIs for GUI applications
  • Often used in JavaFX interoperability
module com.example.guiapp {
    requires java.desktop;
}

5. java.logging

  • Provides java.util.logging framework
  • Lightweight logging compared to external frameworks
module com.example.loggingapp {
    requires java.logging;
}

6. java.management

  • APIs for monitoring and management via JMX
  • Useful in enterprise monitoring solutions
module com.example.monitoring {
    requires java.management;
}

Dependency Management in JDK Modules

Example: Application with database + logging

module com.example.orderservice {
    requires java.sql;
    requires java.logging;

    exports com.example.orderservice.api;
}
  • java.base is implicit
  • java.sql → enables JDBC
  • java.logging → enables logging

Pitfalls When Using JDK Modules

❌ Forgetting to declare requires java.sql when using JDBC APIs
❌ Assuming java.xml is available without declaring it
❌ Overusing transitive requires (requires transitive java.sql) → leaks dependencies unnecessarily
❌ Mixing classpath and module path → leads to class visibility issues


Best Practices

✅ Always explicitly declare required JDK modules (except java.base)
✅ Use jdeps to analyze dependencies
✅ Prefer requires over requires transitive unless absolutely needed
✅ Keep module-info.java minimal and clean
✅ Test applications on the module path, not just classpath


What's New in Java Versions?

  • Java 5–8 → N/A (no modules)
  • Java 9 → JDK modularized (java.base, java.sql, java.xml, etc.)
  • Java 11 → Removed Java EE modules (like java.corba, java.xml.ws)
  • Java 17 → Performance improvements in module resolution
  • Java 21 → No significant updates across Java versions for this feature

Real-World Analogy

Working with JDK modules is like choosing departments in a corporate office. Every employee uses HR (java.base). If you need financial audits (java.sql), you call that department specifically. If not, it remains idle and doesn’t burden the company.


Summary & Key Takeaways

  • The JDK itself is modularized into components like java.base, java.sql, java.xml, java.desktop
  • java.base is always available, others must be explicitly required
  • Tools like jdeps help discover dependencies
  • Explicit modularization improves performance and reduces runtime footprint
  • Declaring correct modules prevents runtime errors and improves maintainability

FAQ: JDK Modules

1. What is the difference between classpath and module path?
Classpath loads all classes blindly, module path enforces explicit dependencies.

2. Why do I get “package not visible” errors?
Because the required JDK module isn’t declared in module-info.java.

3. What is the purpose of requires transitive in JDK modules?
It makes dependencies available to downstream modules but should be used sparingly.

4. How do open and opens differ in JDK modules?
open exposes the entire module, while opens grants reflection access only to specified packages.

5. Are automatic modules useful when dealing with JDK modules?
They help migrate third-party JARs, but JDK modules are explicit and don’t need them.

6. How does JPMS improve security with JDK modules?
It enforces encapsulation and prevents accidental use of internal APIs.

7. Should I use jlink or jmod with JDK modules?
Use jlink for custom runtimes, jmod for distributing libraries.

8. Can I migrate legacy applications using JDK modules incrementally?
Yes, start with --add-modules and gradually introduce module-info.java.

9. How do I handle third-party non-modular libraries with JDK modules?
Use them as automatic modules or place them on the classpath.

10. Do frameworks like Spring and Hibernate require explicit JDK modules?
Yes, they need opens for reflection and require JDK modules like java.sql.