CLI tool
cbeust/jcommander avatar
cbeust/jcommander

JCommander: annotation-based command line parsing for Java 8 through 21

Command line parsing framework for Java

2,027 stars342 forksJavaApache-2.0

At a glance

What is it?
JCommander maps command line arguments to annotated Java fields using @Parameter and @DynamicParameter, covering four Java LTS versions across separate major release lines. The README gives a working example and a build command; the full API documentation lives at jcommander.org.
Who is it for?
JCommander fits Java applications with a moderate or large set of named flags, where annotation-based declarations keep the parameter set visible without a separate iteration loop. Match the version line to your Java LTS: 1.x for Java 8, 2.x for Java 11, 3.x for Java 17, 4.x for Java 21.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Annotation-based parsing replaces the argv iteration loop in Java application code

Java applications that accept command line arguments traditionally read from String[] args and handle each element in conditional logic, checking flag names, parsing their associated values, and setting variables one by one. JCommander moves that work out of imperative code. You annotate fields in a class, pass an instance of that class to the parser, and JCommander fills the fields after reading the argument array.

Annotation scanning means that the mapping between flag name and field happens at runtime rather than at compile time. After parse() returns, the annotated object's fields hold the parsed values with no additional conversion code required in the calling method.

This works well when the parameter set is large or when you want the declaration to stay co-located with the fields that hold the values. One trade-off: annotation scanning runs at startup, and a class hierarchy with many @Parameter fields takes longer to process than a manual switch over a short list. No timing data appears in the README, and jcommander.org is the source for that kind of guidance.

How @Parameter binds scalars, lists, booleans, and positional arguments to fields

@Parameter supports four distinct field patterns, all visible in the README example. A field annotated with bare @Parameter and no names attribute catches positional arguments: the List<String> field fills with every token in argv that is not part of a named flag. A field with names = { "-log", "-verbose" } and Integer type accepts either flag name followed by an integer. Setting the names to a single string, as with names = "-groups", works the same way for String-typed fields. A boolean field with @Parameter(names = "-debug") becomes a flag: the field becomes true when the flag appears in argv and stays false when it does not.

Type conversion depends on the declared Java type of the annotated field. The README example shows Integer, boolean, String, and List<String> as working types. A placeholder attribute, shown as `placeholder = "<group1>,<group2>..."`, provides a hint for usage output but does not affect how the value is parsed.

When two names point to the same field, as in `{ "-log", "-verbose" }`, both flags are interchangeable on the command line.

@DynamicParameter maps open-ended -Dkey=value pairs without declaring each key

JCommander provides a second annotation for the pattern that Java system properties use, where the key names are not known at compile time. The README example declares:

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

The names attribute is the prefix. After parsing "-Doption=value", the map contains the key "option" mapped to "value". Any number of -D-prefixed tokens in argv land in the same map. The README example verifies this with `dynamicParams.get("option")` returning "value".

This differs from @Parameter in contract. A @Parameter field is declared for one specific name and holds one value. @DynamicParameter is declared for one prefix and holds an unbounded set of key-value pairs. Callers already familiar with Java's system property convention can use the same -Dkey=value pattern in application arguments without needing a named @Parameter field for every possible key. The README does not document what separator character @DynamicParameter uses beyond the "=" visible in the single example, so jcommander.org is the place to check edge cases such as values that themselves contain "=".

Building from source with Gradle, and the builder pattern for parsing

The README gives one build command:

code
./gradlew assemble

This compiles the library from the source in src/. The repository root also contains kobaltw and a kobalt/ directory, which points to a previous build tool integration that the README no longer mentions alongside Gradle.

For using JCommander as a dependency rather than building it from source, the README does not list Maven or Gradle coordinates. It says the full documentation is at jcommander.org, which is where those coordinates should appear.

The usage pattern the README shows follows a builder:

java
JCommander.newBuilder()
  .addObject(jct)
  .build()
  .parse(argv);

addObject receives an already-constructed instance of the annotated class. Field defaults declared in the class remain in place for any argument that does not appear in argv. In the README example, the verbose field defaults to 1 in the field declaration and is overridden to 2 by "-log 2" in the argument array. After parse() returns, the object's fields hold the final state.

