Menu

Annotations explained

Sly Technologies

Annotations in Arg API are the quickest way build sophisticated applications which take command line arguments.


Annotations in order of importance

The two most common annotatations used @Property and @Section are discussed first.


@Option - marks a class field or a method as an option and a property

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.

@Option.value - changing the option name

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;

@Option.aliases - assigning additional names

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.

@Option.catchall - option collects all unmatched arguments

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.

Class method options

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")

@Group - marks a class as a static or dynamic group

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.

Dynamic and static groups explained

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);
      }
}

@Help - adds a help description to any option or group


@Rule - applies rule to an option, setting a policy of how an option or a group can be used


@ParameterType - allows a new parameter type be used or changed defaults on builtin types

option


@Script - allows an arbitrary script be executed when the option/property value changes


@GroupFactory - designates a builder factory method to initialize class instances for dynamic groups


@Parameter - defines the parameter properties that an option takes as argument


Related

Wiki: Example1 - basic usage
Wiki: Working with INI config files