args4j with secret parameters

Args4j (http://args4j.kohsuke.org/) is a decent and compact library that makes it easy to parse command line parameters.

If you ever come across a case where you want to pass your app arguments like:

./myapp -dbUser foo -dbPassword s3cr3t

Then you’d be exposing the password to any other users on the system using ps (process show).

Instead, rather call the application using a wrapper script, and save the password in an environment variable as such:

#!/bin/bash
export DBPASSWORD=s3cr3t
./myapp -dbUser foo

In order to achieve this, a decorator is needed so that we can treat environment variables as valid alternatives to options passed via the CLI:

public class DecoratedCmdLineParser extends CmdLineParser {

public DecoratedCmdLineParser(Object bean) {
super(bean);
}

@Override
public void parseArgument(String... args)
throws CmdLineException {

final List<String> allArgs = new ArrayList<>();

// Allow environment variables to override
getOptions().forEach(optionHandler -> {
final OptionDef option = optionHandler.option;
final String envVar = System.getenv(option.metaVar());
if (envVar != null) {
allArgs.add(option.toString());
allArgs.add(envVar);
}
});

// Add regular command line args
allArgs.addAll(Arrays.asList(args));

super.parseArgument(
allArgs.toArray(new String[allArgs.size()]));
}
}

Now you can go ahead using args4j in the conventional manner, but remember to use the decorated implementation of CmdLineParser:

private void runMain(String[] args) throws IOException {

final CmdLineParser parser = new DecoratedCmdLineParser(this);

try {
// Parse arguments
parser.parseArgument(args);
.
.
.

No doubts the decorator can be improved, so feedback/improvements is welcome.