JCommander 1.x through 4.x each target a distinct Java LTS release

According to the README, each major version line targets a distinct Java LTS release: JCommander 1.x is for Java 8, 2.x for Java 11, 3.x for Java 17, and 4.x for Java 21. Picking the wrong version for the Java runtime in your project will cause compatibility failures that the version scheme is designed to avoid.

A module-info.java at the repository root indicates JCommander declares a Java Platform Module System descriptor. For applications running on the module path rather than the classpath, a library without a module descriptor can trigger split-package warnings or reflective access errors. module-info.java addresses that concern, though the README does not describe what the module exports or requires.

No GitHub releases are published on the repository. CHANGELOG.md at the root tracks changes, though its contents are not reproduced in the README. Developers who need to understand what changed between version lines should read CHANGELOG.md directly, since no release tags exist to anchor a specific version to its changelog entry. The last push to the repository was on 2026-09-20.

What the README leaves undocumented and where the gaps fall

Annotation declarations and the builder invocation are what the README covers, with a pointer to jcommander.org for everything else. Topics absent from the README include: how to mark a parameter as required, how to validate parameter values beyond type conversion, how to define subcommands, how to generate usage text, and how to add support for custom types beyond the ones in the example.

For a project of this age and adoption level, those features likely exist. Evaluating JCommander therefore requires checking jcommander.org before you can confirm whether a specific feature is available, since the README will not tell you.

kobalt/ and kobaltw at the repository root are leftovers from a previous build system that the README no longer covers. Both are present in the file listing but irrelevant for building from source today. SECURITY.md at the repository root suggests a documented process for reporting security vulnerabilities exists, though its content is not reproduced in the README.

Apache-2.0 with attribution files, and the annotation model compared to manual parsing

JCommander is licensed under Apache 2.0. license.txt at the repository root holds the license text. A separate notice.md file is also present, which Apache projects include for third-party attribution notices that must be preserved in derived works. Apache 2.0 permits commercial use and redistribution, provided the attribution requirements in those two files are met.

Compared to parsing args manually, the annotation approach trades startup time for readability. A plain iterator over String[] args avoids runtime annotation scanning and carries no library dependency. JCommander adds both of those costs, and the benefit is a single place to see the full parameter set with names, types, descriptions, and defaults. For a small tool with two or three flags, the manual approach is simpler. For an application with a dozen named parameters and positional argument lists, the annotation model keeps the declaration compact.

JCommander covers only argument parsing. No environment variable fallback, no configuration file loading, and no interactive prompt handling are mentioned anywhere in the README. If jcommander.org covers any of those, the README gives no indication.

Editorial conclusion

JCommander fits Java applications with a moderate or large set of named flags, where annotation-based declarations keep the parameter set visible without a separate iteration loop. Match the version line to your Java LTS: 1.x for Java 8, 2.x for Java 11, 3.x for Java 17, 4.x for Java 21. Before adopting, check jcommander.org to confirm whether required-parameter validation and subcommand routing are documented, because the README does not cover them. Apache 2.0 permits use in commercial software with attribution.

Frequently asked questions

How do I add JCommander as a Maven or Gradle dependency?

The README does not list the Maven or Gradle coordinates. It points to https://jcommander.org for the full documentation, which is where the dependency declaration should appear.

What Java version does JCommander support?

Four version lines are defined: JCommander 1.x targets Java 8, 2.x targets Java 11, 3.x targets Java 17, and 4.x targets Java 21. Use the major version that matches your Java LTS.

What does @DynamicParameter do in JCommander?

It collects parameters that share a prefix into a Map<String, String>. The README example uses @DynamicParameter(names = "-D"), so any -Dkey=value token in argv populates the map with that key and value.

Does JCommander support Java modules?

The repository root contains module-info.java, which indicates JCommander declares a Java Platform Module System descriptor. The README does not describe the module's exports or requirements.

Is JCommander open source?

Yes. The license file at the repository root is license.txt and the license identifier in the repository metadata is Apache-2.0. A notice.md file for third-party attribution is also present.

Official sources

  1. cbeust/jcommander on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cbeust-jcommander.svg)](https://hysenlabs.com/projects/cbeust-jcommander)