Over time, local Maven repositories (located by default at ~/.m2/repository) accumulate gigabytes of cached JARs, POMs, and dependencies. Inspecting or filtering these cached artifacts using traditional terminal commands like find or ls can be cumbersome—especially when searching for specific versions or group IDs.

In this tutorial, we will build a lightweight, self-contained Java CLI script using JBang and Java 21 that rapidly scans, filters, and summarizes your local Maven artifacts.

⚡ Quick Summary / Key Features

  • No Compilation Setup: Run directly as a single-file Java script via JBang.
  • Keyword Filtering: Filter artifacts by framework name (e.g., wildfly, quarkus, spring).
  • Cross-Platform: Works out-of-the-box on Linux, macOS, and Windows.
  • Powered by Picocli: Features clean command-line argument parsing via //DEPS info.picocli:picocli.

1. Complete JBang Script Source Code

Create a file named ListM2Artifacts.java and insert the following Java 21 implementation:

///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 21
//DEPS info.picocli:picocli:4.7.6

import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;

import java.nio.file.*;
import java.util.concurrent.Callable;

@Command(
    name = "ListM2Artifacts",
    mixinStandardHelpOptions = true,
    version = "1.0",
    description = "Scans and filters local Maven repository (~/.m2/repository) artifacts."
)
public class ListM2Artifacts implements Callable<Integer> {

    @Option(
        names = {"-f", "--filter"},
        description = "Filter artifacts by keyword (e.g. 'wildfly', 'quarkus', 'jackson')"
    )
    private String filter = "";

    @Option(
        names = {"-m", "--m2-path"},
        description = "Override default Maven local repository path (~/.m2/repository)"
    )
    private Path customM2Path;

    public static void main(String... args) {
        int exitCode = new CommandLine(new ListM2Artifacts()).execute(args);
        System.exit(exitCode);
    }

    @Override
    public Integer call() throws Exception {
        Path repoPath = customM2Path != null 
            ? customM2Path 
            : Paths.get(System.getProperty("user.home"), ".m2", "repository");

        if (!Files.exists(repoPath)) {
            System.err.println("❌ Local Maven repository not found at: " + repoPath);
            return 1;
        }

        System.out.println("🔍 Scanning Maven repository: " + repoPath);
        if (!filter.isBlank()) {
            System.out.println("🔎 Active filter keyword: '" + filter + "'");
        }
        System.out.println("--------------------------------------------------");

        try (var stream = Files.walk(repoPath)) {
            long count = stream
                .filter(Files::isRegularFile)
                .filter(p -> p.toString().endsWith(".jar") || p.toString().endsWith(".pom"))
                .map(repoPath::relativize)
                .map(Path::toString)
                .map(p -> p.replace('\\', '/'))
                .filter(p -> filter.isBlank() || p.toLowerCase().contains(filter.toLowerCase()))
                .peek(System.out::println)
                .count();

            System.out.println("--------------------------------------------------");
            System.out.println("📊 Total matching artifacts found: " + count);
        }

        return 0;
    }
}

2. Running the Script

Execute the script directly using JBang without needing to build a Maven project or configure classpaths manually:

Basic Usage (List All Cached Artifacts):

$ jbang ListM2Artifacts.java

Filter by Keyword (e.g., Find all WildFly or Quarkus artifacts):

$ jbang ListM2Artifacts.java --filter=wildfly

# Output example:
# org/wildfly/core/wildfly-core-model-test/23.0.1.Final/wildfly-core-model-test-23.0.1.Final.jar
# org/wildfly/plugins/wildfly-jar-maven-plugin/11.0.2.Final/wildfly-jar-maven-plugin-11.0.2.Final.pom
# --------------------------------------------------
# 📊 Total matching artifacts found: 42

Custom Maven Repository Directory:

$ jbang ListM2Artifacts.java --m2-path=/opt/custom-maven-repo --filter=jakarta

3. Command-Line Options Summary

Option / Flag Description Example
-f, --filter Filters artifact paths matching the specified substring. -f spring-boot
-m, --m2-path Overrides the default ~/.m2/repository directory path. -m D:/maven/repo
-h, --help Displays automatically generated CLI help options. --help

4. Compiling to a Standalone Native Binary (`//NATIVE`)

If you want instant response times without invoking the JVM startup sequence every time, compile the JBang script into a native executable binary using GraalVM:

$ jbang build --native ListM2Artifacts.java

After compilation completes, run the native binary directly:

$ ./ListM2Artifacts --filter=keycloak

Frequently Asked Questions (FAQs)

Q1: Can I run this script on Windows Command Prompt or PowerShell?

Yes. The script normalizes Windows file path backslashes (\) into standard Unix forward slashes (/), ensuring consistent filter matching across Windows, macOS, and Linux.

Q2: How does JBang handle the Picocli dependency?

JBang reads the //DEPS info.picocli:picocli:4.7.6 directive, automatically downloads the dependency from Maven Central on the first run, and caches it locally for subsequent executions.

Q3: How do I export or install this script globally on my machine?

You can publish or install the script globally using JBang's app alias command: jbang app install ListM2Artifacts.java. After installation, you can invoke ListM2Artifacts directly from any directory in your shell.

Conclusion

By leveraging JBang, Java 21 NIO Streams, and Picocli, you can build clean, powerful system utilities in a single file without the overhead of maintaining full Maven or Gradle project structures.