Giter VIP home page Giter VIP logo

jcommander's Introduction

JCommander

This is an annotation based parameter parsing framework for Java 8 (JCommander 1.x) and 11 (JCommander 2.x).

Here is a quick example:

public class JCommanderTest {
    @Parameter
    public List<String> parameters = Lists.newArrayList();
 
    @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
    public Integer verbose = 1;
 
    @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
    public String groups;
 
    @Parameter(names = "-debug", description = "Debug mode")
    public boolean debug = false;

    @DynamicParameter(names = "-D", description = "Dynamic parameters go here")
    public Map<String, String> dynamicParams = new HashMap<String, String>();

}

and how you use it:

JCommanderTest jct = new JCommanderTest();
String[] argv = { "-log", "2", "-groups", "unit1,unit2,unit3",
                    "-debug", "-Doption=value", "a", "b", "c" };
JCommander.newBuilder()
  .addObject(jct)
  .build()
  .parse(argv);

Assert.assertEquals(2, jct.verbose.intValue());
Assert.assertEquals("unit1,unit2,unit3", jct.groups);
Assert.assertEquals(true, jct.debug);
Assert.assertEquals("value", jct.dynamicParams.get("option"));
Assert.assertEquals(Arrays.asList("a", "b", "c"), jct.parameters);

The full doc is available at https://jcommander.org.

Building JCommander

./gradlew assemble

jcommander's People

Contributors

amuraru avatar andylaw avatar ansel1 avatar cbeust avatar cedricrefresh avatar chrisruffalo avatar dozmus avatar garydgregory avatar glhez avatar helllth avatar jeremysolarz avatar jodastephen avatar kovalskyi avatar lindenb avatar madrob avatar mkarg avatar samvv avatar sclasen avatar selliera avatar simon-clarkstone avatar simon04 avatar tgallagher2017 avatar thnaeff avatar tklerx avatar triceo avatar tzellman avatar vanuan avatar wardev avatar xfournet avatar yevmel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jcommander's Issues

Multiple params gives multiple usage lines

I'm getting usage info printed an odd number of times, ie: if I have 3 params, I see the usage line 3 times.

CommandLineParams clp = new CommandLineParams();
JCommander jcom = new JCommander(clp, args);
jcom.usage();

prints my usage twice in a row

Usage:
    --config -c     Points to the config file (so you can run multiple servers)
    --help -h -?    Help
    --version -v    Display version info
    --config -c     Points to the config file (so you can run multiple servers)
    --help -h -?    Help
    --version -v    Display version info
    --help -h -?    Help

and this is my class

public class CommandLineParams
{
@Parameter(names = { "--version", "-v" }, description = "Display version info")
    public Boolean blnVersion = false;

    @Parameter(names = { "--config", "-c" }, description = "Points to the config file (so you can run multiple servers)")
    public String strConfigFile = "";

    @Parameter(names = { "--help", "-h", "-?" }, description = "Help")
    public Boolean blnHelp = false;
}

Scala can't create an instance of JCommander

Scala 2.8.0 seems to get confused when picking between the (Object, String...) and (Object) constructors. Wondering if the String... bit can be removed from the signature, or at least provide simpler static method to crate the JCommander object.

Actual compiler error message is:
error: ambiguous reference to overloaded definition,
both constructor JCommander in class JCommander of type (Any,java.lang.String*)com.beust.jcommander.JCommander
and constructor JCommander in class JCommander of type (Any)com.beust.jcommander.JCommander
match argument types (Array[ScalaObject])
val commander = new JCommander(Array(new Main, new HelpSettings))

Usage text

Would it be possible to use parameter arity to display something like this when usage() method is called?

Usage:
-flag Description1
-first Description2
-others ... Description3

Problem, argument label would have to be provided in the annotation and i18n.

Usage takes command description from getMainParameterDescription - why?

Why usage() takes desciption of a command from getMainParameterDescription? If the command doesn't have any main parameters then it shows null and do I really have to add synthetic main parameter to have a description in usage()?

I find if would be reasonable to get Description from class-level annotation rather than from main parameter.

Aliases for commands

It would be nice to have the oportunity to define aliases for commands.

CommandMain cm = new CommandMain();
JCommander jc = new JCommander(cm);
CommandAdd add = new CommandAdd();
jc.addCommand("add", add);
CommandCommit commit = new CommandCommit();
jc.addCommand("commit", commit);
jc.aliasCommand("commit", "ci");

Help Option for command which has required options

I would like to define a help option for commands. I created a main command class which has an help option so i can do the following:

name --help

So now i define some commands like the following:

name XYZ [options]

