Modules Make javac Easy

by: Ethan McCue

If you use Java modules, using javac to compile your code is easy.

I figure this wouldn't be known widely - its not that popular for people to use javac directly these days - but its interesting.

Without Modules

javac compiles any files you list in its invocation.

javac -d build src/Main.java src/Other.java

If the other source files are referenced from the ones you listed, you can use --source-path and javac will find the others.

 # Will find src/Other.java so long as Main uses it
javac -d build \
    --source-path src \
    src/Main.java

But, if your source files might not directly reference each other, you need to list every file in your project. That turns into something like this.

javac -d build \
    $(find . -name "*.java" -type f)

Which, while functional, doesn't inspire joy.

With Modules

All of the above methods work, even if you have a module-info.java.

But, if you lay out your code like this

example.mod/
  module-info.java
  example/
    mod/
      A.java
      B.java
      C.java

I.E. with a directory that has the same name as the module within it - then javac can automatically find and compile your code.

javac \
    -d build \
    --module-source-path . \
    --module example.mod

So --module-source-path tells it where to find all the code for a module and --module tells it what module you want to compile.

If you wanted all your code in a src/ folder you can do that as well. You just need to tweak the --module-source-path argument.

example.mod/
  src/
    module-info.java
    example/
      mod/
        A.java
        B.java
        C.java
javac \
    -d build \
    --module-source-path "./*/src" \
    --module example.mod

Where this becomes actually pretty cool is if you have more than one module.

Just put all your project's modules on the same level.

example.mod/
  src/
    module-info.java
    example/
      mod/
        A.java
 
other.mod/
  src/
    module-info.java
    other/
      mod/
        B.java

Now javac can compile more than one module at the same time.

javac \
    -d build \
    --module-source-path "./*/src" \
    --module example.mod,other.mod

If modules require each other - like if example.mod requires other.mod - then all modules will be compiled automatically.

Other Tools

Once you've laid out your code like this other tools, like javadoc, will also be able to automatically discover code for your modules

javadoc \
    -d docs \
    --module-source-path "./*/src" \
    --module example.mod,other.mod

Isn't that neat?

Wrap Up

This leaves off some crucial bits - like how you would get dependencies or run unit tests - but compare it holistically to setting up a multi-module build in Maven. Or Gradle. Or bld. Or whatever.

At least to me this feels way less painful. Worthy of a closer look.

I made a repo with a basic version of this setup here. All the commands you would run are in the Justfile. I also threw in making jars + including resources.


<- Index