Parsing Command Line in Java

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.

This entry was posted in Software Development and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. Reinhard
    Posted October 11, 2013 at 3:42 am | Permalink

    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. Posted October 11, 2013 at 9:16 am | Permalink

    Hi Reinhard,

    You are absolutely right. Thanks for pointing it out!

    Steve

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  • NEED HELP?


    My company has created products like vSearch ("Super vCenter"), vijavaNG APIs, EAM APIs, ICE tool. We also help clients with virtualization and cloud computing on customized development, training. Should you, or someone you know, need these products and services, please feel free to contact me: steve __AT__ doublecloud.org.

    Me: Steve Jin, VMware vExpert who authored the VMware VI and vSphere SDK by Prentice Hall, and created the de factor open source vSphere Java API while working at VMware engineering. Companies like Cisco, EMC, NetApp, HP, Dell, VMware, are among the users of the API and other tools I developed for their products, internal IT orchestration, and test automation.