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 uses directive is a module declaration statement within the Java Platform Module System (JPMS) that specifies a service interface or abstract class consumed by the current module. It explicitly declares the module’s intent to dynamically discover and load implementations of that service at runtime via the java.util.ServiceLoader API, establishing a consumer-provider relationship without creating a compile-time dependency on the implementation classes.

Syntax

The directive is declared exclusively within a module-info.java file. It requires the name of the service type, which can be specified as a fully qualified name or as a simple name if the type is imported prior to the module keyword (per JLS §7.3).
import com.example.serviceapi.MyService;

module com.example.consumer {
    // Requires the module containing the service interface
    requires com.example.serviceapi;
    
    // Declares the intent to consume implementations of the interface using a simple name
    uses MyService;
    
    // Alternatively, using a fully qualified name without an import:
    // uses com.example.serviceapi.AnotherService;
}

Technical Mechanics

ServiceLoader Coupling The uses directive is strictly bound to the ServiceLoader mechanism. If a module attempts to invoke ServiceLoader.load(MyService.class) without explicitly declaring uses MyService; in its module descriptor, the java.util.ServiceLoader library API will throw a java.util.ServiceConfigurationError at runtime. The uses directive authorizes the ServiceLoader to locate providers on behalf of the consumer module. It does not grant the consumer module reflective access to instantiate the provider classes directly; instantiation is handled internally by the ServiceLoader (in java.base) and is authorized by the provides directive within the provider module. Module Resolution and Binding When launching an application, the JVM constructs its boot layer using java.lang.module.Configuration.resolveAndBind(). This means standard module resolution at runtime automatically performs service binding. The JPMS will automatically pull observable provider modules from the module path into the module graph if they provide an implementation for a service declared in a resolved module’s uses directive. Conversely, when assembling a custom runtime image using the jlink tool, service binding is not performed by default. To include provider modules in a generated jlink image based on uses directives, the --bind-services command-line flag must be explicitly passed to the jlink tool. Type Constraints Per JLS §7.7.4, the type specified in the uses directive must specifically be a class or interface type. While arrays are reference types in Java, they are syntactically invalid in a uses directive. The consuming module must have access to this type. If the type is defined in an external module, the consuming module must declare a requires directive for that external module.

Compilation vs. Runtime Behavior

  • Compile-Time: The Java compiler (javac) verifies that the class or interface type specified in the uses directive exists and is accessible to the declaring module. It does not require an implementation of the service to be present on the module path during compilation.
  • Runtime: The module system utilizes the resolved module graph, augmented by automatic service binding, to locate provider classes. The consumer module remains entirely decoupled from the provider modules, interacting with them solely through the service type’s API.
Master Java with Deep Grasping Methodology!Learn More