Command Line Subcommands in Java

Here’s the translation of the Go code to Java, with explanations in Markdown format suitable for Hugo:

Our first program demonstrates how to create command-line subcommands with their own set of flags. This is similar to tools like git where different subcommands (e.g., git commit, git push) have their own specific flags.

import java.util.Arrays;

public class CommandLineSubcommands {
    public static void main(String[] args) {
        // We use Apache Commons CLI for flag parsing in Java
        // You need to add this dependency to your project
        // <dependency>
        //     <groupId>commons-cli</groupId>
        //     <artifactId>commons-cli</artifactId>
        //     <version>1.4</version>
        // </dependency>

        // We declare options for each subcommand
        Options fooOptions = new Options();
        fooOptions.addOption("enable", false, "enable");
        fooOptions.addOption("name", true, "name");

        Options barOptions = new Options();
        barOptions.addOption("level", true, "level");

        // The subcommand is expected as the first argument to the program
        if (args.length < 1) {
            System.out.println("expected 'foo' or 'bar' subcommands");
            System.exit(1);
        }

        // Check which subcommand is invoked
        String subcommand = args[0];
        String[] subcommandArgs = Arrays.copyOfRange(args, 1, args.length);

        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();

        try {
            switch (subcommand) {
                case "foo":
                    // For every subcommand, we parse its own flags and
                    // have access to trailing positional arguments
                    CommandLine cmd = parser.parse(fooOptions, subcommandArgs);
                    System.out.println("subcommand 'foo'");
                    System.out.println("  enable: " + cmd.hasOption("enable"));
                    System.out.println("  name: " + cmd.getOptionValue("name"));
                    System.out.println("  tail: " + Arrays.toString(cmd.getArgs()));
                    break;
                case "bar":
                    cmd = parser.parse(barOptions, subcommandArgs);
                    System.out.println("subcommand 'bar'");
                    System.out.println("  level: " + cmd.getOptionValue("level"));
                    System.out.println("  tail: " + Arrays.toString(cmd.getArgs()));
                    break;
                default:
                    System.out.println("expected 'foo' or 'bar' subcommands");
                    System.exit(1);
            }
        } catch (ParseException e) {
            System.out.println(e.getMessage());
            formatter.printHelp(subcommand, subcommand.equals("foo") ? fooOptions : barOptions);
            System.exit(1);
        }
    }
}

To run the program, compile it and use java:

$ javac CommandLineSubcommands.java
$ java CommandLineSubcommands foo -enable -name=joe a1 a2
subcommand 'foo'
  enable: true
  name: joe
  tail: [a1, a2]

Now try the ‘bar’ subcommand:

$ java CommandLineSubcommands bar -level 8 a1
subcommand 'bar'
  level: 8
  tail: [a1]

But ‘bar’ won’t accept ‘foo’s flags:

$ java CommandLineSubcommands bar -enable a1
Unrecognized option: -enable
usage: bar
 -level <arg>   level

This example demonstrates how to implement subcommands in Java using the Apache Commons CLI library. Each subcommand has its own set of flags, and we can parse and handle them separately. This approach allows for creating complex command-line interfaces similar to popular tools like git or docker.

Next, we’ll look at environment variables, another common way to parameterize programs.