Quarkus no es solo para microservicios y APIs REST. También puedes crear aplicaciones de línea de comandos: herramientas que ejecutas desde la terminal, hacen su trabajo, y terminan.
¿Para qué sirven las CLIs? En el mundo empresarial y de desarrollo, son más comunes de lo que parece:
- Herramientas de diagnóstico: verificar que servicios estén activos, validar configuración antes de un despliegue, chequear conectividad
- Procesamiento de datos: leer archivos CSV, transformarlos, generar reportes
- Clientes de APIs internas: un wrapper que simplifica operaciones frecuentes contra tus propios servicios
- Automatización de tareas: lo que antes era un script Bash difícil de mantener, ahora puede ser Java tipado y testeable
- Utilidades de desarrollo: generadores de código, validadores, formateadores
Lo interesante de hacerlas con Quarkus es que puedes compilarlas como ejecutables nativos. Eso significa arranque veloz (milisegundos, no segundos) y un único archivo que puedes distribuir sin necesidad de que el usuario tenga Java instalado.
Un ejemplo práctico: generador de UUIDs
Vamos a construir un generador de UUIDs con un subcomando que sirva para validar:
$ uuid
a3f8b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c
$ uuid --cantidad 3
a3f8b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c
b4e9c3d2-5f6a-7b8c-9d0e-1f2a3b4c5d6e
c5f0d4e3-6a7b-8c9d-0e1f-2a3b4c5d6e7f
$ uuid validar a3f8b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c
✅ UUID válido
$ uuid validar esto-no-es-un-uuid
❌ No es un UUID válidoEs un ejemplo básico, pero nos va a servir para aprender las funcionalidades principales de Picocli.
Picocli: el framework detrás de las CLIs en Java
Picocli es el framework más popular para crear aplicaciones de línea de comandos en Java. Quarkus lo integra de forma nativa, lo que significa que podemos usar todas sus funcionalidades y además compilar a nativo.
¿Qué nos da Picocli?
- Opciones y flags: parámetros como
--cantidad 5,--mayusculas - Subcomandos: estructuras como
git commit,podman run - Ayuda automática: el clásico
--helpsin escribir código - Validación de argumentos: si alguien pone
--cantidad tres, Picocli avisa que esperaba un número
Creando el proyecto
Para aplicaciones CLI usamos quarkus create cli (en lugar del habitual quarkus create app):
quarkus create cli io.quarkiverso:uuid-generator --no-code && \
cd uuid-generatorEl --no-code evita que Quarkus genere código de ejemplo.
La estructura es la típica de Quarkus con la diferencia que la extensión picocli ya viene incluida.
Antes de escribir código, configura src/main/resources/application.properties:
# Salida limpia (sin banner ni logs)
quarkus.banner.enabled=false
quarkus.log.level=WARNEsto hará que nuestro comando uuid muestre solo el resultado en la salida, sin el banner de Quarkus ni mensajes de log de nivel INFO.
El comando principal
Crea el archivo UuidCommand.java en src/main/java/io/quarkiverso/:
package io.quarkiverso;
import java.util.UUID;
import io.quarkus.picocli.runtime.annotations.TopCommand;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@TopCommand
@Command(
name = "uuid",
description = "Genera identificadores únicos (UUID)",
mixinStandardHelpOptions = true
)
public class UuidCommand implements Runnable {
@Option(
names = {"-c", "--cantidad"},
description = "Cuántos UUIDs generar",
defaultValue = "1"
)
int cantidad;
@Option(
names = {"-u", "--mayusculas"},
description = "Genera UUIDs en mayúsculas"
)
boolean mayusculas;
@Override
public void run() {
for (int i = 0; i < cantidad; i++) {
String uuid = UUID.randomUUID().toString();
System.out.println(mayusculas ? uuid.toUpperCase() : uuid);
}
}
}Veamos qué hace cada parte:
| Elemento | Qué hace |
|---|---|
@TopCommand | Indica a Quarkus que este es el comando principal |
@Command | Define que esta clase es un comando ejecutable |
name = "uuid" | El nombre que aparece en la ayuda |
mixinStandardHelpOptions = true | Agrega --help y --version automáticamente |
@Option | Define parámetros configurables |
La anotación @Option tiene:
names: las formas de invocar la opción (-ccorta, o--cantidadlarga)description: aparece en el--helpdefaultValue: valor si no se especifica
Las opciones booleanas como --mayusculas no necesitan valor. Si están presentes, son true.
En este punto ya puedes probar. Compila con:
quarkus buildY ejecuta:
java -jar target/quarkus-app/quarkus-run.jarEl subcomando validar
Ahora agreguemos un subcomando para validar UUIDs. Crea ValidateCommand.java:
package io.quarkiverso;
import java.util.UUID;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
@Command(
name = "validar",
description = "Verifica si un string es un UUID válido"
)
public class ValidateCommand implements Runnable {
@Parameters(
index = "0",
description = "El string a validar"
)
String input;
@Override
public void run() {
try {
UUID.fromString(input);
System.out.println("✅ UUID válido");
} catch (IllegalArgumentException e) {
System.out.println("❌ No es un UUID válido");
}
}
}Aquí usamos @Parameters en lugar de @Option. La diferencia es que los parámetros son posicionales, como en git commit -m "mensaje" donde «mensaje» es un parámetro.
Ahora conectamos el subcomando al comando principal. En UuidCommand.java, agrega el elemento subcommands (presta atención a los dos comentarios):
@TopCommand
@Command(
name = "uuid",
description = "Genera y valida identificadores únicos (UUID)",
mixinStandardHelpOptions = true, // <-- agregar la , al final
subcommands = { ValidateCommand.class } // <-- agregar esta línea
)
public class UuidCommand implements Runnable {Probando la herramienta
Compila el proyecto:
quarkus buildY ejecuta:
# Genera un UUID
java -jar target/quarkus-app/quarkus-run.jar
# Genera cinco UUIDs
java -jar target/quarkus-app/quarkus-run.jar -c 5
# En mayúsculas
java -jar target/quarkus-app/quarkus-run.jar -u
# Combinando opciones
java -jar target/quarkus-app/quarkus-run.jar -c 3 -u
# Validar un UUID
java -jar target/quarkus-app/quarkus-run.jar validar a3f8b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c
# Validar algo inválido
java -jar target/quarkus-app/quarkus-run.jar validar hola-mundoProbando la ayuda
Ejecuta --help para ver la documentación automática:
# Ayuda general
java -jar target/quarkus-app/quarkus-run.jar --help
# Ayuda del subcomando
java -jar target/quarkus-app/quarkus-run.jar validar --helpTodo esto lo genera Picocli a partir de las anotaciones. No escribimos ni una línea de código para la documentación.
Validación automática de Picocli
Una de las ventajas de Picocli es que valida los argumentos automáticamente. Si alguien se equivoca, el error es claro:
java -jar target/quarkus-app/quarkus-run.jar --cantidad tres
Invalid value for option '--cantidad': 'tres' is not an intNo tuvimos que escribir código para eso. Picocli sabe que cantidad es un int y valida la entrada.
Compilando a ejecutable nativo
Hasta ahora usamos java -jar, que funciona pero tarda casi un segundo en arrancar porque levanta la JVM. La ventaja de Quarkus es que podemos compilar un ejecutable nativo.
Para compilar a nativo, ejecuta:
quarkus build --nativeLa compilación nativa tarda un poco, pero el resultado vale la pena. El ejecutable queda en target/:
./target/uuid-generator-1.0.0-SNAPSHOT-runner -c 3Para usarlo como mostramos al principio (uuid -c 3), renómbralo de la siguiente manera para que el ejecutable nativo quede en la raíz del proyecto:
# Linux / macOS
mv target/uuid-generator-1.0.0-SNAPSHOT-runner uuid
./uuid -c 3
# Windows
rename target\uuid-generator-1.0.0-SNAPSHOT-runner.exe uuid.exe
uuid.exe -c 3La diferencia en velocidad de arranque es notable:
# Con JVM
time java -jar target/quarkus-app/quarkus-run.jar
# 0.204 total
# Nativo
time ./uuid
# 0.020 totalEl ejecutable nativo arranca, en este caso, unas 10 veces más rápido. Para una herramienta que se ejecuta frecuentemente, eso marca la diferencia.
El ejecutable es autónomo: no necesita Java instalado ni librerías extra. Puedes copiarlo a cualquier lugar de tu sistema.
Pruebas
Como vimos en Testing en Quarkus: La guía definitiva, una aplicación bien construida incluye pruebas. El proyecto de este artículo no es la excepción.
En el repositorio git disponible al final de este artículo 👇, incluyo dos tipos de tests:
UuidCommandTestcon@QuarkusTest: pruebas rápidas que se ejecutan en JVM durante el desarrolloUuidCommandITcon@QuarkusIntegrationTest: pruebas contra el ejecutable nativo compilado
Ambos validan los mismos escenarios: generación de UUIDs, opciones combinadas, validación correcta e incorrecta, y manejo de errores en argumentos.
# Tests unitarios
./mvnw test
# Tests de integración (compila el nativo automáticamente)
./mvnw verify -DnativeResumen
Desde la línea de comandos también se explora el Quarkiverso. En este artículo creamos una CLI con Quarkus, aprendemos a estructurar comandos reales y la convertimos en un ejecutable nativo listo para usar:
| Concepto | Para qué sirve |
|---|---|
@TopCommand | Indica el comando principal a Quarkus |
@Command | Define comandos y subcomandos |
@Option | Parámetros con nombre (--cantidad) |
@Parameters | Parámetros posicionales |
subcommands | Estructura jerárquica de comandos |
mixinStandardHelpOptions | --help y --version automáticos |
quarkus build --native | Ejecutable instantáneo |
El código completo está disponible en el repositorio del Quarkiverso.

