Java: Automatic configuration dialog for cli-parser annotated fields

In case you haven’t heard about cli-parser – it’s a command-line interface library for Java and a very handy one at that. Its main class parses command line parameters into fields of a given class specified just by annotations. It can also produce a neat usage description characteristic for CL programmes. A definition of CLI for cli-parser looks like this (modified example from cli-parser website):

public static class TestCommand {
        @Argument(value = "input", description = "This is the input file", required = true)
        private String inputFilename;

        @Argument(value = "output", alias = "o", description = "This is the output file", required = true)
        private String outputFile;

        @Argument(description = "This flag can optionally be set")
        private boolean someflag;

        @Argument(description = "Minimum", alias = "m")
        private Integer minimum;

        @Argument(description = "List of values", delimiter = ":")
        private Integer[] values;

        @Argument(description = "List of strings", delimiter = ";")
        private String[] strings;

        @Argument(description = "not required")
        private boolean notRequired;

    }

I’ve created an automatic dialog generator for specifying those arguments and configuration saver/loader for storing them between sessions. Its usage is extremely simple and illustrated below:

public class Demo {
	public static void main(String[] args) throws Exception {
		final TestCommand tc = new TestCommand();
		AccessController.doPrivileged(new PrivilegedExceptionAction() {
			public Object run() throws Exception {
				ArgsConfig ac = new ArgsConfig(tc);
				ac.load();
				ac.addGroup("default", "Demo");
				ac.showDialog(null, "eu.algoholic.thin_git.ArgsConfig Demo");
				if (ac.isConfirmed())
					ac.save();
				return null;
			}
		});
	}
}

Usage of AccessController.doPrivileged() is necessary when ArgsConfig resides in different package than your CLI class, which normally IS the case.

You might be puzzled about the ArgsConfig.addGroup() method. It has to be present because I’ve introduced the @ArgExtra annotation for additionally grouping the arguments into related sets. ArgsConfig.addGroup() specifies that certain group (in this case “default”) should be included in the generated dialog, and also specifies its display name, in this case – “Demo”.

Using @ArgExtra the CLI definition can be more sophisticated, including hints like usage of specific file choosers:

class TestCommand {
        @Argument(value = "input", description = "This is the input file", required = true)
		@ArgExtra(group="files", hints = "open-file-chooser")
        public String inputFilename;

        @Argument(value = "output", alias = "o", description = "This is the output file", required = true)
		@ArgExtra(group="files", hints = "save-file-chooser")
        public String outputFile;

        @Argument(value="someflag", description = "This flag can optionally be set")
		@ArgExtra(group="misc")
        public boolean someflag;

        @Argument(value="minimum", description = "Minimum", alias = "m")
		@ArgExtra(group="misc")
        public Integer minimum;

		@Argument(value="val_list", description = "List of values", delimiter = ":")
		@ArgExtra(group="lists")
        public Integer[] values;

        @Argument(value="str_list", description = "List of strings", delimiter = ";")
		@ArgExtra(group="lists")
        public String[] strings;

        @Argument(value="not_req", description = "not required")
		@ArgExtra(group="misc")
        public boolean notRequired;
}

public class Demo {
	public static void main(String[] args) throws Exception {
		final TestCommand tc = new TestCommand();
		AccessController.doPrivileged(new PrivilegedExceptionAction() {
			public Object run() throws Exception {
				ArgsConfig ac = new ArgsConfig(tc);
				ac.load();
				ac.addGroup("files", "Files");
				ac.addGroup("lists", "Lists");
				ac.addGroup("misc", "Miscellaneous");
				ac.showDialog(null, "eu.algoholic.thin_git.ArgsConfig Demo");
				if (ac.isConfirmed())
					ac.save();
				return null;
			}
		});
	}
}

resulting in the following dialog (where values are stored between sessions):

As you can see, it’s a pretty neat result for so little code ; )

Below, I have attached the ArgsConfig and Demo source code (BSD licensed) and binaries. Enjoy!

DOWNLOAD: argsconfig_demo.zip (extract before running)

Leave a Reply

Your email address will not be published. Required fields are marked *