How to create a command line tool using Java?

Java applications can be run using command line , but you can pass only arguments .

Based on the position of the arguments , you can retrieve them in your application and code your logic.

What if you can pass flags to your java application and let it execute logic based on that.

Like in node.js you can create a new project by typing “npm install” or for building a maven project you use” maven clean install.”

That will be a cool application to develop using Java.

There is a java library named picocli which helps in doing exactly that.

As their website says:

Picocli is a Java library and mini-framework for creating command line applications with almost no code.

Let’s use this library to create a command line tool in Java.

Let’s develop a file manipulation tool which can create a file , write to it and read contents of an existing file.

Here is the algorithm:

STEP 1: Copy CommandLine.java from picocli github repository

STEP 2: Create a Java application and paste the copied file in it

STEP 3: Create a main class and add new command to do file manipulation operations

STEP 4: Create an exe and install the command line tool as a Windows native application (optional)

STEP 1: Copy CommandLine.java from picocli github repository

Go to

https://github.com/remkop/picocli/blob/master/src/main/java/picocli/CommandLine.java

and download the file

STEP 2: Create a Java application and paste the copied file in it

Create a java application , create a package picocli and copy the downloaded file into it(you can use a different package name but then you need to modify the copied file which is quite huge)

STEP 3: Create a main class and add new command to do file manipulation operations

I created a class named FileClient.java and added a picocli command.

To add a picocli command:

  • Annotate your class with @Command.
  • Implement Callable interface
  • Perform the operation to be performed inside call() method
  • Capture flag values by annotating class variables with @Option

For example to create a command to create a file through command line, let’s use the flag -cf.

So if user fires a command like this:

filecli -cf "myfirstfile.txt"

a new file gets created.

You can’t directly use the command filecli until your application is converted into a Windows native application but you can run the java main class or jar file and execute the application.

Here is how to annotate the class for running a command :

@Command(name = "fileCli", description = "Performs file manipulation operations", mixinStandardHelpOptions = true, version = "File Client 1.0")
public class FileClient implements Callable<String> {

name is an identifier for the command

description describes the command

mixinStandardHelpOptions will display all the available commands and their usage when user uses the flag –help

version will display the tool’s version when user uses the flag -V

Here it the implementation to create a file:

public String call() throws Exception {

        if (name != null) {
            Path file = of(name);
            if (!file.toFile().exists()) {

                createFile(file);
            }

        }
}

As you see we are creating a file using the variable “name”.

This name is passed as a parameter in command line.

To implement this declare a variable annotated with @Option:

    @Option(names = "-cf", description = "Creates a new file with given name")
    private String name;

Now when user uses the flag -cf followed by the file name , the name is picked up by the application and a new file is created.

I added an option -o to open a file :

    @Option(names = "-o", description = "Opens a given file")
    private boolean openFile;

As you see , this is a boolean variable and doesn’t require any arguments supplied next to it . If user provides the flag -o this flag is set.

I am using both the -cf and -o flags to create a file and open it if user wants so:

  public String call() throws Exception {

        if (name != null) {
            Path file = of(name);
            if (!file.toFile().exists()) {

                createFile(file);
            }

        }
        if (openFile) {
            Runtime.getRuntime().exec("notepad.exe " + name);
        }
}

I added two more options to read and write to a file .

Here is the entire class:

package picocli;

import picocli.CommandLine.Command;
import picocli.CommandLine.Option;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;

import static java.nio.file.Files.createFile;
import static java.nio.file.Path.of;

@Command(name = "fileCli", description = "Performs file manipulation operations", mixinStandardHelpOptions = true, version = "File Client 1.0")
public class FileClient implements Callable<String> {


    @Option(names = "-cf", description = "Creates a new file with given name")
    private String name;

    @Option(names = "-o", description = "Opens a given file")
    private boolean openFile;

    @Option(names = "-w", description = "Writes to a given file")
    private String fileToWrite;

    @Option(names="-r",description = "Opens a file and displays its contents")
    private String fileToRead;

    @Option(names = "-content", description = "Content to write to a file")
    private String content;

    public static void main(String... args) throws Exception {
        int exitCode = new CommandLine(new FileClient()).execute(args);
        System.exit(exitCode);
    }

    public String call() throws Exception {

        if (name != null) {
            Path file = of(name);
            if (!file.toFile().exists()) {

                createFile(file);
            }

        }
        if (openFile) {
            Runtime.getRuntime().exec("notepad.exe " + name);
        }

        if(fileToRead!=null){

            Runtime.getRuntime().exec("notepad.exe " + fileToRead);
        }

        if (fileToWrite != null) {

            Files.writeString(of(fileToWrite), content);
        }

        return "success";
    }
}

You can now run the main java class using a command like this (in the path where .class files are generated):

java picocli.FileClient -cf "helloworld.txt"

I executed this in the below path in my local:

G:\projects\fullstackdeveloperblog\spring\springboot\fileclient\out\production\fileclient>

It created a new file named helloworld.txt in the same path . Providing the entire file path will create it in the corresponding location.

I then converted the application into a jar file using the steps cited here (Generating a jar).

After that I could run the application using the below command :

java -jar fileclient.jar -cf "helloworld.txt"

To open the file after creating it , I used the below command:

java -jar fileclient.jar -cf "helloworld.txt" -o

Now let us create a windows native application and use this tool from any path in our machine!

STEP 4: Create an exe and install the command line tool as a Windows native application

I created an exe file using the steps highlighted here : (Creating a windows native application in Java). I named it as “filecli” which will be the command to use to do the file manipulation operations.

I installed it and it got installed in C:/Program Files/filecli by default.

I included this path in PATH variable:

After this I could run my command line tool from anywhere:

This is the first windows native command line tool I created.

Quite cool!

Note:

I have taken an opinionated approach in using picocli for developing this sample tool . For example , I downloaded the source code and copied it in my project , you can also add it as a maven dependency. For the full features please refer their website.

Entire code is available here: https://github.com/vijaysrj/flieclient

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s