10.3 Modular Compilation, Packaging, and CLI Execution
Key Takeaways
- Modular compilation with javac relies on --module-path (-p) to locate precompiled module dependencies and --module-source-path to compile multiple module source trees in a single atomic invocation.
- The java runtime launches modular applications using --module-path (-p) and --module (-m), specified in the standard format <module-name>/<main-class-name> or <module-name> if the main class is embedded in the modular JAR.
- The separator between module name and main class in CLI invocations is strictly a forward slash (/), regardless of operating system platform.
- The jar tool packages modular binaries, checks descriptor validity, and embeds execution metadata including the main class (--main-class) and version string (--module-version) directly into module-info.class.
- The jdeps tool performs static bytecode dependency analysis, detects missing module declarations, and scans for illegal references to deprecated internal JDK APIs with --jdk-internals.
Modular Compilation, Packaging, and CLI Execution
The Java Platform Module System introduces dedicated command-line options across standard JDK tools including javac (compiler), jar (archiver), java (launcher), and jdeps (dependency analyzer). For the 1Z0-830 exam, mastering exact CLI flag syntax, multi-module source path structures, modular JAR descriptors, runtime execution flags, and static analysis diagnostics is essential.
1. Modular CLI Options Master Matrix
Understanding the standard command-line flags and their short forms across the JDK toolset is heavily tested on the exam.
| Option / Flag | Short Flag | Tool | Description |
|---|---|---|---|
--module-path <path> | -p | javac, java, jar, jdeps | Specifies search path for application modules and modular JARs (replaces -cp / --class-path). |
--module-source-path <path> | N/A | javac | Specifies base directory containing multiple module source subdirectories. |
--module <module>[/<mainclass>] | -m | java, javac | Specifies the main module and optional main entry point class to execute or compile. |
-d <dir> | N/A | javac | Output destination directory for compiled .class files. |
--module-version <ver> | N/A | jar, javac | Embeds a version string (e.g., 2.1.0) into module-info.class. |
--main-class <class> | -e | jar | Embeds the default application entry-point class into module-info.class. |
--describe-module | -d | jar, java | Inspects and prints module descriptor metadata from a modular JAR or runtime module. |
--list-modules | N/A | java | Lists all observable platform and application modules. |
--show-module-resolution | N/A | java | Traces step-by-step module graph resolution at startup. |
--list-deps | N/A | jdeps | Analyzes and lists all modular dependencies for a class or JAR. |
--jdk-internals | N/A | jdeps | Scans for deprecated internal JDK APIs (e.g., sun.misc.*). |
2. Compiling Modular Code with javac
Modular compilation with javac can operate in single-module mode or multi-module mode.
Single-Module Compilation
When compiling a single module whose source files are located under src/com.app:
# Compiling module descriptor and source files to destination output 'mods/com.app'
javac -d mods/com.app \
src/com.app/module-info.java \
src/com.app/com/app/Main.java \
src/com.app/com/app/model/Order.java
Compiling Dependent Modules with --module-path (-p)
When compiling a module that depends on another pre-compiled module located in the mods directory:
javac -p mods \
-d mods/com.client \
src/com.client/module-info.java \
src/com.client/com/client/Runner.java
- The
-p(or--module-path) flag tellsjavacwhere to locate compiled module artifacts (module-info.classfiles or modular JARs). - The
-dflag specifies the target output directory for compiled class files.
Multi-Module Source Tree Compilation with --module-source-path
When multiple modules are developed in a single source tree, javac can compile all modules atomically in a single command using --module-source-path.
Directory Structure Requirement:
Each module source subdirectory under the source root must exactly match the module name declared in its module-info.java.
project/
└── src/
├── com.app.core/
│ ├── module-info.java
│ └── com/app/core/CoreService.java
└── com.app.client/
├── module-info.java
└── com/app/client/Main.java
# Compiles all modules defined under src into their respective mods/<module-name> subdirectories
javac --module-source-path src -d mods $(find src -name "*.java")
# Or compile specific modules from the source tree:
javac --module-source-path src -d mods --module com.app.core,com.app.client
[!NOTE] During multi-module compilation,
javacautomatically determines the inter-module dependency order and compiles dependent modules in the correct sequence.
3. Packaging Modular JARs with jar
A Modular JAR is an archive that contains a compiled module-info.class in its root directory, alongside standard compiled class files and package directories.
1. Basic Modular JAR Creation
# Create directory for packaged JARs
mkdir -p mlib
# Package the compiled module into a modular JAR
jar --create --file mlib/com.app.core.jar -C mods/com.app.core .
2. Embedding Main Class and Module Version
The jar tool allows embedding metadata directly into module-info.class:
jar --create --file mlib/com.app.client-1.0.jar \
--main-class com.app.client.Main \
--module-version 1.0.0 \
-C mods/com.app.client .
--main-class <fqcn>(or-e): Specifies the binary entry-point class.--module-version <version>: Embeds a module version string into the descriptor.
3. Updating an Existing Modular JAR
jar --update --file mlib/com.app.client-1.0.jar \
--main-class com.app.client.Main
4. Inspecting a Modular JAR with --describe-module
To verify the descriptor content of a packaged modular JAR:
jar --describe-module --file mlib/com.app.client-1.0.jar
# Or using short flags:
jar -d -f mlib/com.app.client-1.0.jar
Sample Output:
com.app.client@1.0.0 jar:file:.../mlib/com.app.client-1.0.jar!/module-info.class
exports com.app.client.api
requires com.app.core
requires java.base mandated
main-class com.app.client.Main
4. Running Modular Applications with java
The java launcher boots the Java Virtual Machine using the module path.
Execution Syntax Patterns
# Pattern 1: Full syntax with explicit module and main class
java --module-path mlib --module com.app.client/com.app.client.Main
# Pattern 2: Short flags (-p and -m)
java -p mlib -m com.app.client/com.app.client.Main
# Pattern 3: Short syntax when Main-Class is embedded in module-info.class
java -p mlib -m com.app.client
# Pattern 4: Passing application command-line arguments
java -p mlib -m com.app.client/com.app.client.Main arg1 arg2 --verbose
[!IMPORTANT] When executing via
-m <module>/<mainclass>, the forward slash (/) separates the module name from the fully qualified class name. The separator is always a forward slash/, regardless of operating system (Windows, macOS, Linux). Never use colons, semicolons, or dots as the module-to-class separator.
5. Diagnostic and Migration Flags
When running modular applications or troubleshooting migration issues, the java launcher offers specialized flags:
--show-module-resolution: Logs the module resolution process step-by-step during JVM startup, showing root modules, required modules, and resolved bindings.--list-modules: Prints all modules observable by the runtime (built-in platform modules and modules found on the module path).--add-modules <module-list>: Explicitly adds root modules to the default root set for module graph resolution (vital when running tests or loading optional modules).--add-exports <module>/<package>=<target-module>: Patches a module at runtime to export an internal package, breaking encapsulation for legacy migration.--add-opens <module>/<package>=<target-module>: Patches a module at runtime to open an internal package for deep reflection.
6. Dependency Diagnostics with jdeps
The jdeps tool analyzes static byte-code references in class files and JAR archives to discover required modules and detect illegal API usage.
# High-level module dependency summary
jdeps --summary -p mlib mlib/com.app.client-1.0.jar
# Output:
# com.app.client -> com.app.core
# com.app.client -> java.base
# List all required platform and application modules
jdeps --list-deps mlib/com.app.client-1.0.jar
# Check module descriptor for unused dependencies or missing requires
jdeps --check com.app.client -p mlib mlib/com.app.client-1.0.jar
# Scan legacy code for usage of deprecated internal JDK APIs
jdeps --jdk-internals legacy-app.jar
Understanding jdeps --jdk-internals Output
When migrating legacy libraries, jdeps --jdk-internals flags problematic classes and suggests standard replacement APIs:
legacy-app.jar -> jdk.unsupported
com.legacy.crypto.CipherUtil -> sun.misc.BASE64Encoder JDK internal API (JDK removed / encapsulated)
Suggested replacement: Use java.util.Base64
A developer needs to compile two interdependent modules (com.app and com.util) organized in a source directory tree where source files are located at src/com.app/module-info.java and src/com.util/module-info.java. Which javac command properly compiles both modules into the mods destination directory?
A modular JAR is packaged using the command: jar --create --file mlib/orders.jar --main-class com.orders.Main -C mods/com.orders .. Which command properly runs this application using the packaged entry point?
Which of the following CLI commands correctly launches a modular Java application named com.analytics with entry point class com.analytics.app.Runner located on module path dist?
Which JDK command-line tool is specifically designed to perform static bytecode dependency analysis, discover required modules, and detect deprecated internal JDK APIs?