Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The provides directive is a module declaration statement within the Java Platform Module System (JPMS) used to declare that a module provisions one or more implementations of a specific service type (which can be an interface, an abstract class, or a concrete class). It acts as the service provider mechanism in a modular Java application, instructing the JVM’s ServiceLoader to discover and instantiate these implementations at runtime.

Syntax

The directive is declared exclusively within a module-info.java file using the provides ... with ... syntax.
module <module-name> {
    provides <fully-qualified-service-type> with <fully-qualified-provider-type>;
}
Multiple provider implementations for a single service can be declared by separating the provider types with a comma:
module <module-name> {
    provides <fully-qualified-service-type> 
        with <provider-type-one>, 
             <provider-type-two>;
}

Technical Constraints and Mechanics

To successfully compile and execute a module using the provides directive, the following strict rules defined by the Java Language Specification (JLS) apply: 1. Module Location The <provider-type> specified after the with keyword must be declared within the current module. A module cannot provide an implementation that resides in a different module. 2. Visibility Requirements The <provider-type> must be a public class or interface. If the provider type is a nested type, it must be declared static. 3. Instantiation Rules and Type Compatibility Because the ServiceLoader must instantiate the provider at runtime, the <provider-type> must satisfy one of the following two structural requirements:
  • Provider Method: The <provider-type> declares a public static method named provider() that takes no arguments. The return type of this method must be the <service-type> or a subtype of the <service-type>.
    • Note: When the provider() method is present, the <provider-type> itself can be an interface or an abstract class, and the <provider-type> does not need to implement or extend the <service-type>. The ServiceLoader will invoke this method to obtain the service instance.
  • No-Argument Constructor: If no provider() method is present, the <provider-type> must be a concrete class (it cannot be abstract or an interface). Furthermore, it must strictly implement or extend the <service-type>, and it must declare a public constructor with zero arguments.
4. Encapsulation The package containing the <provider-type> does not need to be exposed via an exports directive. The provides directive grants the ServiceLoader deep reflective access to instantiate the class or invoke the provider() method, maintaining strong encapsulation of the implementation details from other modules. 5. Module Dependencies If the <service-type> resides in a separate module, the module declaring the provides directive must be able to read the module containing the service type. This readability does not strictly require a direct requires directive for the API module itself; it can be achieved implicitly (e.g., if the service type is in java.base) or via implied readability (e.g., by reading an intermediate module that declares requires transitive for the API module).

Structural Example

// module-info.java
module org.myapp.database.postgres {
    // Reads the module containing the DatabaseDriver service type
    requires org.myapp.database.api;
    
    // Declares the implementation
    provides org.myapp.database.api.DatabaseDriver 
        with org.myapp.database.postgres.internal.PostgresDriverImpl;
}
In this structure, org.myapp.database.postgres.internal.PostgresDriverImpl remains strongly encapsulated and hidden from other modules at compile-time and runtime, but the JVM registers it as an available implementation of DatabaseDriver during module resolution.
Master Java with Deep Grasping Methodology!Learn More