The options for the command XYZ now contain required flag for example --file (what ever).
The result from that it is not possible to have a help option for the XYZ command (ok i can define one, but i can't parse it, cause it would produce a ParameterException: The following options are required: --file ... first).
An example of my problem can be found in the project cli-test
The question is might it be a good idea to create a special annotation @parameter(help = true...) to make it possible to parse the --help before an exception will be thrown. May be there are other better solutions as well?

support injection of parameter list into non-List types (e.g. Arrays or scala.collection.List etc)

It would be nice to support alternative collection types for the list of strings other than java.util.List such as Array or other containers (such as scala.collection.immutable.List from Scala).

when hacking in Scala code its neater to avoid the java.util.List types.

I figure we could have an IStringListConverter like the IStringConverter which can deal with converting a List to a Java Array or Scala List etc

No check for parameter with missing argument

It seems that JCommander doesn't check for missing parameter values. If you run the following program with the arguments "-n" instead of "-n something", then an ArrayIndexOutOfBoundsException is thrown.

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;

public class Test {
    @Parameter(names = "-n")
    private String name;

    public static void main(String[] args) {
        Test test = new Test();
        new JCommander(test, args);
        System.out.println(test.name);
    }
} 

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at com.beust.jcommander.JCommander.parseValues(JCommander.java:466)
at com.beust.jcommander.JCommander.parse(JCommander.java:174)
at com.beust.jcommander.JCommander.<init>(JCommander.java:141)
at Test.main(Test.java:10)

IllegalAccessException in convertValues, but carries on anyway

I've just had a user point out this to me in my project:

http://code.google.com/p/jslint4java/issues/detail?id=44

The fix is simple—my converter needs to be public access, not default access.

What concerns me is that JCommander printed the exception to stdout and then carried on anyway. Looking in JCommander.convertValue(), I think that it should either be throwing a wrapped RuntimeException, or printing a more sensible error message in place of a stack trace.

What do you think?

Using commands feels a bit awkward at the moment

Using commands isn't as easy as the rest of JCommander.

I have code that looks like this:

    CommandLineArgs cl=new CommandLineArgs();
    JCommander commander = new JCommander(cl);
    Cat cat = new Cat();
    commander.addCommand(Cat.NAME, cat);
    Tail tail = new Tail();
    commander.addCommand(Tail.NAME, tail);
    Index index = new Index();
    commander.addCommand(Index.NAME, index);

The thing that's bugging me is that I had to define a public static final NAME field in each of my command instead of annotating the class, simply calling

    addCommand(command)

The same is the case for using the command:

    String command = commander.getParsedCommand();
    if(Tail.NAME.equals(command)) {
        [...]
    }

So there are two places where I still need to juggle with plain strings.
Instead, I'd like to have something like

    Object commandObject = commander.getParsedCommandObject();

This would be really useful if all registered command objects would implement the same interface, e.g. Runnable. In that case, I could simply cast the returned commandObject and call run() (after checking against null, obviously).

This functionality could even be wrapped into the getParsedCommandObject() method like this:

    Runnable commandObject = commander.getParsedCommandObject<Runnable.class>();

Java 6 required?

I just realized that JCommander obviously requires Java 6 since it seems to use java.io.Console. I learned it the hard way. ;)

It would be nice if the usage of Console could be optional. I'm not sure if this can be achieved, though. I've seen that it's only used for reading a password. How about implementing an fallback that can be used on 1.5 Java?

