Netflix's JVM Ecosystem Team has published a preview of ja and a set of related command line tools that treat the Java Module System, rather than the class path, as the foundation of a project's description. The family is composable: ja itself supplies only command line ergonomics and orchestration, and every capability it exposes is backed by a tool that can be adopted and driven independently.

Making the module descriptor the project model

Java's build and dependency ecosystem matured around its own strong models for projects, dependencies and builds before the module system appeared, so a module descriptor has largely been treated as one more artifact to keep in agreement with everything else. The tools invert that: the descriptor becomes a complete description of the project, with dependency versions placed beside the corresponding requires directives and module metadata expressed through documentation tags.

/**
* @mainClass com.example.application.Main
*/
module com.example.application {
requires com.example.framework; // @1.2.3
}

Paired with command line ergonomics familiar from other languages, the result is a simpler path to creating and consuming modules.

A tool family you can compose as you like

Because graphical tooling covers so much of the Java workflow — formatting, navigation, API documentation, a compiled view of the project — the language has had less cause to expose the same functions as small command line utilities. Coding agents make the gap obvious, since they often fail to locate dependencies, documentation and sources. Each ja feature therefore rests on a standalone tool:

  • jig resolves module versions, compiles and assembles, emitting standard module system arguments for other tools. It also bridges Maven repositories through a standalone module proxy and publishing commands.
  • jfmt formats source according to the Code Conventions for the Java Programming Language, adapted for modern Java, and removes the whitespace, indentation, import ordering and qualified class reference problems common in agent-written code.
  • jist offers source aware symbol search — a grep-style interface over class files and their sources. It reaches symbols and sources without indexing, LSPs or MCPs, and interoperates with other build tools through an argument file contract.
  • jdocserver serves API documentation for local browsing.

All of them implement Tool or ToolProvider, so they can run in process, and they rely on the platform's tool discovery and execution mechanism. They are meant to sit in your JDK alongside the standard tools. ja uses the same model, with OptionChecker and optional custom metadata to learn which module system options each tool supports, then resolve arguments on its behalf. That yields a continuous path from your source path modules into JDK tooling such as jdeps, jlink and jshell.

Locating and naming existing artifacts

An audit of the 1,000 most popular artifacts on Maven Central found explicit module definitions in only 232 of them, with 248 more declaring automatic module names; the remaining 520 expressed no module name at all. Since the module system does not separate namespace from module name, module-first tooling has to solve naming and location for repositories as they exist.

Maven Central already supplies a verified namespace, since publishers prove control of reverse domain group IDs. The tools combine that verifiable DNS namespace with the full module name to form a canonical Maven module coordinate, such as pkg:maven/com.netflix/com.netflix.tools.ja. For modules that already exist, an author can publish a single Maven relocation pom at the canonical coordinate so the original coordinate remains discoverable. Where neither option is available, candidates are walked from the namespace root using common Maven artifact conventions to infer coordinates from module names. A short alias list covers common modules that avoid reverse DNS names, though authors are encouraged to namespace their modules. The module proxy in jig presents resolved modules using filename-based naming conventions, which makes automatic modules without stable names safe to use. Taken together, these conventions let most existing artifacts be located from a module name and version alone.

Access requirements as declared metadata

ALL-UNNAMED appears frequently in Java access options because of class path usage, and it conceals the source of the technical debt incurred — debt that matters more as Java heads toward integrity by default. Preparing to Make Final Mean Final, for instance, requires applications to explicitly authorize which modules may mutate final fields.

The tools let runtime access requirements be written as module metadata and carried with the descriptor through the module's whole lifecycle. A library can record the access it needs:

/**
* @enableFinalFieldMutation com.example.framework
*/
module com.example.framework {
}

The consuming application stays in control and must authorize the framework explicitly before it is available at runtime:

/**
* @mainClass com.example.application.Main
* @enableFinalFieldMutation com.example.framework
*/
module com.example.application {
requires com.example.framework; // @1.2.3
}

ja's command line interface supports adding dependency and authorization together:

ja require [email protected] \
--enable-final-field-mutation com.example.framework

Resolution fails with an unsatisfied access requirement when that authorization is missing. Native access follows the same pattern via @enableNativeAccess, and qualified exports and opens are supported as well.

Integrity also rests on module-info.hash, which stores persistent hashes of resolved binary dependencies; later resolution verifies them and rejects any artifact that has changed. Annotation processing goes a step beyond recent annotation processor security improvements by being treated as an explicit code generation step, so generated sources sit beside ordinary module sources, are visible in code review, and a module can be assembled without running generator code.

Getting started

The authors argue that every Java project should be modular whatever build tool it uses, and that library authors producing automatic modules should avoid split packages and publish explicit modules instead. Installation instructions are available in the project's guide.