/java-cli-template

Template repository for starting new java based CLI applications built with Picolci

Primary LanguageJavaMIT LicenseMIT

Java CLI Template

Maven CI Gradle CI

This is a template repository for building CLI applications with Java. It leverages Picocli for bootstrapping the CLI execution and GraalVM native-image for building a native image executable.

  • JDK Version: 17
  • GraalVM Version: 21.3.0

Build

Maven

For the native-image build, see instructions at bottom for tooling pre-requisites. Your JAVA_HOME will need to be set with GraalVM installation.

./mvnw clean install # Build executable JAR
./mvnw clean install -D nativeImage # Build native image

Gradle

./gradlew clean build # Build executable JAR
./gradlew clean nativeImage # Build native image

Docker

An external build is first required since the Dockerfile needs to ADD the executable JAR.
By default, the JAR used is from maven build.

docker build -t java-cli-template .

To use the gradle build output:

docker build -t java-cli-template --build-arg "JAR=build/libs/java-cli-template-*.jar" .

Run

Maven

Executable JAR

java -jar target/java-cli-template-*.jar --help
java -jar target/java-cli-template-*.jar hello-world
java -jar target/java-cli-template-*.jar hello-world Brian
echo "Brian" | java -jar target/java-cli-template-*.jar hello-world -

Native Image

./target/app --help
./target/app hello-world
./target/app hello-world Brian
echo "Brian" | ./target/app hello-world -

Gradle

Executable JAR

java -jar build/libs/java-cli-template-*.jar --help
java -jar build/libs/java-cli-template-*.jar hello-world
java -jar build/libs/java-cli-template-*.jar hello-world Brian
echo "Brian" | java -jar build/libs/java-cli-template-*.jar hello-world -

Native Image

./build/graal/app --help
./build/graal/app hello-world
./build/graal/app hello-world Brian
echo "Brian" | ./build/graal/app hello-world -

Docker

docker run java-cli-template --help
docker run java-cli-template hello-world
docker run java-cli-template hello-world Brian
echo "Brian" | docker run -i java-cli-template hello-world -

Reflection in Native Image

Runtime reflection in a native image is tricky. GraalVM can detect basic usage of class loading with reflection, however it cannot determine classes loaded dynamically. To allow it to work, some configuration needs to be done.

See Reflect.java for how the class is loaded "dynamically".

This Will Work

./app reflect java.lang.String

This is because it has been configured in reflect-config.json.

This Will Not Work

./app reflect java.util.List

This is because it is not included in reflect-config.json

Native Image Prerequisites When Using Maven

The maven build requires that GraalVM and native-image tooling already be available on the machine.

  • GraalVM CE
  • GraalVM CE native-image
  • zlib / xcode

GraalVM Installation

./install-graalvm.sh

If you are using Gradle or Docker, you do not need to perform this installation.

GraalVM and Native Image Installation Instructions