DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report

JCommander – Parsing Command Line Parameters With Ease

Tomasz Dziurko user avatar by
Tomasz Dziurko
·
May. 23, 12 · Interview
Like (0)
Save
Tweet
Share
24.72K Views

Join the DZone community and get the full member experience.

Join For Free

from time to time each of us have to create a small console application to perform a few tedious tasks that can be automated so we can concentrate on more creative ones instead. and every time i had to build such an app i struggled with passing options via command line parameters. instead of concentrating on implementing logic, i had to create a parser, validator and so on. and in another console application i had to do the same… again and again. but thankfully it’s over.

thanks to small library by cédric beust , creator of well-known java testing framework testng . this time he created jcommander with a motto because life is too short to parse command line parameters . but enogh talking, let’s sit down and write some code.

a simple use case

at the begginning assume that we have to write an application to generate a timesheet report from a given month. so simplified use case is: connect to application where all data is stored and load what everything we need. to perform this operation we need four parameters: url to the application where data is stored, authentication token and of course number of month and year. so let’s create a settings class where all this data will be stored.

public class settings {
 
    private string url;
 
    private string authenticationtoken;
 
    private integer month;
 
    private integer year;
 
}

and our main application class with main() method:

public class main {
 
    public static void main(string[] args) {
 
        settings settings = new settings();
        // somehow pass args[] to settings object
 
        // do the logic
    }
}

but how should we pass all stuff from command line parameters to the settings class so it is automatically initialized with these values? it’s simple!

first we have to annotate fields in settings class using @parameter so jcommander will know how to map parameters from command line to fields.

public class settings {
 
    @parameter(names = "-url", description = "server address", required = true)
    private string url;
 
    @parameter(names = "-token", description = "authentication token", required = true)
    private string authenticationtoken;
 
    @parameter(names = "-month", description = "number of month (1-12) for timesheet", required = true)
    private integer month;
 
    @parameter(names = "-year", description = "year", required = true)
    private integer year;
 
}

annotation we’ve added looks pretty straightforward. we define name of parameter and whether it is required or not. if we do not provide a token (which is required) in command line we will get something similar to:

exception in thread "main" com.beust.jcommander.parameterexception: the following options are required: -token

and in next step we have to inform jcommander which object should be initialized with data extracted from command line. it’s a simple one-liner.

public class main {
 
    public static void main(string[] args) {
 
        settings settings = new settings();
        new jcommander(settings, args); // simple one-liner
        // do the logic
    }
}

and that’s all. we have simple jcommander example working and all settings passed via command line params are now initialized in settings object.

some additional options

multiple values

but then we receive some new feature requests. we have to generate report for a list of projects. it can be only one project but it can be more. so how can we implement it? nothing difficult. we add list<string> projects to our settings class and mark it as a required parameter.

@parameter(names = "-project",
    description = "codes of projects to be included in timesheet report", required = true)
private list<string> projectcodes;

seeing a collection jcommander will detect that it should expect multiple values for project parameter name. and if we call our console application with something like

java -jar application.jar -project project1 -project project2 - project project3

we will get list of these names in projectcodes field.

input validation

if we want to validate that month parameter is between 1 and 12 we can do it easily with just one method from interface iparametervalidator . in our case it will look like show below:

public class monthvalidator implements iparametervalidator {
 
    @override
    public void validate(string name, string value) throws parameterexception {
        int month = integer.parseint(value);
 
        if(month < 1 || month > 12) {
            throw new parameterexception("parameter " + name + " should be between 1 and 12");
        }
    }
}

and we have to declare this validator using validatewith from @parameter annotation:

@parameter(names = "-month",
    description = "number of month (1-12) for timesheet", required = true, validatewith = monthvalidator.class)
private integer month;

input conversion

sometimes we need to have one of our options mapped to something more than a simple basic type. let’s say that in our example console application user should provide type of report output he/she wants to get. it could be console output, pdf or xls file. so in out settings class we have a enum outputenum with three allowed values:

public class settings {
 
    // ...
    @parameter(names = "-output", description = "report output format", required = true)
    private outputenum output;
 
}
 
public enum outputenum {
 
    console,
    pdf,
    xls;
 
    // converter that will be used later
    public static outputenum fromstring(string code) {
 
        for(outputenum output : outputenum.values()) {
            if(output.tostring().equalsignorecase(code)) {
                return output;
            }
        }
 
        return null;
    }
}

but now jcommander doesn’t know how to work with our new enum class. we need to provide a converter. so let’s create one. and again, it’s easy :) we have to implement one method from istringconverter and throw parameterexception when something is wrong.

public class outputconverter implements istringconverter<outputenum> {
 
    @override
    public outputenum convert(string value) {
        outputenum convertedvalue = outputenum.fromstring(value);
 
        if(convertedvalue == null) {
            throw new parameterexception("value " + value + "can not be converted to outputenum. " +
                    "available values are: console, pdf, xls.");
        }
        return convertedvalue;
    }
}

and when converter is ready, we should inform jcommander to use it on one of fields in settings class with converter annotation parameter.

public class settings {
 
    // ...
    @parameter(names = "-output", description = "report output format", required = true, , converter = outputconverter.class)
    private outputenum output;
 
}

and now settings object will be correctly initialized with outputenum.

summary

that’s all. i’ve shown some most useful features of jcommander, an easy tool to make parsing command line paramters a breeze. if you want some more info, please check official jcommander website or even dive into its source code on github.

Command (computing) application Ease (programming language)

Published at DZone with permission of Tomasz Dziurko, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Detecting Network Anomalies Using Apache Spark
  • Asynchronous Messaging Service
  • How Chat GPT-3 Changed the Life of Young DevOps Engineers
  • Configure Kubernetes Health Checks

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: