Home > Software Development > Parsing Command Line in Java

Parsing Command Line in Java

October 10th, 2013 Leave a comment Go to comments

If you develop a command line tool, you would probably need to parse options and arguments. In Java, you can use Apache Commons CLI to handle the parsing. Since I don’t write much command line program, I don’t need these tools. While reading vCO API sample, I found one command line tool called args4j which is written by Kohsuke Kawaguchi who had created the famous Hudson/Jenkins server.

To my curiosity, I just wrote a sample to learn how to use it. Based on my limited experience, I think it can handle all what I want in parsing command line. It’s a good addition to my toolbox for software development. License wise, args4j is under MIT license which is one of the least restrictive open source licenses like BSD which I use for the vijava API.

Lost VMs or Containers? Too Many Consoles? Too Slow GUI? Time to learn how to "Google" and manage your VMware and clouds in a fast and secure HTML5 App.

Here is the sample I wrote based on the original sample from the project home. The original sample requires newer version of the binary I downloaded (2.0.21) because of additional “hidden” field in the Option annotation. Upgrading to latest version of 2.0.25 seems to require Java 7 because it uses java.io.file.Path. Upgrading to Java 7 may take much time, so I just removed the hidden field of the Option annotation and everything worked.

A big change I made from the original sample is to move the arguments into its own class instead of mixing them together in the main class. I think that is most likely the way most people would use the APIs.

package org.doublecloud.cli.demo;
 
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.BooleanOptionHandler;
 
import static org.kohsuke.args4j.ExampleMode.ALL;
 
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
/**
 * @author Steve Jin (http://www.doublecloud.org)
 */
 
class MyArgument
{
  @Option(name = "-r", usage = "reconnect to server automatically")
  public boolean reconnect;
 
  @Option(name = "-o", usage = "output to this file", metaVar = "OUTPUT")
  public File out = new File(".");
 
  @Option(name = "-u")
  public String str = "(default value)";
 
  @Option(name = "-t", usage = "timeout in seconds, must be an integer", metaVar="INT")
  public int num = 30;
 
  @Option(name = "-custom", handler = BooleanOptionHandler.class, usage = "boolean value for checking the custom handler")
  public boolean data;
 
  // receives other command line parameters than options
  @Argument
  public List<String> arguments = new ArrayList<String>();
}
 
public class CommandLineDemo
{
  public static void main(String[] args) throws IOException
  {
    MyArgument va = new MyArgument();
    CmdLineParser parser = new CmdLineParser(va);
 
    // to show in wider console, increase the default 80
    parser.setUsageWidth(120);
 
    try
    {
      parser.parseArgument(args);
    }
    catch (CmdLineException e)
    {
      System.err.println("Error: " + e.getMessage());
      System.err.println("java CommandLineDemo [options...] arguments...");
      parser.printUsage(System.err);
      System.err.println();
      System.err.println("  Example: java CommandLineDemo" + parser.printExample(ALL));
      return;
    }
 
    // this will redirect the output to the specified output
    System.out.println(va.out);
 
    if (va.reconnect)
      System.out.println("-r flag is set");
 
    if (va.data)
      System.out.println("-custom flag is set");
 
    System.out.println("-str was " + va.str);
 
    if (va.num >= 0)
      System.out.println("-n was " + va.num);
 
    // access arguments
    System.out.println("other arguments are:");
    for (String s : va.arguments)
      System.out.println(s);
  }
}

To run the code, you can type in the following

java CommandLineDemo -r -t 30 -o OUTPUT -custom "http://doublecloud.org" -tt

It’s OK if you use a different combination of options, arguments – it just gets into error handling logic, something should be tested anyway.

After trying the args4j, I also found a good article which compares args4j and jCommander with real use cases. Highly recommend it.

  1. Reinhard
    October 11th, 2013 at 03:42 | #1

    Hi Steve,

    thanks for your tons of valuable information. In this one I just found a small typo. In the 3rd section you write:

    “Upgrading to latest version of 2.0.25 seems to require Java 7 because it uses java.io.file.Path.”

    This should read “java.nio.file.Path”, right? 😉

    Best Regards,
    Reinhard

  2. October 11th, 2013 at 09:16 | #2

    Hi Reinhard,

    You are absolutely right. Thanks for pointing it out!

    Steve

  1. No trackbacks yet.