Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Java module directives define a module’s dependencies, which of its packages other modules can access, and how it participates in service loading. The key distinction is that exports grants ordinary compile-time and run-time access to a package, while opens grants run-time reflective access. requires declares dependencies; uses and provides connect service consumers and providers.

What a module directive declares

A module descriptor, usually named module-info.java, contains a module declaration and directives. A module declaration can have an empty body, or include directives that describe three kinds of relationships:

  • Dependencies: which other modules this module needs, using requires.
  • Package access: which packages it makes accessible, using exports or opens.
  • Services: which services it consumes or implements, using uses and provides.

The Java SE 9 Language Specification groups the directives by these purposes. The examples below use illustrative names, not a tested or real application. See the Java SE 9 Language Specification, Chapter 7 for the normative Java 9 rules.

How do requires directives work?

A requires directive declares that one module depends on another. The named module must be readable to the declaring module under the module system’s rules.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Ordinary dependency

requires com.example.foo.http; declares a dependence on com.example.foo.http. Every module other than java.base has an implicit dependence on java.base, unless it declares that dependence explicitly. The java.base module itself cannot have a requires directive.

Transitive dependency

requires transitive com.example.foo.network; makes the dependency transitive for readability: modules that read the declaring module also acquire an implied dependence on com.example.foo.network. This is useful when the declaring module’s API exposes types from that dependency and its consumers need to read the dependency too. It does not export the dependency’s packages on the declaring module’s behalf.

Static dependency

requires static com.example.foo.optional; means the dependency is required at compile time but optional at run time. It does not allow compilation to succeed without the dependency when the code being compiled requires it.

When should a package be exports or opens?

Use exports when other modules should use a package’s public and protected types and members as ordinary API. Use opens when code needs run-time reflective access, such as when a framework inspects types or members, without making the package available for compile-time use by other modules.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Directive Compile-time access Run-time access Reflective access
exports package.name; Yes, to public and protected types and members Yes, to public and protected types and members Yes, to those public and protected elements
opens package.name; No Yes, to public and protected types and members Yes, to all types and members in the package

Unqualified and qualified access

An unqualified directive applies broadly:

  • exports com.example.foo.bar; makes the package’s exported API accessible to other modules.
  • opens com.example.foo.quux; opens the package for run-time reflection generally.

A qualified directive names the modules that receive access:

  • exports com.example.foo.internal to com.example.foo.probe; exports that package only to the listed module.
  • opens com.example.foo.internal to com.example.foo.network, com.example.foo.probe; opens it for reflection only to the listed modules.

An unqualified export is a broad API commitment. The Java SE 9 specification identifies unqualified exports, along with transitive dependencies, as elements of a module’s primary API. Qualified exports and opens let a module grant narrower access where that fits its design.

What an open module changes

open module com.example.foo { ... } opens all packages in the module for run-time reflection, as though each package had an opens directive. It does not export all packages for compile-time use. Other modules still get compile-time access only to packages the descriptor explicitly exports; individual opens directives can therefore be omitted from an open module.

How do uses and provides support services?

These directives describe the consumer and provider sides of the service-loading model:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • uses com.example.foo.spi.Intf; declares that the module consumes the service represented by that type.
  • provides com.example.foo.spi.Intf with com.example.foo.Impl; declares that the module supplies an implementation of the service. A provider can list one or more implementations.

The consumer declares uses; the module supplying an implementation declares provides ... with. This lets service users and providers be decoupled through ServiceLoader, rather than requiring the consumer to name a particular implementation. See Dev.java’s Modules guide for an introduction to module relationships and services.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Putting the directives together

This illustrative descriptor groups dependencies, package access, and service declarations in one module:

module com.example.foo {
    requires com.example.foo.http;
    requires java.logging;
    requires transitive com.example.foo.network;

    exports com.example.foo.bar;
    exports com.example.foo.internal to com.example.foo.probe;

    opens com.example.foo.quux;
    opens com.example.foo.internal to com.example.foo.network,
                                  com.example.foo.probe;

    uses com.example.foo.spi.Intf;
    provides com.example.foo.spi.Intf with com.example.foo.Impl;
}

Read it by purpose: the first three directives declare dependencies; the exports and opens directives define package access; the final two directives declare service consumption and provision. Each directive expresses a different relationship, so choosing one depends on whether the need is readability, ordinary API access, reflective access, or service loading.

For Java 9 syntax and exact language rules, consult the Java SE 9 JLS, Chapter 7. For an introductory explanation, see Oracle Java Magazine, September/October 2017.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.