Option Groups

Option Groups

The @OptionGroup annotation defines key=value pair options collected into a Map. This is useful for options like -Dkey=value where the same flag can be repeated with different keys.

Properties

PropertyTypeDefaultDescription
nameString""Option name (variable name if empty)
shortNamechar'\u0000'Short name (e.g., -D)
descriptionString""Help description
requiredbooleanfalseIs option required?
defaultValueString[]{}Default values
askIfNotSetbooleanfalsePrompt user if not set
converterClass<? extends Converter>NullConverter.classCustom value converter
completerClass<? extends OptionCompleter>NullOptionCompleter.classCustom completer
validatorClass<? extends OptionValidator>NullValidator.classCustom validator
activatorClass<? extends OptionActivator>NullActivator.classCustom activator
rendererClass<? extends OptionRenderer>NullOptionRenderer.classCustom renderer
parserClass<? extends OptionParser>AeshOptionParser.classCustom parser

Basic Example

@CommandDefinition(name = "compile", description = "Compile the project")
public class CompileCommand implements Command<CommandInvocation> {

    @OptionGroup(shortName = 'D', description = "Define system properties")
    private Map<String, String> properties;

    @Override
    public CommandResult execute(CommandInvocation invocation) {
        if (properties != null) {
            properties.forEach((key, value) ->
                invocation.println(key + " = " + value));
        }
        return CommandResult.SUCCESS;
    }
}

Usage: compile -Denv=prod -Ddebug=true -Dlog.level=INFO

Each -D occurrence adds an entry to the map. The key and value are split on the = character.

Field Type Requirements

The annotated field must implement Map. Both Map and TreeMap (or other Map implementations) are supported:

// String keys and values
@OptionGroup(shortName = 'D')
private Map<String, String> define;

// String keys with typed values (uses built-in converters)
@OptionGroup(shortName = 'D', description = "Define properties")
private TreeMap<String, Integer> limits;

When using typed values, the value portion is converted using the built-in converter for that type, or a custom converter if specified.

Real-World Examples

Java-Style System Properties

@CommandDefinition(name = "run", description = "Run application")
public class RunCommand implements Command<CommandInvocation> {

    @OptionGroup(shortName = 'D', description = "System properties")
    private Map<String, String> systemProperties;

    @Option(description = "Main class")
    private String mainClass;

    @Override
    public CommandResult execute(CommandInvocation invocation) {
        if (systemProperties != null) {
            systemProperties.forEach(System::setProperty);
        }
        // run application...
        return CommandResult.SUCCESS;
    }
}

Usage:

$ run --mainClass com.example.App -Dserver.port=8080 -Dspring.profiles.active=dev

Build Configuration

@CommandDefinition(name = "build", description = "Build project")
public class BuildCommand implements Command<CommandInvocation> {

    @OptionGroup(shortName = 'P', description = "Build parameters")
    private Map<String, String> params;

    @OptionGroup(shortName = 'E', description = "Environment overrides")
    private Map<String, String> env;

    @Override
    public CommandResult execute(CommandInvocation invocation) {
        // Access individual values from the map
        String version = params != null ? params.get("version") : "1.0";
        invocation.println("Building version " + version);
        return CommandResult.SUCCESS;
    }
}

Usage:

$ build -Pversion=2.0 -Ptarget=release -Ehome=/opt/app

Differences from @OptionList

@OptionGroup@OptionList
Field typeMap<K, V>List<T> or Set<T>
Input format-Dkey=value (repeated)--opt val1,val2,val3
Use caseKey-value pairsSimple value collections
RepetitionSame flag repeated with different keysSingle flag with separated values