Command line parsing framework for Java

Related tags

CLI jcommander
Overview

JCommander

This is an annotation based parameter parsing framework for Java 8.

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
Comments
  • Accepting a single main parameter doesn't appear to be possible

    Accepting a single main parameter doesn't appear to be possible

    We only support opening a single case at a time, so I figured I would just use this for accepting the location as the main parameter:

    @Parameter(descriptionKey = "DesktopMainArguments.docLocation")
    public File docLocation;
    

    Attempting to parse then throws the following exception:

    com.beust.jcommander.ParameterException: Main parameter field public java.io.File com.acme.main.MainArguments.docLocation needs to be of type List, not class java.io.File
    

    I'm sure I could change it to a list, but then I would have to put in boilerplate to check that the user hasn't specified more than one. Is there a proper way to do this directly? Because I can't seem to find it in the examples or in the API.

    I thought validation might be the way to do it, but I suspect I was wrong about that because the validator receives the original command-line string, not the final converted object.

    opened by hakanai 21
  • Newer versions on Central Repository

    Newer versions on Central Repository

    Would it be possible to sync or release the newer versions of jcommander to the Central Repository again? The last one available there is 1.48

    https://repo1.maven.org/maven2/com/beust/jcommander/

    Newer versions are available on jcenter

    https://dl.bintray.com/cbeust/maven/com/beust/jcommander/

    but it would just be nice to be able to use jcommander with Maven and other projects out of the box as well. Just makes it easier to use in open source projects imho..

    opened by mosabua 17
  • Strange behaviour of the parameter validators

    Strange behaviour of the parameter validators

    Hi,

    We are having a strange behaviour from the way JCommander is dealing with validator classes. Let me describe our scenario in more details. We have a parent command, called Parent, and two completely disjoint subclasses - A and B, which are as well both JCommander commands.

    Both A and B define parameter with the same name - call it 'par', of the same type (Parent does not have this 'par' parameter). But only command B specifies a validator class for this parameter.

    Now, what happens is that we call the command A from the command line, and we get an error ... from the validator for command B! But this validator shouldn't be called at all for command A - this breaks our semantics and intention.

    I made some debugging and this is what happens:

    When JCommander launches, it scans and installs all recoginzed comands - for example {B, A, Parent}. Next, it enters some initializing phase of setting default values for all command parameters - it iterates the commands, one by one. First, it reaches the command B, and next it reaches its parameter 'par'. It tries to set default value to it, which is firstly checked to be taken from a property provider file (if any). At this point in time, such a value is being set to our parameter, because we do use a property provider file. Next, the validator is called for this default value. And here the validation fails - which is completely OK, since this value is not suitable for command B - but is perfectly OK for command A.

    So, to summarize: although I call only one command, JCommander initializes and sets default values (and then calls validators) on all commands, and on all of their parameters.

    To my understanding, this is a bug and it should be fixed.

    Kindest Regards, Krum.

    opened by kpymkata 17
  • Need way to automatically show usage if required params are missing

    Need way to automatically show usage if required params are missing

    Currently if you specify help = true in a parameter, exceptions are suppressed. However, you then have to manually check for required parameters not being set.

    It would be great if there were a way to prevent exceptions from being thrown on missing required parameters, but print the usage text instead. Maybe in addition to adding help = true to a help parameter, you could also specify usage = true, and if a parameter is missing, even if the help option was not given on the commandline, JCommander could set the help parameter value to true, so that the usage text is displayed?

    opened by lukehutch 16
  • better support for positional arguments

    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
    
    opened by jstrachan 16
  • Java 6 required?

    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 :(

    opened by huxi 15
  • Project help wanted?

    Project help wanted?

    @cbeust Cedric, according to the Github statistics, your project is stale since one year. While there are recent issues and PRs, no commits have been pushed for one full year. Do you need project help? Our company could chime in and manage the project for you if you like.

    opened by mkarg 13
  • Flexible usage formatting

    Flexible usage formatting

    Hello,

    This is the basic skeleton of what I want to do with usage formatting.

    • I have managed to extract most of the usage formatting to the UsageFormatter and its default subclass DefaultUsageFormatter.
    • I only left behind JCommander#usage() to act as a simple way to print usage, without messing with the underlying UsageFormatter.
    • I allow injecting UsageFormatter into JCommander through a setter.

    I want to do the following before we consider this solution:

    • [X] Try to implement a Unix-style usage formatter to test the flexibility of the solution
    • [X] Try to restrict the access of members I exposed in JCommander to make this work
    • [X] Clean up the DefaultUsageFormatter code some more
    • [x] Test it

    One problem is that this is a public API change, so you might choose to keep some of the old usage methods in JCommander for backwards compatibility sake.

    opened by dozmus 12
  • Allow parameters to be abbreviated

    Allow parameters to be abbreviated

    This code allows users to enter the shortest unambiguous prefix of a parameter name. For example, given parameters --alpha --beta, and --barium, users need only type --a, --bet, and --bar on the command line.

    Last November, we discussed implementing this as a "wrapper" to JCommander. However, that solution does not work well when commands are used. For example, JCommander allows the parameters for different commands to have different prefixes. It would be very difficult to implement the abbreviations as a wrapper and support similar behavior.

    Instead, I made a few small changes right in JCommander. In particular I added an AbbreviationMap instance variable. This object maps abbreviated parameters to the appropriate ParameterDescription (if the abbreviation is unambiguous).

    I then added this code at JCommander line 642 in parseValues:

    ParameterDescription pd; if (allowAbbreviations) { pd = m_abbrevMap.get(a); } else { pd = m_descriptions.get(a); }

    I got AbbreviationMap from Paul Hosler's JOptSimple package. It uses the MIT license.

    I added these two methods:

    /** * Parse and validate the command line parameters allowing abbreviated parameters. */ public void parseWithAbbreviations(String... args) { parseWithAbbreviations(true, args); }

    /** * Parse the command line parameters allowing abbreviated parameters. / public void parseWithAbbreviations(boolean validate, String... args) { parse(validate, true / allow abbreviations */, args); }

    Perhaps instead of parse, parseWithoutValidation, and two versions of parseWithAbbreviations, we want to simply make this method public:

    private void parse(boolean validate, boolean allowAbbreviations, String... args) {

    Let me know what you think.

    opened by kurmasz 12
  • Support for invoking runnable callbacks on command parsing

    Support for invoking runnable callbacks on command parsing

    Support for invoking runnable callbacks on command parsing

    This started as an attempt to let users specify command names and aliases using annotations. However, since you still have to manually match command name against getParsedCommand() output in order to select the right action to be invoked, moving command name to the annotation provides little benefit by itself.

    The solution, as proposed in issue #54, is to associate a callback (e.g. Runnable) with a command and automatically invoke it when the command is encountered and parsed (see CommandCallableScenarioTest). Additionally, I have added a custom JRunnable class that receives the parsed parameters as an argument to the callback.

    The advantage is that you can define command name and aliases in the annotation once, specify the runnable, and the rest is handled by JCommander. You also don't need to save a reference to the parameters object, you can just do jc.addCommand(new MyCommandOpts(), new JCallable<MyCommandOpts>(){ ... }.

    The drawbacks of the approach are:

    1. The callback invoking logic is simply: parsed command --> associated callback. For anything more complex, the user will have to go back to the old-fashioned way.
    2. The order in which JCommander#parse() is called and the associated callbacks are invoked will change. Currently you call parse() then your get the parsed command and invoke the associated callback. With the new approach first you define the callback, then you call parse(). This may cause problems if you need to insert custom logic that needs the original ordering.

    Let me know if you have an opinion on this style of doing things. Maybe it's an overkill?

    opened by rodionmoiseev 12
  • Not all repositories provide the latest version 1.74 ?

    Not all repositories provide the latest version 1.74 ?

    opened by Pitterling 11
  • upgrade gradle 6.6.1 -> 7.6

    upgrade gradle 6.6.1 -> 7.6

    Fixes #548

    I upgraded this by running the gradle wrapper command which also had the effect up updating the gradlew scripts.

    gradle wrapper --gradle-version 7.6
    
    opened by pgier 1
  • Build fails with Java 17

    Build fails with Java 17

    I'm using Java 17 (openjdk version "17.0.5" 2022-10-18) on macos, and when I try to run the default build, it fails with a Java module error:

    > ./gradlew assemble
    > Task :compileJava FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':compileJava'.
    > java.lang.IllegalAccessError: class org.gradle.internal.compiler.java.ClassNameCollector (in unnamed module @0x2f377c45) cannot access class com.sun.tools.javac.code.Symbol$TypeSymbol (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.code to unnamed module @0x2f377c45
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 780ms
    1 actionable task: 1 executed
    
    opened by pgier 1
  • Global parameter validation documentation is not deployed to jcommander.org

    Global parameter validation documentation is not deployed to jcommander.org

    opened by jontmy 1
  • Main parameter conversion has priority over arity validation

    Main parameter conversion has priority over arity validation

    Suppose that I have this converter which takes a String and attempts conversion into an Index - which is basically a wrapper around an int:

    public class IndexConverter implements IStringConverter<Index> {
        @Override
        public Index convert(String value) {
            if (!StringUtil.isNonZeroUnsignedInteger(value)) {
                throw new ParameterException("The index must be a non-zero unsigned integer.");
            }
            return Index.fromOneBased(Integer.parseInt(value));
        }
    }
    

    However, if I define a parameter in my command class like so, and I attempt to let JCommander parse the command <command word> 123 abc, now I get the ParameterException thrown because the "abc" is not an integer - but should JCommander instead realize that the arity of 2 is incorrect before attempting conversion?:

    @Parameters(commandDescription = "...")
    public class ExampleCommand extends Command {
    
        @Parameter(description = "...", required = true, converter = IndexConverter.class, arity = 1)
        private Index targetIndex;
        ...
    }
    

    My rationale for raising this issue is that the exception message is of the wrong specificity - the exception from the failed conversion has higher priority than the exception from the arity.

    This is behavior is undesirable for my use case as it's more important to reject the incorrect arity than to inform the user of a failed conversion.

    Could there be a way to configure JCommander to validate arities before conversions?

    opened by jontmy 0
  • why specified convert not effect ?

    why specified convert not effect ?

    I create a JobPriorityConverter class, it's inherit from EnumConverter.

    public class JobPriorityConverter extends EnumConverter<JobPriority> {
      public JobPriorityConverter(final String str, final Class<JobPriority> clazz) {
        super(str, clazz);
      }
    
      @Override
      public JobPriority convert(String value) {
        JobPriority jobPriority = super.convert(value);
        if (jobPriority == JobPriority.VERY_HIGH || jobPriority == JobPriority.UNKNOWN_JOB_PRIORITY) {
          return JobPriority.HIGH;
        } else {
          return jobPriority;
        }
      }
    }
    

    The JobPriority is generated by proto, it look like below

    public enum JobPriority implements com.google.protobuf.ProtocolMessageEnum {
      UNKNOWN_JOB_PRIORITY(0),
      VERY_HIGH(1),
      HIGH(2),
      NORMAL(3),
      UNRECOGNIZED(-1);
    }
    

    Now, I have a parameter.

    @Parameter(names = {"--priority"}, converter = JobPriorityConverter.class)
    protected JobPriority priority = JobPriority.NORMAL;
    

    But I run the program, for example: java -classpath xxx ... className --priority VERY_HIGH, then it should be HIGH, actually it's still VERY_HIGH.

    I pass the invalid priority, it output.

    Exception in thread "main" com.beust.jcommander.ParameterException: Invalid value for -pr parameter. Allowed values:[UNKNOWN_JOB_PRIORITY, VERY_HIGH, HIGH, NORMAL, UNRECOGNIZED]
    	at com.beust.jcommander.converters.EnumConverter.convert(EnumConverter.java:38)
    	at com.beust.jcommander.converters.EnumConverter.convert(EnumConverter.java:13)
    	at com.beust.jcommander.JCommander.convertValue(JCommander.java:1472)
    	at com.beust.jcommander.ParameterDescription.addValue(ParameterDescription.java:238)
    	at com.beust.jcommander.JCommander.processFixedArity(JCommander.java:895)
    	at com.beust.jcommander.JCommander.processFixedArity(JCommander.java:870)
    	at com.beust.jcommander.JCommander.parseValues(JCommander.java:721)
    	at com.beust.jcommander.JCommander.parse(JCommander.java:340)
    	at com.beust.jcommander.JCommander.parse(JCommander.java:319)
    
    opened by Wuv1Up 0
  • Why is there `module-info.java`?

    Why is there `module-info.java`?

    I am packaging this project and noticed this file outside of java source tree. Is it supposed to be added manually or not? If not, is there a reason why it is present in the project at all? I see that currently released jars are not modular. In any case even the module-info.java seems to be incomplete as I got the following errors when I attempted to build the project with the file added into the java source tree:

    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project jcommander: Compilation failure: Compilation failure: 
    [ERROR] /builddir/build/BUILD/beust-jcommander-1.82/src/main/java/com/beust/jcommander/Parameterized.java:[11,17] package java.util.logging is not visible
    [ERROR]   (package java.util.logging is declared in module java.logging, but module com.beust.jcommander does not read it)
    [ERROR] /builddir/build/BUILD/beust-jcommander-1.82/src/main/java/com/beust/jcommander/Parameterized.java:[12,17] package java.util.logging is not visible
    [ERROR]   (package java.util.logging is declared in module java.logging, but module com.beust.jcommander does not read it)
    

    I just want to point out that the current situation creates confusion for others as to whether or not module-info.java should be used.

    opened by mkoncek 0
Owner
Cedric Beust
Creator of Android Gmail.
Cedric Beust
TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

Emmet Hayes 1 Dec 2, 2022
A command line parser generator

jbock is a command line parser that works similar to airline and picocli. While most of these other tools scan for annotations at runtime, jbock is an

H90 73 Dec 13, 2022
Command-line API for Atlassian JIRA using the Tomitribe CREST library

Atlassian JIRA Command-Line (CLI) Jamira is a command-line API for Atlassian JIRA using the Tomitribe CREST library. Installation Jamira can be downlo

Tomitribe 12 Sep 10, 2022
DeV Tools - Swiss Army Knife of command line utilities

dvt aims to bundle all small utilities used by developers (typically a mix of cli and online tools) into one binary that you can simply use in the console. No need for complex pipe-ing, copy-pasting on different sites or keep installing cli utilities for every need.

Madalin Ilie 13 Sep 15, 2022
AWS JSON TRANSLATOR CLI is a command line application to translate JSON files using AWS Translate

A command line tool to translate JSON files using AWS Translate.

Marc Guillem 0 May 30, 2022
Annotation-based command framework for Minestom

Minestand Annotation-based command framework for Minestom Advantages over other frameworks Minestand works by converting your classes into Minestom co

null 6 Aug 27, 2022
Wrapper around ping command for Windows and MacOS

Wrapper around ping command for Windows and MacOS. Extended with functionality to intercept results provided by the ping command output (latency, ttl and etc.)

Vladislav Kozlov 1 Jan 6, 2022
Jansi is a small java library that allows you to use ANSI escape sequences to format your console output which works even on windows.

Description Jansi is a small java library that allows you to use ANSI escape codes to format your console output which works even on Windows. It also

FuseSource 955 Dec 28, 2022
ASCII renderer in pure java with no external dependencies

Java ASCII Render ASCII renderer in pure java with no external dependencies. Java ASCII Render supports graphical primitives/elements, layers, context

David E. Veliev 140 Dec 12, 2022
JLine is a Java library for handling console input.

JLine JLine is a Java library for handling console input. It is similar in functionality to BSD editline and GNU readline but with additional features

null 1.2k Jan 5, 2023
A library for creating interactive console applications in Java

Text-IO Text-IO is a library for creating Java console applications. It can be used in applications that need to read interactive input from the user.

Beryx 295 Jan 5, 2023
Java library for creating text-based GUIs

Lanterna Lanterna is a Java library allowing you to write easy semi-graphical user interfaces in a text-only environment, very similar to the C librar

null 2k Dec 31, 2022
Command line parsing framework for Java

JCommander This is an annotation based parameter parsing framework for Java 8. Here is a quick example: public class JCommanderTest { @Parameter

Cedric Beust 1.8k Dec 29, 2022
TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

Emmet Hayes 1 Dec 2, 2022
Yet another Java annotation-based command parsing library, with Dependency Injection inspired by Guice

Commander A universal java command parsing library Building This project uses Gradle. Clone this repository: git clone https://github.com/OctoPvP/Comm

OctoDev 4 Oct 2, 2022
Java monitoring for the command-line, profiler included

jvmtop is a lightweight console application to monitor all accessible, running jvms on a machine. In a top-like manner, it displays JVM internal metri

null 1.2k Jan 6, 2023