Annotations in Arg API are the quickest way build sophisticated applications which take command line arguments.
The two most common annotatations used @Property and @Section are discussed first.
The @Option annotation can be used on a class field or a class method. Both static and class instance variations are supported. For class instance type, a dynamic group is created and object of class type is instantiated using possibly a @GroupFactory method and appropriate options are set when options change.
A static class field:
@Option
static boolean option`;
A dynamic or class instance field:
@Option
boolean option;
Dynamic fields require that the class they are declared in is annotated with @Group annotation. This creates an option group which can be instantiated via command line, configuration file or programmatically include the object instance of the class.
The @Option.value attribute you can assign a new name to the option. Otherwise the name is calculated based on the class field name, when accessible via the java reflection API.
This assigns a new name abc to option which would otherwise be named def:
@Option("abc")
static boolean def;
Allows additional names or aliases to be assigned to the same option. The option will be selected via any of the provided aliases and the main name it was assigned. Sometimes it is neccessary to assign legacy names or different level of verbosity for an option.
@Option(aliases = {"def", "ghi", "jkl"})
static boolean abc;
The option can be now selected via the name abc or any of the aliases def, ghi, jkl.
Catchall allows an option to be assigned 1 or more unmatched values from the command line. As a matter of fact the
option does not even have to be specified on the command line explicitely. Any unmatched arguments will be made available to the catchall option as values.
Typically collections are used as catchall which collect all remaining arguments. However a single value option can also be used and only the first unmatched argument will be assigned to it.
@Option(catchall = true)
static List<String> filenames;
where
shell> java myprogram file1 file2 file3 file4
# or
shell> java myprogram --filenames file1 file2 file3 file4
# or
shell> java myprogram --filenames file1 --filenames file2 file3 file4
would assign all 4 files to collection filenames.
Note this feature has not been released yet
Class method options in Args API are easy to use but very flexible way of creating sophisticated options and their behavior.
Lets compare a class method option with a regular class field one
public class MyClass {
@Option
static int counter;
creates a simple option which when accessed looks like this
OptionInfo<Integer> counter = root.getStaticOption("counter");
assert counter.getValue() == MyClass.counter;
Simple enough. With the use of a method option, we can add sophisticated behavior if needed
public class MyClass {
@Option
static int counter(int value) {
return value * 2;
}
which also produces the same option
OptionInfo<Integer> counter = root.getStaticOption("counter");
Except now we do not have a class field to reference in an assertion, but we can do this if the command line was --counter 10:
assert counter.getValue() == MyClass.counter(10);
which should return the same option value as from the command line.
Method options input parameters and the return value need not be of the same type either. The parameter type in method signature determins which command line values are expected. The return value of the method determines the option value type, the <T> in OptionInfo<T>. For example
@Option
static Collection<String> colors(int count, String name) {
Collection<String> myColors = new ArrayList<>();
for (int i = 0; i < count; i ++) {
myColors.add(name + "-" + count);
}
return myColors();
}
The option signature now looks like this
OptionInfo<Collection<String>>
The command line for 'colors' option would look like this
--colors 10 red
Where the invocation of the method by the Args library would look like this, with the corresponding parameters
Collection<String> myColors = MyClass.colors(10, "red")
Section groups together one or more options into a group. When present a GroupInfo<?> object is created and added to the RootGroupInfo. All of the classes' fields are added to this new group.
If @Group annotation is not provided on a class, all of the classes fields are added to the RootGroupInfo instead a new group. So although @Group annotation is option if a class contains only static fields, it is required for any class that contains dynamic or class instance fields which are marked as options with @Option.
The easiest way to explain the concept of static and dynamic groups (or sections) is using a INI config file example.
If we have a class
@Group
public class Adapter {
@Option
static boolean disableAllAdapters;
@Option
int mtu;
}
and we also have the following INI configuration file
[adapter]
disableAllAdapters = false
[adapter:eth0]
mtu = 1500
[adapter:eth1]
mtu = 512
See [Working with INI config files].
Alternatively we can provide the same using command line
shell> java myprog --disable-all-adapters false --adapter eth0 -mtu 1500 --adapter eth1 --mtu 512
See [Working with command line arguments].
To read the INI config file
@Group
public class Adapter {
@Option
static boolean disableAllAdapters;
@Option
int mtu;
public static void main(String[] args) {
RootGroupInfo root = Args.readIniConfig("config.ini", Adapter.class);
System.out.printf("disable all adapters? %s%n", Adapter.disableAllAdapters);
for (Adapter adapter: roor.getAll(Adapter.class)) {
final String name = root.getGroup(adapter).getName();
System.out.printf("%s: mtu=%d%n", name, adapter.mtu);
}
}
option
Wiki: Example1 - basic usage
Wiki: Working with INI config files