Building & running modular apps
Directory layout, javac --module-source-path, java -m, modular jars, and module-path vs classpath.
Source layout
Convention: one directory per module under a common root, each containing its module-info.java at its own source root:
src/
com.acme.app/
module-info.java
com/acme/app/Main.java
com.acme.lib/
module-info.java
com/acme/lib/Util.java
Compiling multiple modules
javac --module-source-path src \
-d out \
$(find src -name "*.java")
--module-source-path tells javac the root where module directories live. Compiled classes land in out/com.acme.app/ etc., preserving the module structure.
Running a modular app
java --module-path out \
--module com.acme.app/com.acme.app.Main
--module-path (alias -p) is the module equivalent of --class-path. The -m / --module flag specifies <module>/<main-class>.
Modular jars
Package each module into its own jar. The --main-class and --module-version attributes can be embedded:
jar --create \
--file mods/com.acme.app.jar \
--main-class com.acme.app.Main \
--module-version 1.0 \
-C out/com.acme.app .
Once jarred, launch with:
java --module-path mods -m com.acme.app
module-path vs classpath
| | --class-path | --module-path |
|---|---|---|
| Encapsulation | None | Strong (exports only) |
| Dependency check | Runtime | Compile + runtime |
| Missing module | ClassNotFoundException at runtime | Detected at startup |
| Type | unnamed module | named or automatic module |
You can mix both flags — common during migration — but named modules cannot explicitly require the unnamed module (the unnamed module is a catch-all, not a first-class citizen).