First of all, we need to create a new Kotlin project with Gradle as a build system. The easiest way to do that is by clicking through the Project window in IntelliJ IDEA.
The second step is to configure the build.gradle.kts file so that it looks like this: I’ll explain it later.
- You need to add the Kotlin plugin and kotlin.kapt.
- Add picocli-codegen as kapt (kotlin-annotation-processor)
- Add picocli as an implementation
- Create kapt block with the argument project.
- Configure the jar file output by setting a manifest with the attribute Main-Class. In my case it is CheckSumKt.
- Exclude the META-INF files from the classpath.
- Enable Annotation Processors in intelliJ. Docs here
Create the CheckSum class
This file has a special syntax, the Command annotation defines the name of the command, which should be called finally. It also defines, the version and if it should generate a help option.
The Class or command Checksum has a parameter and one option. With the Parameter annotation you can define, at which position the parameter should get read in. You could give it a default value, in my example, I leave it without.
With the Option annotation you can define options like the algorithm. You can also give it a default value. In this case “MD5”.
The next part is the call() function. It creates a ByteArray with the provided file. Then it converts that ByteArray to a checkSum of the chosen algorithm. After that it just prints out that cryptic value on a new line and returns 0.
The return value needs to be 0, because every other value would be a failure.
The last step is the main function. It Takes an Array of Strings as arguments and returns nothing. This main class creates an instance of the Checksum class and executes it. The logic for this is handeled by Picocli.
Build and start the Application
To build the application, you just have to use a normal gradle command:
$ ./gradlew clean build
To start your application now, run:
$ java -jar build/libs/picocli-test-1.0.jar
picocli-test is the project name in my example. The version is defined in the build.gradle.kts file.
The output should look something like this. You can use these parameters and options defined in your CheckSum class. For example to see the SHA-1 checkSum of a file with the content “hello” you would type:
To run this jar file like a real cli application, run these two commands in your project directory.
echo "export PATH=$PATH:$(pwd)" >> ~/.zshrc
echo "alias checksumjar='java -jar $(pwd)/build/libs/picocli-test-1.0.jar'" >> ~/.zshrc
The first one adds the current directory to the PATH variable. This makes the files in this directory executable. The second one creates an alias for the jar file.
Native with GraalVM
To use GraalVM, you have to download it first via homebrew:
$ brew install graalvm-ce-java8
Now you need to set the prerequesites for GraalVM like described here.
After that, you can go to the java home of the GraalVM and run ./bin/gu
$ cd /Library/Java/JavaVirtualMachines/graalvm-ce-java8- 21.0.0/Contents/Home$ ./bin/gu install -L /bin/native-image
The last step is to actually create the actual image with :
$ $GRAAL_HOME/native-image -cp classes:build/libs/picocli-test-1.0.jar --no-server -H:Name=checksum CheckSumKt
The result you will endup is a file in the root of your project with the name checksum. You can run it with
Why to make this extra step? Simple! The file runs now native on Linux and MacOS and is blazing fast. It does not need the JVM anymore installed and is now immutable to wrong java versions on client side.
The total time got minimized by a factor of 17 ! 🤯 Thats a big difference, especially if the application gets bigger.
Thanks for reading this article. I hope it was helpful