Picocli's value proposition is that it eliminates boilerplate code from the
application.
This allows users to build powerful command line applications with a
minimum of code.
For example:
@Command(name = "demo", mixinStandardHelpOptions = true,
description = "Demonstrate parsing & type conversion")
public class SimpleDemo implements Runnable {
@Option(names = "-x", description = "Print count. ${DEFAULT-VALUE}
by default.")
private int x;
@Option(names = "-d") private double d;
@Option(names = { "-u", "--timeUnit"}) private TimeUnit unit;
@Override
public void run() {
for (int i = 0; i < x; i++) {
System.out.printf("You selected %f, %s.%n", d, unit);
}
}
public static void main(String[] args) {
CommandLine.run(new SimpleDemo(), args);
}
}
If you call this program with command line arguments
-x 3 -d 1.23 -u MINUTES
it will print the following:
You selected 1.230000, MINUTES.
You selected 1.230000, MINUTES.
You selected 1.230000, MINUTES.
With a minimum of code this program defines a set of options, parses the
command line parameters, converts the string values to strongly typed
values, and makes the command line options values available in the
annotated fields. Error handling and help requests are handled in the
CommandLine.run method. There is no need for any Map-like processing any
more, this is all pushed into the library.
(Note that in addition to the annotations API there is also a programmatic
API - similar to the Commons CLI API - which is useful for programs that
dynamically define options. An example of such a program is Groovy's
CliBuilder, which migrated to picocli recently.)
The mixinStandardHelpOptions annotation adds --help and --version options,
so if you call this program with command line argument
--help
it will print the following:
Usage: demo [-hV] [-d=<d>] [-u=<unit>] [-x=<x>]
Demonstrate parsing & type conversion
-d=<d>
-h, --help Show this help message and exit.
-u, --timeUnit=<unit>
-V, --version Print version information and exit.
-x=<x> Print count. 0 by default.
The @Command annotation allows you to plug in a default provider:
@Command(name = "demo", mixinStandardHelpOptions = true,
description = "Demonstrate parsing & type conversion",
defaultValueProvider = PropertyDefaultProvider.class)
public class SimpleDemo implements Runnable { // ...
An example default value provider that reads a properties file could look
like the below.
This does not take care of the encoding requirement you mentioned, but
should be straightforward to extend to meet your requirements:
class PropertyDefaultProvider implements IDefaultValueProvider {
private Properties properties;
@Override
public String defaultValue(ArgSpec argSpec) throws Exception {
if (properties == null) {
properties = new Properties();
File file = new File(System.getProperty("user.dir"),
"defaults.properties");
try (Reader reader = new FileReader(file)) {
properties.load(reader);
}
}
return argSpec.isOption()
? properties.getProperty(((OptionSpec) argSpec).longestName())
: properties.getProperty(argSpec.paramLabel());
}
}
I hope this clarifies a bit.
On Mon, Feb 11, 2019 at 7:30 AM Albretch Mueller <[email protected]> wrote:
> On 2/10/19, P. Ottlinger <[email protected]> wrote:
> > Another way to help out (from the ASF universe) would be:
> > https://tamaya.apache.org/
>
> I did take a look at tamaya:
>
> https://tamaya.apache.org/features.html
> ~
> To me having to go:
>
> Configuration config = Configuration.builder()
> .withDefaultPropertySources()
> .addPropertySources(new MyCustomPropertySource())
> .withDefaultConverters()
> .build();
>
> is a nonsensical and wasteful overkill. What is this useful for,
> exactly? Are there actual use cases that kind of coding relates to?
> ~
> On 2/9/19, Remko Popma <[email protected]> wrote:
> > Picocli has a pluggable default provider
> > (https://picocli.info/#_default_provider), so it should be fairly
> > straightforward to implement what you describe.
>
> I also spent some time taking a look at picocli and it seems to me
> like some other kind of an overkill:
>
> 13.1. Registering Subcommands Programmatically
> Subcommands can be registered with the CommandLine.addSubcommand
> method. You pass in the name of the command and the annotated object
> to populate with the subcommand options. The specified name is used by
> the parser to recognize subcommands in the command line arguments.
>
> CommandLine commandLine = new CommandLine(new Git())
> .addSubcommand("status", new GitStatus())
> .addSubcommand("commit", new GitCommit())
> .addSubcommand("add", new GitAdd())
> .addSubcommand("branch", new GitBranch())
> .addSubcommand("checkout", new GitCheckout())
> .addSubcommand("clone", new GitClone())
> .addSubcommand("diff", new GitDiff())
> .addSubcommand("merge", new GitMerge())
> .addSubcommand("push", new GitPush())
> .addSubcommand("rebase", new GitRebase())
> .addSubcommand("tag", new GitTag());
>
> It is strongly recommended that subcommands have a @Command
> annotation with name and description attributes.
> ~
> > It also has other nice features that you might be interested in, like
> usage
> > help with ANSI colors, ... and much
> > more.
>
> Does it come with ANSI colors? Will it also dance the macarena for me?
>
> I can't even get what is the point of going through such hoops, when,
> to me, all you need is for a HashMap<String><String[]> to be returned
> to you. Users shouldn’t be forced to enter command line arguments in a
> strict way and order and they should be able to chose the character
> encoding of the data they will be feeding into a program (you can’t
> expect for every text on a corpus to be encoded as ASCII or UTF-8).To
> me this is all there should be to such an utility.
>
> Command line arguments are interpreted as strings in the local
> character encoding anyway, right? You would take it from there,
> interpreting those sequences of characters with whichever semantics
> your code needs to define:
>
> HashMap<String, String[]> HMSSAr ...
>
> String[] aIVal00 = HMSSAr.get("--int-val00");
> int iVal00 = (new Integer(aVal00[0])).intValue();
>
> String[] aLVal02 = HMSSAr.get("--long-val02");
> long lVal02 = (new Integer(aLVal02[0])).longValue();
>
> String[] aSAr = HMSSAr.get("--strings-ar00");
> KCommandObjects KCObjs = new KcommandObjects[aSAr.length];
> HashMap<String, Integer> HMSI = new HashMap<String, Integer>();
> for(int k = 0; (k < aSAr.length) ;++k){
> HMSI.put(aSAr[k], k);
> KCObjs[k] = Class.forname(aSAr[k]).newInstance();
> }// k [0, aSAr.length)
>
> . . .
>
> I am half way into finishing such a thing, which I thought someone
> must had done already. Then I will try to integrate with commons-cli
> or put it out there.
>
> I would like to still understand why is it that there exist so many
> libraries which complicate such matters and why is it that java itself
> doesn't offer a basic option like the one I have described.
>
> lbrtchx
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>
>