Study guide
12.1 Module Architecture, `module-info.java`, and Module Paths
Oracle Java SE 17 Developer Certified Professional 1Z0-829
Track your progress as you read
Finished sections get a check mark.
1 Introduction: The 1Z0-829 Exam
About the Java SE 17 Developer (1Z0-829) Exam
2 Chapter 1: Java Fundamentals & Language Basics
1.1 Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting 1.2 Local Variable Type Inference (`var`) Rules and Scoping 1.3 Operators, Precedence, Evaluation Order, and Short-Circuit Evaluation 1.4 Text Blocks, String Immutability, and StringBuilder APIs
3 Chapter 2: Program Flow & Decision Constructs
2.1 Conditional Branching with if/else and the Ternary Operator 2.2 Switch Statements and Switch Expressions 2.3 Iteration Constructs, Loop Control, and Branching Labels
4 Chapter 3: Object-Oriented Design & Class Mechanics
3.1 Class Declarations, Field/Method Signatures, and Access Modifiers 3.2 Constructors, Overloading, Initialization Order, and Garbage Collection 3.3 Inheritance, Method Overriding, Polymorphism, and `super`/`this` 3.4 Abstract Classes, Static Members, and Object Methods (`equals`, `hashCode`, `toString`)
5 Chapter 4: Advanced OOP: Interfaces, Records & Sealed Types
4.1 Interface Architecture: Default, Static, and Private Methods 4.2 Enumerations: Constants, Constructors, Methods, and Custom Bodies 4.3 Records: Canonical/Compact Constructors, Components, and Immutability 4.4 Sealed Classes and Interfaces: `permits`, Hierarchy Constraints, and Modifiers
6 Chapter 5: Pattern Matching & Nested Types
5.1 Pattern Matching for `instanceof` and Flow Scoping Mechanics 5.2 Nested Types: Member Inner, Static Nested, Local, and Anonymous Classes 5.3 Defensive Programming, Immutability Patterns, and Validation
7 Chapter 6: Generics, Collections & Arrays
6.1 Generic Classes, Interfaces, Methods, and Type Erasure 6.2 Bounded Type Parameters and Wildcards (PECS Rule) 6.3 Collections Framework: List, Set, Queue, and Deque APIs 6.4 The Map Interface, Sorting, Comparable, and Comparator 6.5 Arrays: Declaration, Initialization, Multidimensional Arrays, and the Arrays Utility Class
8 Chapter 7: Functional Programming & Lambda Expressions
7.1 Functional Interfaces and Lambda Syntax Rules 7.2 Standard Functional Interfaces in `java.util.function` 7.3 Method References: Static, Bound, Unbound, and Constructor References
9 Chapter 8: The Stream API
8.1 Stream Lifecycle: Creation, Pipeline Architecture, and Lazy Evaluation 8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing 8.3 Terminal Stream Operations: Reduction, Matching, Finding, and Collecting 8.4 Primitive Streams (`IntStream`, `LongStream`, `DoubleStream`) and Numeric Statistics
10 Chapter 9: Advanced Streams & Collectors
9.1 The Optional Class: Safe Null Handling, Transformation, and Chaining 9.2 The Collectors API: Downstream Reductions, Grouping, and Partitioning 9.3 Parallel Streams: Fork/Join Pool, Spliterators, and Concurrency Pitfalls
11 Chapter 10: Exception Handling
10.1 The Java Exception Hierarchy: Checked vs. Unchecked Exceptions and Errors 10.2 Exception Constructs: `try-catch-finally`, Multi-Catch, and Rethrowing 10.3 Try-With-Resources, `AutoCloseable`, Suppressed Exceptions, and Custom Exceptions
12 Chapter 11: Date/Time API & Localization
11.1 Date and Time Core Types: `LocalDate`, `LocalTime`, `LocalDateTime` 11.2 Timestamps, Intervals, and Durations: `Instant`, `Period`, and `Duration` 11.3 Time Zones, Daylight Saving Time (DST) Offsets, and `ZonedDateTime` 11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters 11.5 Formatting and Parsing Messages, Numbers, Percentages, and Localized Dates
13 Chapter 12: Java Platform Module System (JPMS)
12.1 Module Architecture, `module-info.java`, and Module Paths 12.2 Module Directives: `requires`, `requires transitive`, `exports`, and Qualified Exports 12.3 Reflection, Deep Encapsulation, `opens`, and Open Modules 12.4 Services in JPMS (`uses`, `provides...with`), Migration Paths, and Tooling (`jlink`, `jdeps`) 12.5 Compiling and Packaging Code: Non-Modular JARs, Modular JARs, and Migration Strategies
14 Chapter 13: Concurrency & Multithreading
13.1 Thread Fundamentals, `Runnable`, `Callable`, and Thread Lifecycle 13.2 Memory Visibility, `volatile`, Intrinsic Locks, and Synchronization 13.3 The Concurrency Framework: `ExecutorService`, Thread Pools, and `Future` 13.4 Concurrent Collections, Atomic Variables, Explicit Locks, and `CompletableFuture`
15 Chapter 14: Java I/O and NIO.2
14.1 Classical I/O: Byte and Character Streams, Readers, Writers, and Buffering 14.2 Object Serialization, `Serializable`, `transient`, and `serialVersionUID` 14.3 NIO.2 Architecture: `Path`, `Paths`, and Basic `Files` Operations 14.4 Advanced NIO.2: Directory Walking, Streams (`Files.lines`, `walk`), and `WatchService`
16 Chapter 15: Accessing Databases with JDBC
15.1 JDBC Architecture, Drivers, `DriverManager`, and `DataSource` Connections 15.2 SQL Execution: `Statement`, `PreparedStatement`, and `CallableStatement` 15.3 `ResultSet` Navigation, Data Types, and Transaction Management (Commit, Rollback, Savepoints)
17 Chapter 16: Annotations & the Java Logging API
16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs 16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration
12.1 Module Architecture, `module-info.java`, and Module Paths
Key Takeaways Explain This Topic AI
The Java Platform Module System (JPMS) solves 'JAR hell' and classpath fragility by introducing reliable configuration and strong encapsulation at the JVM and compiler levels.
The module declaration file, module-info.java, must reside at the root of the module source hierarchy and compiles into module-info.class at the root of the output directory or JAR.
The module-path (--module-path or -p) locates modular artifacts and validates dependencies at startup, contrasting with the linear, unencapsulated class search of the classpath.
Compilation and packaging commands (javac and jar) require explicit module flags (--module-source-path, -d, --module, --main-class) to build and run modular binaries.
JPMS strictly forbids circular dependencies among modules at compile time and link time, aborting immediately if cycles are detected.
Last updated: October 2026
Module Architecture, module-info.java , and Module Paths
The Java Platform Module System (JPMS), introduced in Java 9 via Project Jigsaw and refined through Java 17 LTS, represents the most significant architectural evolution of the Java runtime environment since its inception. Prior to modularization, Java applications suffered from fundamental scalability and security liabilities known collectively as "JAR hell." JPMS replaces implicit runtime classloading assumptions with an explicit, compiler-enforced contract of module boundaries.
Motivation and Core Architectural Goals
For over two decades, Java applications relied exclusively on the classpath . The classpath model suffered from three primary architectural flaws that JPMS directly resolves:
Fragile, Linear Class Loading ("Classpath Hell") :
When locating classes, the JVM scans classpath entries sequentially from left to right. If two JAR files contain a class with the identical fully qualified name (e.g., due to conflicting library versions), whichever JAR appears first on the classpath satisfies the classloader, silently shadowing the second. Furthermore, missing dependencies are not detected at application startup; they manifest as runtime ClassNotFoundException or NoClassDefFoundError instances hours or days after deployment when an unreferenced code path executes.
Monolithic JDK Runtime :
Before Java 9, the entire Java runtime library was packaged into massive, monolithic binaries—chiefly rt.jar (runtime) and tools.jar —exceeding 60 megabytes. Even trivial command-line utilities or microservices were forced to load or bundle the entire Java standard library, including desktop GUI stacks ( java.desktop ) and CORBA legacy subsystems. JPMS dismantled rt.jar , partitioning the JDK into dozens of distinct modules (such as java.base , java.sql , java.logging , and java.net.http ).
Lack of True Encapsulation :
In the legacy model, access modifiers were bounded only by package scope. Any class marked public was accessible to every other class on the classpath. Internal JDK implementation classes (such as sun.misc.Unsafe or internal security adapters) could not be hidden from user code, creating fragile couplings that hindered JVM evolution.
The Two Pillars: Reliable Configuration and Strong Encapsulation
JPMS establishes two foundational pillars:
Reliable Configuration : Explicit dependency graphs declared in module descriptors are verified by the compiler and at JVM launch before main() executes. If any required module is absent, duplicate, or creates an illegal dependency, execution aborts immediately.
Strong Encapsulation : A public class within a module is no longer universally public. It is accessible outside its parent module only if its containing package is explicitly exported by that module, and the consuming module explicitly declares a readability requirement on it.
Anatomy of module-info.java
A module is a uniquely named, self-describing collection of code and data. The descriptor is defined in a special file named module-info.java .
Placement and Structure
The module-info.java file must reside in the root of the module's source folder hierarchy, directly alongside the top-level package directories (never inside a package subfolder). When compiled, it produces module-info.class , which must reside in the root of the compiled output directory and at the root of the resulting modular JAR file. project-root/
- └── src/
- └── com.example.billing/
- ├── module-info.java
- └── com/
- └── example/
- └── billing/
- ├── InvoiceService.java
- └── internal/
- └── TaxCalculator.java
The declaration uses the module contextual keyword followed by the module identifier and a body enclosed in braces: module com.example.billing {
- // Module directives: requires, exports, opens, uses, provides
- }
Note
module , requires , exports , opens , uses , provides , with , and to are restricted contextual keywords . They act as keywords only within the context of a module-info.java file. In regular Java source code, you can freely use these terms as variable or method identifiers (e.g., int module = 42; or void exports() {} ).
Module Naming Rules and Conventions
Module names follow reverse domain name notation (e.g., com.example.billing ), mirroring standard package conventions. However, the compiler enforces strict identifier syntax:
Module names consist of one or more identifiers separated by dots ( . ).
Each identifier segment must be a valid Java identifier: it cannot start with a digit, cannot contain hyphens ( - ), and cannot match reserved Java keywords.
Hyphens are strictly forbidden in module names in source declarations. A declaration like module com.example-app { } produces a compilation error. (Tools automatically convert hyphens to dots when deriving automatic module names from JAR filenames).
Classpath vs. Module-Path
Understanding how the JVM resolves code requires distinguishing between the classpath and the module-path.
- Characteristic Classpath ( --class-path , -cp , -classpath ) Module-Path ( --module-path , -p )
- Mechanism Sequential, flat search across directories and JARs Graph-based resolution of named module artifacts
Encapsulation None; all public classes are globally accessible Strict; unexported packages are inaccessible outside the module
Dependency Check Lazy, runtime discovery upon class referencing Strict startup validation; aborts immediately if dependencies fail
Package Integrity Permits split packages across different JAR files Forbids split packages; identical package names abort loading
Descriptor File Ignores module-info.class if present; treated as flat JAR Requires or synthesizes module definitions ( module-info.class )
Target Environment Legacy code executing inside the Unnamed Module Modern modular code executing inside Named Modules
Modular applications are executed using the --module-path (or -p ) option to supply the modules, and --module (or -m ) to designate the initial module and main class: java --module-path mods --module com.example.billing/com.example.billing.Main
# Equivalent short-form syntax:
- java -p mods -m com.example.billing/com.example.billing.Main
- Compiling, Packaging, and Running Modular Applications
Working with modular source code introduces specific command-line options for javac , jar , and java .
1. Compiling Modular Code
When compiling a single module, compile module-info.java alongside the module's source files: javac -d out/com.example.billing \
- src/com.example.billing/module-info.java \
- src/com.example.billing/com/example/billing/*.java
When compiling multiple modules simultaneously, use the --module-source-path flag to point to the directory containing module subfolders: javac -d out --module-source-path src $(find src -name "*.java")
The compiler automatically maps each subdirectory in src to its corresponding module output under out .
2. Packaging Modular JARs
A modular JAR is identical to a standard JAR except that it contains module-info.class at its root. You can record the application's main entry point directly into the modular JAR using the --main-class attribute: jar --create --file=lib/billing.jar \
--main-class=com.example.billing.Main \
-C out/com.example.billing .
- To inspect the compiled module descriptor inside a modular JAR: jar --describe-module --file=lib/billing.jar
- 3. Executing Modular Applications
If the modular JAR was packaged with --main-class , the class name can be omitted from the -m option: java -p lib -m com.example.billing
Prohibition of Circular Module Dependencies
One of JPMS's most uncompromising design constraints is the absolute prohibition of circular dependencies at compile time and link time. [module A] ---> requires ---> [module B]
- ^ |
- | |
- +---------- requires ----------+
If module A requires module B , and module B requires module A (either directly or indirectly through a chain of dependencies), the compiler fails immediately: error: cyclic dependence involving com.example.alpha and com.example.beta
Warning
The Circularity Trap Circular dependencies cannot be circumvented using requires transitive , qualified exports, or runtime flags. The module system constructs a Directed Acyclic Graph (DAG) during layer resolution. If a cycle is present, the module layer cannot be instantiated. Developers must refactor common dependencies into a shared independent module or decouple implementations using JPMS service providers ( uses and provides ).