Lesson 48 • Expert
CLI Tools with Java
Build professional command-line tools using picocli — argument parsing, subcommands, and native images.
Before You Start
You should know IO & NIO (file operations), Exception Handling (error reporting), and Deployment (JAR packaging). Familiarity with Annotations helps since picocli is annotation-driven.
What You'll Learn
- ✅ Parsing command-line arguments manually and with picocli
- ✅ Options, positional parameters, and type conversion
- ✅ Subcommands and nested command hierarchies
- ✅ ANSI colors, progress bars, and interactive prompts
- ✅ Input validation and meaningful error messages
- ✅ GraalVM native-image for instant startup
1️⃣ Why picocli?
Analogy: Parsing command-line arguments manually is like building a house from raw lumber — you can do it, but why? picocli is like a pre-fab kit: define your options with annotations, and picocli handles parsing, validation, help text, tab completion, and colored output automatically.
| Approach | Lines of Code | Features | Maintenance |
|---|---|---|---|
| Manual args[] | 100+ lines | Basic parsing only | High (all edge cases on you) |
| Apache Commons CLI | 30-50 lines | Options, help text | Medium (older API) |
| picocli | 10-20 lines | Everything + colors + completion | Low (annotation-driven) |
Try It: Argument Parser Simulator
// 💡 Try modifying this code and see what happens!
// CLI Argument Parser
console.log("=== CLI Argument Parsing ===\n");
// 1. Manual parsing (the hard way)
console.log("1. MANUAL PARSING (Don't do this in production!):");
function parseArgs(args) {
let result = { options: {}, positional: [] };
for (let i = 0; i < args.length; i++) {
if (args[i].startsWith("--")) {
let key = args[i].substring(2);
let hasValue = args[i + 1] && !args[i + 1].startsWith("-");
result.optio
...Try It: Subcommands & CLI Simulation
// 💡 Try modifying this code and see what happens!
// Subcommands and interactive CLI
console.log("=== Subcommands & CLI Execution ===\n");
// 1. Subcommand hierarchy
console.log("1. SUBCOMMAND HIERARCHY (like git):");
console.log(` @Command(name = "mytool", subcommands = {
UserCommand.class,
ConfigCommand.class
})
class MyTool implements Runnable { ... }
@Command(name = "user", subcommands = {
UserCreateCommand.class,
UserListCommand.class,
UserDeleteComm
...Try It: ANSI Colors & GraalVM Native
// 💡 Try modifying this code and see what happens!
// ANSI output and GraalVM native compilation
console.log("=== ANSI Colors & Native Images ===\n");
// 1. ANSI color output
console.log("1. ANSI COLORS IN CLI:");
console.log(` // picocli supports ANSI markup
System.out.println(CommandLine.Help.Ansi.AUTO.string(
"@|bold,green ✅ Success!|@ File processed."));
System.out.println(CommandLine.Help.Ansi.AUTO.string(
"@|bold,red ❌ Error:|@ File not found."));
System.out.println(Co
...Common Beginner Mistakes
- ❌ Not providing --help — users expect it. picocli's
mixinStandardHelpOptions = trueadds it automatically - ❌ Printing errors to stdout — errors go to
System.err, normal output toSystem.out. This allows users to redirect output properly - ❌ Ignoring exit codes — scripts depend on exit codes. Return 0 for success, non-zero for errors
- ❌ Hardcoding file paths — use
@Parametersfor file arguments. Support stdin with-as a conventional filename - ❌ No input validation messages — picocli validates types automatically, but add custom validation with clear error messages for business rules
Pro Tips
- 💡 Tab completion — picocli generates bash/zsh completion scripts with
AutoComplete.bash("mytool", new MyTool()). Huge UX improvement! - 💡 Config file + CLI args — use
@PropertiesDefaultProviderto load defaults from a config file, overridable by CLI args - 💡 Interactive mode — picocli supports
@Option(interactive = true)for passwords. Prompts the user and hides input - 💡 man pages — picocli can generate AsciiDoc man pages from your annotated commands. Professional documentation for free!
📋 Quick Reference
| Feature | picocli Annotation | Example |
|---|---|---|
| Named option | @Option(names = {"-n", "--name"}) | --name Alice |
| Positional arg | @Parameters(index = "0") | file.txt |
| Subcommand | @Command(subcommands = ...) | git commit |
| Default value | defaultValue = "10" | Fallback if not provided |
| Password | @Option(interactive = true) | Hidden input prompt |
| Completion | AutoComplete.bash() | Tab completion script |
🎉 Lesson Complete!
You can now build professional CLI tools with picocli! You understand options, subcommands, ANSI output, and GraalVM native compilation. Next: Clean Architecture — designing maintainable, testable applications with SOLID and DDD.
Sign up for free to track which lessons you've completed and get learning reminders.