10.2 Module Directives: requires, exports, opens, provides, and uses

Key Takeaways

  • The requires directive establishes direct module readability, while requires transitive grants implied readability, automatically propagating module access to downstream consumers.
  • The requires static directive declares a mandatory compile-time dependency that becomes optional at runtime, enabling optional feature sets without runtime ClassNotFoundException failures.
  • The exports directive makes public types in a package accessible at compile-time and runtime, and qualified exports (exports ... to) restrict this accessibility exclusively to named target modules.
  • Exporting a package is non-recursive: exporting com.app does not export subpackages like com.app.model, and wildcard export syntax is strictly illegal.
  • The opens directive enables deep reflective access to private members of a package at runtime without exposing public types at compile-time, while uses and provides with configure decoupled ServiceLoader service provider bindings.
Last updated: September 2026

Module Directives: requires, exports, opens, provides, and uses

A module descriptor (module-info.java) controls access boundaries, dependencies, and service bindings through explicit module directives. On the 1Z0-830 exam, questions test the precise differences between module targets versus package targets, implied readability mechanics (requires transitive), optional compile-time dependencies (requires static), qualified visibility, non-recursive export rules, and reflective permissions.


1. Dependency Directives: requires, requires transitive, and requires static

To consume types declared in another module, a module must declare readability using the requires family of directives.

1. Basic requires (Direct Readability)

module com.app.billing {
    requires java.sql;              // Target is a MODULE name
    requires com.app.inventory;     // Target is a MODULE name
}
  • Syntax: requires <module-name>;
  • Rule: The target must be a module name, never a package name or class name. Writing requires java.sql.DriverManager; or requires java.util; results in a compile-time error.
  • Readability: Grants the declaring module the ability to read and access exported public types from <module-name>.
  • Acyclicity: JPMS strictly prohibits cyclic dependencies. If module A requires B; and module B requires A;, both compilation (javac) and runtime startup (java) fail with a cyclic dependency error.

2. requires transitive (Implied Readability)

Implied readability allows a module to pass along its dependency to any downstream module that reads it.

// Module: com.app.repository
module com.app.repository {
    requires transitive java.sql;   // Downstream consumers gain readability to java.sql
    exports com.app.repository.api;
}

// Module: com.app.web
module com.app.web {
    requires com.app.repository;    // Implicitly gains readability to java.sql!
}
  • Semantics: If Module X declares requires transitive Y;, and Module Z declares requires X;, then Module Z automatically gains readability to Module Y without needing to write requires Y; in its own descriptor.
  • Mandatory Use Case (API Leakage): When an exported class in Module X exposes a type from Module Y in its public or protected method signatures (return types, parameter types, field types, or exceptions), Module X must declare requires transitive Y;. Without transitive, downstream consumers calling that method cannot compile because they cannot resolve the returned type.
package com.app.repository.api;
import java.sql.Connection; // From java.sql module

public class DatabaseHelper {
    // Public method returns java.sql.Connection!
    // com.app.repository MUST declare 'requires transitive java.sql;'
    public Connection getActiveConnection() {
        return null;
    }
}

3. requires static (Compile-Time Optional Dependency)

module com.app.analytics {
    requires static lombok;          // Needed during compilation only
    requires static com.optional.profiler; // Optional at runtime
}
  • Semantics: The dependency is mandatory during compilation (javac), but optional at runtime (java).
  • If the required module is absent on the module path when launching the JVM, the runtime resolves the module graph cleanly without errors.
  • If the application executes code at runtime that attempts to load classes from the missing module, a NoClassDefFoundError or ClassNotFoundException is thrown. Code should defensively check for class availability before invocation (e.g., via Class.forName() or try-catch).
  • Modifiers Combination: You can combine modifiers: requires static transitive <module-name>; or requires transitive static <module-name>;.

2. Encapsulation Directives: exports and Qualified exports ... to

Standard exports

module com.app.finance {
    exports com.app.finance.services; // Target is a PACKAGE name
    exports com.app.finance.dto;
}
  • Syntax: exports <package-name>;
  • Rule: The target must be a package name, never a module or class name.
  • Accessibility: Exposes all public and protected classes, interfaces, records, and enums in <package-name> to any module that reads com.app.finance.
  • No Subpackage Inheritance: Exporting a package does not export its subpackages. For example, exports com.app.finance; does not export com.app.finance.services or com.app.finance.internal. Every subpackage must have its own exports directive.
  • No Wildcards: Wildcard syntax like exports com.app.finance.*; is strictly forbidden by the Java compiler.
  • Internal Encapsulation: Non-public members, package-private classes, and all types inside non-exported packages remain strictly inaccessible outside the module.

