Skip to content

Source Modules

Danny Thomas edited this page Sep 17, 2026 · 2 revisions

Source modules

We allow a module-info.java file to describe everything needed to resolve, compile and assemble a module. As the module system does not include dependency versions in requires directives, we append a // @version comment record them:

/**
 * @release 21
 * @mainClass com.example.cli.Main
 */
module com.example.cli {
    requires com.example.library; // @1.2.3
}

Dependency versions also participate in transitive resolution. Conflicts follow Maven's nearest-wins rule, after which the module system validates the selected graph. Module Javadoc tags record additional metadata that also cannot be expressed by standard module directives:

  • @release selects the Java release used for compilation
  • @mainClass declares the entry point used by module=main and main-class
  • @enablePreview enables preview compilation

Without @release, compilation uses the consuming toolchain's default release. Preview features require @release to match the running JDK.

Runtime access

Following Integrity by Default, runtime access that can weaken module integrity must be authorized by a selected root module.

Record access requirements that cannot be expressed by standard module directives with module Javadoc tags:

Tag Compiler option Launcher option
@enableNativeAccess module - --enable-native-access=module
@enableFinalFieldMutation module - --enable-final-field-mutation=module
@addOpens module/package=target - --add-opens module/package=target
@addExports module/package=target --add-exports module/package=target --add-exports module/package=target
/**
 * @enableNativeAccess com.example.lib
 * @addOpens java.base/java.lang=com.example.framework
 */
module com.example.framework {
    requires com.example.lib; // @1.0.0
}

When jig compiles a source module, it stores these requirements in the generated module-info.class as a com.netflix.module.ModuleRuntimeAccess attribute. The requirements therefore travel with published JARs and JMODs.

Recording a requirement does not authorize it. A published dependency cannot authorize its own access. Authorization must come from an explicitly selected source root or the corresponding command-line option, and is not inherited through requires directives. System modules are trusted, so requirements recorded in the current runtime image are applied automatically.

--validate-runtime-access checks the requirements of every module in the resolved graph against those authorizations. Resolution fails when a non-system module requirement has not been authorized. Validation does not emit runtime access options; request each required option explicitly with -r.

Every operand must refer to modules and, where applicable, packages in the resolved configuration. Broad pseudo-modules such as ALL-UNNAMED are not supported.

Annotation processors

Declare an annotation processor with requires static and select it with @processWith:

/** @processWith com.example.processor */
module com.example.application {
    requires static com.example.processor; // @1.2.3
}

requires static makes the processor available during compilation without adding it to the runtime graph.

Requesting processor-module-path places the selected processor and its dependencies on --processor-module-path. The processor may be a source module or a published module.

The selected module must provide javax.annotation.processing.Processor through its module descriptor or service configuration. Resolution fails if the module is absent from the graph or does not provide that service.

Source module paths

Point to a directory whose immediate subdirectories are source modules:

jig --module-source-path src -m com.example.app

Map module names to source directories explicitly:

jig --module-source-path com.example.app=app/src/main/java \
  --module-source-path com.example.core=core/src/main/java \
  --module-source-path com.example.api=api/src/main/java \
  -m com.example.app

A wildcard can substitute the module name:

jig --module-source-path 'src/*/main/java' -m com.example.app

--module-source-path may be repeated, and the forms may be combined.

Source options

Request source-path to combine the source directories of selected local modules with sources artifacts resolved for published modules. A missing optional sources artifact does not affect module resolution.

Verify dependency integrity

An optional module-info.hash file alongside module-info.java records the expected content hash of each resolved binary dependency:

com.example.lib=module:sha256:a1b2c3d4e5f6...
org.apache.commons.io@2.15.1=module:sha256:f6a7b8c9d0e1...

The key is the module name followed by the version reported by its descriptor when present. Two flags control the creation and validation of the module-info.hash file:

  • --update-module-hashes reconciles the file with the resolved --module-path. It verifies retained dependencies, adds new dependencies, and removes entries that are no longer present.
  • --verify-module-hashes requires every dependency on the resolved binary --module-path to have one matching entry. Entries for dependencies that are no longer resolved are permitted

Clone this wiki locally