Unfortunately, I need to stay 1.5 compatible for a little bit longer :(

Default value display in usage()

I have a command which has an option --torev

@Parameter(names = {"--torev"}, description = "The revision to which the scanning process will run.", converter = RevisionConverter.class)
private int toRev;

Based on the RevisionConverter class i can give on the command line:

command --torev HEAD

But if i printout the usage:

--torev The revision to which the scanning process will run. (default: -1)

Does exist a god way to show the HEAD for the default instead of the -1?

Default values displayed in usage change based on arguments parsed

For example, the following test case fails:

Commander jc = new JCommander(new Args1(), new String[]{"-log", "1"});
StringBuilder sb = new StringBuilder();
jc.usage(sb);
String expected = sb.toString();
jc = new JCommander(new Args1(), new String[]{"-debug", "-log", "2", "-long", "5"});
sb = new StringBuilder();
jc.usage(sb);
String actual = sb.toString();
Assert.assertEquals(actual, expected);

You can merge it from: http://github.com/jstrachan/jcommander/commit/bc45c63aa41f108cbe8bdd7c04a1d6c979edd700

Missing newline in usage output

The current output of the usage() method looks like this:

Usage: <main class> [options]
  Options:    --foo         foo argument
    --download     download the file to <dir>

JCommander.java:669 needs an extra newline to place the first argument on the next line.

Type aware main parameter

It would be nice to have main parameter's list type aware (List), rather than List and be able to specify converter for it.

mutually exclusive options?

There is a mechanism to define mutually exclusive options in a command (similar to groups in Apache Commons-cli)? For example: to select how to connect to oracle database.
--thin 'localhost:1521:orcl'
--oci orcl (in this case, use entry in tnsnames.ora)
Then, define that one, and only one, both is required (--thin or --oci)

git-style help

Is there any convenient way to implement something like the help command as used in git?

git help pull

[showing some help]

Currently I've got about 20 commands for my little app. It would be great to have a help beside the usage. The usage is often to small and can't handle an larger amount of remarks.

helper facade for sub commands?

I found there was a bit of head scratching & glue code work to figure out how to make a 'git' like set of commands needing the following...

  • making a Map name -> command
  • add the contents of the map to the JCommander
  • creating a new Help command so that you could type "help" to list all the commands or "help foo" to show help on a sub command (right now the help command needs a reference to JCommander)
  • doing the try/catch around the parse/run, printing out the usage on failures
  • when parsing works, looking up the parsed command in the Map then executing it

I wonder if its worth a little helper class for wrapping up this code so others can reuse it - as none of it really is application specific.

e.g. a facade object which can be configured with the Map<String,Object> commands, adds a Help command by default if there's none already provided that does the common thing and has a few strategy methods that folks could override if required (say to print something before/after an error) that does the try/catch stuff and looks up the command to execute and then invokes the command - by default testing if its a Runnable and calling run() otherwise failing?

It would be nice to be able to do code something like...

Map<String,Runnable> myCommands = new ....
JCommanderRunner runner = new JCommanderRunner(myMainThingy);
runner.setCommands(myCommands);
runner.run(args);

And if a command is a Runnable it'd just do the right thing without any code required. If you're commands are not runnable then you could derive from JCommanderRunner and override the execute(Object command) method to do something application specific (but Runnable seems a reasonable default for now).

the order of commands should be defined in some way.

It should be possible to define the order of commands. Currently
the order is randomly. It doesn't depend on the order of added commands
neither it's alphabetical.
Sometimes it would be helpful to group some commands because they belong to eachother.

Support Multiple value-holder objects rather than just one global one.

Allow JCommander (or a multiple-value-holder version) to accept many objects which declare @parameter fields, throwing on duplicate @parameter declarations. This lets you be more supple about where you put your @parameters.

I've created a patch which has a copied-and-modified version of JCommander.java which supports this for reference. It's not refactored with respect to JCommander.

http://github.com/cgruber/jcommander/commit/e18cf51938050933773f7130ca745afae2380115

usage(cmdName) shows wrong usage.

When using the cj.usage(cmdName) I receive the wrong output:

when invoking 'ToolHelper client-move' I would expect another usage since there
is the correct client-move-command provided in the usage(xx).
Until 1.5 it was working correctly.
Move client
Usage: ToolHelper [options] [command] [command options]
Options: --cluster, -c Aktivate Cluster-Mode (default: false)
--hostname Host-Name
--password, -p Password
--port Port
--username, -u Username
Commands:
client-move Move Client
client-loeschen Delete Client
client-kopieren Copy Client

By the way, in the line with Options: I would expect a linebreak... ;)

Allow custom setup method in options object

I would find it useful if JCommander could trigger a custom initializer in the options object. Right now I still have some code in my main class that deals with option initialization. While all actions are nicely configured by calling JCommander, the non-option arguments still need to be processed separately. I would rather move the necessary logic right into my options class to completely separate the option processing.

I would propose a new annotation to mark a method as an initializer that is called after all the other parsing and checking has been completed. What do you think?

public class Options {
  /** Holds all non-option arguments. */
  @Parameter(description = "filespec...")
  public List filespecs = new ArrayList();

  ...

  @Analyze
  public void analyze() throws IOException {
    try {
      // perform additional sanity checking, custom option processing
      if (filesspecs.isEmpty())
        ...
    } catch (Exception ex) {
      throw new ParameterException("Reason", ex);
    }
  }
}

description of a sub-command should be different to the description of the arguments to a command

when using sub commands with JCommander and doing

jc.usage

it lists all the sub commands, using the description of the command line arguments such as

Usage: myProgram [options] [command] [command options]
  Options:  Commands:
    foo   descriptionOfArguments

Then if you do

jc.usage("foo")

It shows something like

Usage: foo [options] descriptionOfArguments
  Options:    --bar     does something
    --another  something else