Qualified Exports (exports ... to)

module com.app.core {
    // Only com.app.admin and com.app.billing can access com.app.core.internal
    exports com.app.core.internal to com.app.admin, com.app.billing;
}
  • Restricts package accessibility strictly to the specified comma-separated list of target module names.
  • Any module not in the to list cannot access the package at compile time or runtime.

3. Reflection Directives: opens and Qualified opens ... to

Frameworks relying on reflection (e.g., ORMs, JSON serializers, dependency injectors) often need access to private fields and constructors without exposing those internal implementation details as a public compile-time API.

module com.app.model {
    exports com.app.model.api;      // Accessible at compile time and runtime
    opens com.app.model.entities;   // Runtime reflection only!
    opens com.app.model.dto to com.fasterxml.jackson.databind; // Qualified opens
}
  • Syntax: opens <package-name>; or opens <package-name> to <module-name-1>, <module-name-2>;
  • Target: Must be a package name (with target module names in the to clause for qualified opens).
  • Compile-Time Isolation: Code in other modules cannot compile against classes in opened-only packages. javac treats unopened and opened-only packages as hidden.
  • Runtime Reflection: Allows other modules (or specified modules in qualified opens) to perform deep reflection (AccessibleObject.setAccessible(true)) on private, protected, and package-private elements within <package-name>.
  • Open Module Constraint: You cannot use opens inside an open module (causes a compile error).

4. Service Directives: uses and provides ... with

JPMS integrates directly with java.util.ServiceLoader to support decoupled Service Provider Interfaces (SPI).

// Service Consumer Module Descriptor
module com.app.client {
    requires com.app.spi;           // Module containing the interface
    uses com.app.spi.PaymentGateway; // Target is fully qualified INTERFACE/CLASS
}

// Service Provider Module Descriptor
module com.app.stripe.provider {
    requires com.app.spi;
    provides com.app.spi.PaymentGateway 
        with com.app.stripe.StripePaymentGateway; // Target is SPI and Implementation
}
  • uses <interface-or-class-name>;:
    • Informs the runtime that the declaring module consumes implementations of the specified interface or abstract class via ServiceLoader.load().
    • The target must be a fully qualified type name, not a module or package.
  • provides <interface-name> with <implementation-class-1>, <implementation-class-2>;:
    • Informs the runtime that this module supplies one or more concrete implementations for the service interface.
    • Multiple implementations are separated by commas.
    • The implementation class does not need to be exported in an exports directive.

5. Directives Master Reference & Exam Trap Matrix

DirectiveTarget EntityValid Target TypeCompile-Time VisibilityRuntime Deep Reflection
requires M;ModuleModule nameExported types of MOnly if opened by M
requires transitive M;ModuleModule nameExported types of M + passes to consumersOnly if opened by M
requires static M;ModuleModule nameExported types of M (Mandatory)Optional at runtime
exports P;PackagePackage namepublic/protected types to allPublic types only
exports P to M1, M2;PackagePackage name (to Modules)public/protected types to M1, M2Public types to M1, M2
opens P;PackagePackage nameNone (Hidden from javac)All members (including private)
opens P to M1;PackagePackage name (to Module)None (Hidden from javac)All members to M1 only
uses S;TypeInterface or Class nameN/A (Service Consumer)Via ServiceLoader
provides S with C;TypesInterface with Concrete ClassN/A (Service Provider)Instantiated by ServiceLoader
Loading diagram...
Implied Readability Chain via requires transitive
Test Your Knowledge

Module com.data.service contains an exported public class with the method public java.sql.Connection createConnection(). Module com.data.app declares requires com.data.service; and attempts to compile a class calling createConnection(). How must com.data.service declare its dependency on java.sql so that com.data.app compiles without an explicit requires java.sql; directive?

A
B
C
D
Test Your Knowledge

Which of the following correctly distinguishes the exports directive from the opens directive in a standard named module descriptor?

A
B
C
D
Test Your Knowledge

A developer writes exports com.myapp.orders; in a module-info.java file and expects classes in com.myapp.orders.model and com.myapp.orders.util to be accessible to external modules. What is the behavior in JPMS?

A
B
C
D
Test Your Knowledge

An application relies on a bytecode instrumentation framework for code analysis during compilation, but this framework is not required when running in production. Which directive should be used in module-info.java?

A
B
C
D