Menu

Injection of Values

Chris DeGreef

Injection of values from the command-line directly into your class attributes is not only the easiest way to use Argument but it also decouples the application code from knowing anything about the command-line.

As covered in the [Retrieval of Values] article you can always directly reference the arguments and obtain their values. And then you can write code to "push" these values into class attributes so that your code can make use of them. But that is not the recommended approach.

All examples that follow will assume that the user of MyProgram entered the command-line like this.

> MyProgram -a value1

Notice the use the shortest version of unrelated keywords in the examples. That way the focus can remain on the ones associated with this topic. -tS is the shortest way of entering --type String. -ka is the shortest way of entering --key a.

The Hard Way

Starting with the retrieval way and then modifying it to be the injection technique.

// in the main method
ICmdLine argument = CmdLine.create("-tS -ka").parse(commandLineArgs);
String myArgValue = (String) argument.arg("-a").getValue();
System.out.println(myArgValue);

Injecting a String into a Variable

With injection of values we don't need to hang on to the Argument instance so we don't assign it to a variable. We have defined a public class attribute called myArgValue that will be the target of the -a argument. This is because we have used the --variable parameter when defining the parser. Argument will look for the variable and push the value of the argument into it during the parse call.

// class attribute
public String myArgValue;
// in the main method
CmdLine.create("-tS -ka --variable myArgValue").parse(this, commandLineArgs);
System.out.println(myArgValue);

Getting the Variable Types Right

It is important to match up the argument --type parameter and the type of the variable. --type String will need a String variable, --type Integer can make use of the primitive int or the class Integer as the variable type. An example of --type Integer. Notice the very shortened version of the --variable parameter (-v).

// class attribute
public int myArgValue;
// in the main method
CmdLine.create("-tI -ka -v myArgValue").parse(this, commandLineArgs);
System.out.println(myArgValue);

Storing --multiple values in an Array

This example shows -a as a multiple value argument. In Java, one way to store that in a variable is to use an array. Here, -a is a String type so we will store the values in a String[]. Argument will create the String[] before adding the values to it. You don't need to initialize the variable in any way.

// class attribute
public String[] myArgValues;
// in the main method
CmdLine.create("-tS -ka --multiple 1 -v myArgValues").parse(this, commandLineArgs);
for (String value : myArgValues)
    System.out.println(value);

Storing --multiple values in a List

This example shows -a as a multiple value argument. In Java, one way to store that in a variable is to use a List. Here, -a is a String type so we will store the values in a List<String>. Argument will create the List<String> as an ArrayList<String> before adding the values to it. You don't need to initialize the variable in any way.

// class attribute
public List&lt;String&gt; myArgValues;
// in the main method
CmdLine.create("-tS -ka --multiple 1 -v myArgValues").parse(this, commandLineArgs);
for (String value : myArgValues)
    System.out.println(value);

Using --class to override what Argument will make

--class is needed if Argument can not determine the type from the variable (--var) itself or you need to provide a different class due to the variable type not being a concrete class, or it uses generics. Argument will by default attempt to create instances for the --type of argument you have defined. In some cases this may produce errors that indicate you need to use --class.

--class is only valid for embedded parsers (--begin arguments). It is mutually exclusive with the --factoryM and --factoryA parameters.

These examples use a second class called MyGroup. It is created for the embedded parser and used when loading the embedded parsers argument.

This is to show that --class is not usually needed. The type that Argument creates for myGroup is inferred from its type definition.

static public class MyGroup {
    public String  testString1;
    public String  testString2;
}