Ideally we'd be able to describe what a command does somewhere (e.g. a description annotation on the command object itself?) along with describe its parameter.

For example imagine doing something like git...

$ git help
Usage: git [options] [command] [command options]
  Options:  Commands:
    commit   Record changes to the repository

$ git help commit

git commit - Record changes to the repository

Usage: commit [options] <file>... the files to commit
  Options:    --bar     does something
    --another  something else

So changes required are

  • have somewhere we can describe a command (e.g. @description annotation on the command object?)
  • when calling jc.usage() we use that description
  • when we call usage(command) we need to output the command description, then in the usage use the current parameter description

If we're going to add a new annotation which is only really used for sub commands, maybe @command is better?

So the Commit class could look something like

@Command(name="commit", description="Record changes to the repository")
public class Commit {
  @Parameter(description="<file>... the files to commit")
  public List<String> files;
  ...

Then sub commands could just be an array of objects - since you can find the name and description of the command from the same annotation

LICENSE information missing

Not to be stickler, but most projects include a license.txt file in the project and also note the license in the copyright headers in the source files.

Allow fuzzy arity for boolean parameters

There is one use case JCommander does not yet seem to support, which I require. One currently can either use arity = 0 to use the shorthand form of e.g. --test to set a boolean parameter. Or set arity >= 1 to support switching on|off using the expanded notation e.g. --test false. But I need to be able to allow both notations concurrently.

I've already implemented this feature in a simple and straightforward way that should not break the current contract. If you are interested in adding this feature, please let me know and I will send you the sources. Thanks.

BTW, very nice job with JCommander. Well done!

jline shell for JCommander?

I really like the sub-command thing so you can build something like "git commands args".

It would be cute if we could create a "Shell" command so you could do the equivalent of "git shell" then be in a shell where you can execute sub-commands as top level commands with up/down/history and tab completion using something like...

http://jline.sourceforge.net/

either that or a plugin for bash completion for jcommander commands

Display error for JCommander#usage

When using JCommander#usage with 2 commands and 1 hidden option, #usage is rendering incorrectly.

Usage: <main class> [options] [command] [command options]

  Options:  Commands:
    csv2xmi   Blah
    score

Instead of what I would expect.

Usage: <main class> [options] [command] [command options]

  Options:  
  Commands:
    csv2xmi   Blah
    score  

Overloading

Ok, I finally found my use case for parameter overloading.

Using the new command stuff makes this relatively clear :)

Imagine that you have multiple commands with the same parameter's name ...
For example, using the 'git' example, you may find that multiple commands will requires a '-f' parameter (for force).

Currently, all parameters have to have unique names.

mutually exclusive options?

There is a mechanism to define mutually exclusive options in a command (similar to groups in Apache Commons-cli)? For example: to select how to connect to oracle database.

--thin 'localhost:1521:orcl'

--oci orcl (in this case, use entry in tnsnames.ora)

Then, define that one, and only one, of both is required (--thin or --oci)

(sorry, i closed by error, and no form to reopen)

Better formatted usage help

While the automated usage help is a very nice feature, there are several problems with it:

  • parameters are separated into long and short options. I like a strict lexicographic sorting much better, plus it seems to be prevalent with most command-line tools
  • the description texts are not wrapped and therefore easily break formatting when using longer descriptions

I would propose that the current behavior is either changed or made configurable. I already adjusted my copy accordingly. If you would like to get hold of the changes, please don't hesitate to contact me. Thank you.

better support for positional arguments

right now options which are based on their position rather than named; (i.e. @parameter without a name) the current option is just to support a single @parameter injection point which takes a List

for commands where you expect positional arguments this loses lots of the benefit of the injection & type coercion & validation using the @parameter annotation along with the nicely generated usage documentation.

It would be nice if we could supply an indexed parameter as opposed to a the named/optional parameter.

e.g.

class Copy {
  @IndexParameter(0, name = "from", "the source file(s) used to copy")
  File from;

  @IndexParameter(1, name = "to", "the destination file")
  File to;
}

So rather than having to manually parse a List and figure out whats what, we can use the simpler annotation approach.

Also usage would be able to do something like...

Usage: copy [options] from to
    from   the source file(s) used to copy
    to       the destination file
  Options:    
    --bar        does something
    --another  something else

This also opens up the requirement for one of the parameters to be a collection, specifying minimum cardinality. e.g. you might want to do this...

class Copy {
  @IndexParameter(0, name = "from", "the source file(s) used to copy", arity = 1)
  List<File> from;

  @IndexParameter(1, name = "to", "the destination file")
  File to;
}

so that you could run the command

copy a b dest

but get an error you do any of the following

copy
copy a

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.