static public class MyProgram {
    // class attribute
    public MyGroup myGroup;
    // in the main method
    CmdLine.create(
        "-tBegin -ka -v myGroup",
            "-tString -k t1 -p --var testString1",
            "-tString -k t2 -p --var testString2",
        "-tEnd -ka"
    ).parse(this, commandLineArgs);
    System.out.println(myGroup.testString1);
    System.out.println(myGroup.testString2);

Usage:
Input:


MyProgram -a ('Little' 'Gray Cloud')

Output:

Little
Gray Cloud

--class is needed for this example. The target variable (myGroup) is defined this time as a superclass (Object). And we want to create the proper instance (MyGroup).

static public class MyGroup {
    public String  testString1;
    public String  testString2;
}

static public class MyProgram {
    // class attribute
    public Object myGroup;
    // in the main method
    CmdLine.create(
        "-tBegin -ka -v myGroup --class " + MyGroup.class.getName(),
            "-tString -k t1 -p --var testString1",
            "-tString -k t2 -p --var testString2",
        "-tEnd -ka"
    ).parse(this, commandLineArgs);
    System.out.println(((MyGroup)myGroup).testString1);
    System.out.println(((MyGroup)myGroup).testString2);

Using a Factory to create values

This is the fun part. And probably the most useful for complex command lines. It enables you to use polymorphism when populating multi-value arguments (--multiple) based on the information from the command-line. Unlike --class, --factoryMethod can be used on --type begin and --type String arguments.

Factories for --type String arguments

In this example we have two subclasses of the AbstractColor class. Argument will call the factory method create to get the proper instance. The (String) value that the user enters is passed to the factory method and the proper instance is returned to Argument.

static abstract  public class AbstractColor {
    static public AbstractColor create(String name) {
        if ("red".equals(name)) return new RedColor();
        if ("blue".equals(name)) return new BlueColor();
        return null;
    }
}

static public class RedColor extends AbstractColor {
}

static public class BlueColor extends AbstractColor {
}

static public class MyProgram {
    // class attribute
    public AbstractColor color;
    // in the main method
    CmdLine.create(
        "-tString -kcolor --var color --factoryMethod AbstractColor.create --list red blue"
    ).parse(this, commandLineArgs);
    System.out.println(color.getClass().getName());

Input:


MyProgram --color red

Output:

RedColor

Factories for --type String arguments with --multiple values

This also is a good technique for --multiple valued arguments.

static abstract  public class AbstractColor {
    static public AbstractColor create(String name) {
        if ("red".equals(name)) return new RedColor();
        if ("blue".equals(name)) return new BlueColor();
        return null;
    }
}

static public class RedColor extends AbstractColor {
}

static public class BlueColor extends AbstractColor {
}

static public class MyProgram {
    // class attribute
    public AbstractColor[] color;
    // in the main method
    CmdLine.create(
        "-tString -kcolor --var color --factoryMethod AbstractColor.create --list red blue -m1"
    ).parse(this, commandLineArgs);
    for (AbstractColor col : color)
        System.out.println(col.getClass().getName());

Input:


MyProgram --color red blue red

Output:

RedColor
BlueColor
RedColor

Factories for --type Begin arguments (requires --factoryArgName)

Since they are so similar we will just go right to a --multiple valued embedded argument. The new to be away of is the --factoryArgName used to help create the instances. The --factoryArgName specifies which of the arguments in the embedded parse will be used when calling the --factoryMethod.

To show the power of --begin we have added a new variable to the AbstractColor class called intensity.

static abstract  public class AbstractColor {
    static public AbstractColor create(String name) {
        if ("red".equals(name)) return new RedColor();
        if ("blue".equals(name)) return new BlueColor();
        return null;
    }
    public int intensity;
}

static public class RedColor extends AbstractColor {
}

static public class BlueColor extends AbstractColor {
}

static public class MyProgram {
    // class attribute
    public AbstractColor[] color;
    // in the main method
    CmdLine.create(
        "tBegin -k color --var color --factoryMethod AbstractColor.create --factoryArgName '--name' -m1",
        "    -tString  -kname   -p   --list red blue",
        "    -tInteger -kintensity -p --var intensity --range 0 255",
        "-tEnd -k color"
    ).parse(this, commandLineArgs);
    for (AbstractColor col : color)
        System.out.println(col.getClass().getName() + " " + col.intensity);

Input:


MyProgram --color (red 85) (blue 190) (red 13)

Output:

RedColor 85
BlueColor 190
RedColor 13


Related

Wiki: Home
Wiki: Retrieval of Values

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.