JBang: La Herramienta de Scripting que le Faltaba a Java


El ecosistema Java ya cuenta con poderosas herramientas de gestión de proyectos como Maven y Gradle, pero hasta ahora carecía de una herramienta de scripting simple y potente. Aquí es donde entra JBang, un lanzador minimalista pero versátil para archivos Java, Kotlin y Groovy que está transformando la manera en que escribimos scripts en el ecosistema Java.
¿Qué es JBang?
JBang es una herramienta que permite ejecutar código Java (y otros lenguajes JVM) tan fácilmente como ejecutarías un script en Python o JavaScript. Lo más impresionante es que incorpora gestión de dependencias, plantillas y hasta tiene su propia "App Store".
Instalación y Configuración
La instalación de JBang es sencilla y está disponible para Windows, Linux y macOS. Aquí te muestro los pasos básicos:
En Windows
curl -Ls https://sh.jbang.dev | bash
En Linux/macOS
curl -Ls https://sh.jbang.dev | bash
Para verificar la instalación:
jbang --version
Instalación de JDK
JBang puede manejar la instalación de JDK por ti:
jbang jdk install 23
extension vsc
Tu Primer Script con JBang
Vamos a crear nuestro primer script. Es tan simple como:
jbang init helloworld.java
Esto creará un archivo con este contenido:
///usr/bin/env jbang "$0" "$@" ; exit $?
import static java.lang.System.*;
public class helloworld {
public static void main(String... args) {
out.println("Hello world");
}
}
Para ejecutarlo:
jbang helloworld.java
# Salida: Hello world
Gestión de Dependencias
Una de las características más potentes de JBang es su manejo de dependencias. Veamos un ejemplo más elaborado usando una librería externa para crear texto ASCII art:
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.github.lalyos:jfiglet:0.0.9
import com.github.lalyos.jfiglet.FigletFont;
public class AsciiArt {
public static void main(String... args) throws Exception {
String text = args.length > 0 ? args[0] : "JBang";
System.out.println(FigletFont.convertOneLine(text));
}
}
Al ejecutarlo:
jbang AsciiArt.java "Hola"
Obtendrás algo como:
_ _ _
| | | | | |
| |__| | ___ | | __ _
| __ |/ _ \| |/ _` |
| | | | (_) | | (_| |
|_| |_|\___/|_|\__,_|
Scripts en Groovy
JBang también soporta Groovy, lo que nos permite escribir scripts más concisos. Aquí hay algunos ejemplos:
Ejemplo Básico en Groovy
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS org.apache.commons:commons-lang3:3.12.0
import org.apache.commons.lang3.StringUtils
def mensaje = "¡Hola desde Groovy!"
println StringUtils.reverse(mensaje)
println "Argumentos recibidos: ${args}"
Ejemplo más Complejo en Groovy con HTTP
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS org.apache.httpcomponents:httpclient:4.5.13
//DEPS com.fasterxml.jackson.core:jackson-databind:2.13.0
import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.client.HttpClients
import com.fasterxml.jackson.databind.ObjectMapper
def httpClient = HttpClients.createDefault()
def mapper = new ObjectMapper()
def response = httpClient.execute(new HttpGet("https://api.github.com/users/jbangdev"))
def json = mapper.readTree(response.entity.content)
println """
GitHub User Info:
----------------
Name: ${json.name}
Bio: ${json.bio}
Followers: ${json.followers}
Following: ${json.following}
"""
Aplicaciones REST con Quarkus
JBang hace que crear APIs REST sea sorprendentemente fácil. Aquí tienes un ejemplo completo:
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 17+
//DEPS io.quarkus:quarkus-bom:3.15.1@pom
//DEPS io.quarkus:quarkus-resteasy
//DEPS io.quarkus:quarkus-resteasy-jsonb
//DEPS io.quarkus:quarkus-swagger-ui
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Path("/tareas")
public class TareasAPI {
private static final Map<Integer, String> tareas = new ConcurrentHashMap<>();
private static int contador = 1;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Map<Integer, String> listarTareas() {
return tareas;
}
@POST
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.APPLICATION_JSON)
public Map<String, Object> agregarTarea(String tarea) {
int id = contador++;
tareas.put(id, tarea);
return Map.of(
"id", id,
"tarea", tarea,
"mensaje", "Tarea agregada exitosamente"
);
}
}
Para probar esta API:
# Inicia el servidor
jbang TareasAPI.java
# En otra terminal, prueba los endpoints
curl -X POST -H "Content-Type: text/plain" -d "Comprar víveres" http://localhost:8080/tareas
curl http://localhost:8080/tareas
Aplicaciones de Escritorio con JavaFX
JBang también facilita la creación de aplicaciones GUI. Aquí un ejemplo con JavaFX:
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS org.openjfx:javafx-controls:19
//DEPS org.openjfx:javafx-fxml:19
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class AppJavaFX extends Application {
@Override
public void start(Stage stage) {
Button btn = new Button("¡Haz clic!");
btn.setOnAction(e -> System.out.println("¡Botón presionado!"));
VBox root = new VBox(btn);
Scene scene = new Scene(root, 300, 200);
stage.setTitle("Demo JavaFX con JBang");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Catálogos y App Store
Uso de Catálogos
JBang permite crear y compartir catálogos de scripts. Aquí un ejemplo de jbang-catalog.json
:
{
"catalogs": {},
"aliases": {
"http-server": {
"script-ref": "scripts/HttpServer.java",
"description": "Servidor HTTP simple"
},
"backup": {
"script-ref": "scripts/Backup.java",
"description": "Script de respaldo"
}
}
}
Ejemplos de la App Store
Algunos scripts útiles disponibles en la App Store de JBang:
# Servidor HTTP simple
jbang httpd@jbangdev
# Búsqueda en Maven Central
jbang gavsearch@jbangdev spring-boot
# Mensaje divertido con una vaca
jbang cowsay@ricksbrown/cowsay "¡Moo desde JBang!"
Características Avanzadas
Scripts sin Clase Principal
A partir de Java 23, puedes escribir scripts más concisos:
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 23+
//COMPILE_OPTIONS --enable-preview -source 23
//RUNTIME_OPTIONS --enable-preview
void main(String... args) {
System.out.println("¡Hola desde un script moderno!");
}
Soporte para Markdown
JBang puede ejecutar código Java dentro de archivos Markdown:
# Mi Script en Markdown
Este es un documento Markdown con código ejecutable.
```java
System.out.println("¡Ejecutando desde Markdown!");
## Consejos y Mejores Prácticas
1. **Gestión de Versiones de JDK**
```bash
# Listar JDKs instalados
jbang jdk list
# Ver JDKs disponibles
jbang jdk list --available
Exportación de Scripts
# Crear un JAR ejecutable jbang export portable myscript.java # Crear una imagen nativa jbang export native myscript.java
Caché y Rendimiento
# Limpiar caché jbang cache clear # Ignorar caché al ejecutar jbang --fresh myscript.java
JBang para DevOps: Ejemplo Simple
Aquí tienes un ejemplo sencillo pero útil de un script JBang para tareas DevOps básicas:
HealthChecker.java
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.squareup.okhttp3:okhttp:4.12.0
//DEPS info.picocli:picocli:4.7.5
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.util.concurrent.Callable;
@Command(name = "healthcheck",
description = "Verifica el estado de servicios y genera un reporte simple",
version = "healthcheck 1.0")
public class HealthChecker implements Callable<Integer> {
@Option(names = {"-u", "--urls"}, description = "URLs a verificar", required = true, split = ",")
private String[] urls;
@Option(names = {"-t", "--timeout"}, description = "Timeout en segundos", defaultValue = "30")
private int timeout;
private static final OkHttpClient client = new OkHttpClient();
@Override
public Integer call() {
System.out.println("🔍 Iniciando verificación de servicios...\n");
boolean allOk = true;
for (String url : urls) {
try {
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
boolean isHealthy = response.isSuccessful();
String status = isHealthy ? "✅ ACTIVO" : "❌ CAÍDO";
System.out.printf("Servicio: %s\n", url);
System.out.printf("Estado: %s\n", status);
System.out.printf("Código: %d\n", response.code());
System.out.println("------------------------\n");
if (!isHealthy) {
allOk = false;
}
}
} catch (Exception e) {
System.out.printf("Servicio: %s\n", url);
System.out.printf("Estado: ❌ ERROR\n");
System.out.printf("Error: %s\n", e.getMessage());
System.out.println("------------------------\n");
allOk = false;
}
}
if (allOk) {
System.out.println("✨ Todos los servicios están funcionando correctamente");
return 0;
} else {
System.out.println("⚠️ Algunos servicios presentan problemas");
return 1;
}
}
public static void main(String... args) {
int exitCode = new CommandLine(new HealthChecker()).execute(args);
System.exit(exitCode);
}
}
Uso del Script
- Verificar un solo servicio:
jbang HealthChecker.java -u https://jsonplaceholder.typicode.com/
- Verificar múltiples servicios:
jbang HealthChecker.java -u https://servicio1.com/health,https://servicio2.com/health
- Especificar timeout:
jbang HealthChecker.java -u https://api.ejemplo.com/health -t 60
Ejemplo de Salida
🔍 Iniciando verificación de servicios...
Servicio: https://jsonplaceholder.typicode.com/
Estado: ✅ ACTIVO
Código: 200
------------------------
Servicio: https://api.ejemplo.com/health
Estado: ❌ ERROR
Error: connect timed out
------------------------
⚠️ Algunos servicios presentan problemas
Características del Script
Simplicidad: Un solo archivo que hace una tarea específica y útil.
Funcionalidad DevOps común: Verifica el estado de servicios web.
Salida clara: Usa emojis y formato legible para mejor visualización.
Configurable: Permite especificar URLs y timeout.
Códigos de salida: Retorna 0 si todo está bien, 1 si hay problemas.
Ventajas de este Enfoque
Fácil de mantener: Todo el código está en un solo archivo.
Portable: Se puede ejecutar en cualquier lugar con JBang instalado.
Extensible: Fácil de modificar para agregar más funcionalidades.
Práctico: Útil para monitoreo básico y scripts de CI/CD.
Posibles Mejoras
Agregar soporte para autenticación básica
Incluir verificación de certificados SSL
Generar reportes en diferentes formatos
Agregar notificaciones (email, Slack, etc.)
Incluir métricas de tiempo de respuesta
Este ejemplo es ideal para empezar con JBang en DevOps, ya que:
Es fácil de entender y modificar
Resuelve un problema común
Sirve como base para scripts más complejos
Generador de Reportes Docker
El Generador de Reportes Docker es una herramienta desarrollada con JBang que automatiza la creación de informes detallados sobre los contenedores Docker en tu sistema.
Script para generar reportes sobre contenedores Docker:
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.github.docker-java:docker-java:3.3.5
//DEPS com.github.docker-java:docker-java-transport-httpclient5:3.3.5
//DEPS org.apache.commons:commons-csv:1.10.0
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.core.DockerClientBuilder;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import java.io.FileWriter;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
public class DockerReport {
public static void main(String[] args) {
try (DockerClient dockerClient = DockerClientBuilder.getInstance().build()) {
List<Container> containers = dockerClient.listContainersCmd()
.withShowAll(true)
.exec();
String fileName = "docker-report-" +
DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm")
.withZone(ZoneId.systemDefault())
.format(Instant.now()) +
".csv";
try (CSVPrinter csvPrinter = new CSVPrinter(
new FileWriter(fileName),
CSVFormat.DEFAULT.withHeader(
"Container ID",
"Names",
"Image",
"Status",
"State",
"Created",
"Ports"
))) {
for (Container container : containers) {
csvPrinter.printRecord(
container.getId(),
String.join(", ", container.getNames()),
container.getImage(),
container.getStatus(),
container.getState(),
Instant.ofEpochSecond(container.getCreated())
.atZone(ZoneId.systemDefault())
.toString(),
container.getPorts() != null
? container.getPorts().length
: 0
);
}
}
System.out.println("Reporte generado: " + fileName);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}
}
Como funciona:
jbang DockerReport.java
Resultado
Conclusión
JBang representa un cambio significativo en cómo podemos trabajar con Java y otros lenguajes JVM. Ya sea para prototipado rápido, scripts de utilidad o incluso aplicaciones pequeñas, JBang ofrece una experiencia moderna y eficiente que hace que el desarrollo en Java sea más accesible y ágil.
La combinación de gestión de dependencias integrada, soporte multi-lenguaje, y una comunidad activa que comparte scripts a través de la App Store hace de JBang una herramienta indispensable en el arsenal de cualquier desarrollador Java moderno.
Recursos Útiles
Subscribe to my newsletter
Read articles from Rossana Suarez directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Rossana Suarez
Rossana Suarez
Soy Roxs 👩💻| Software Developer | DevOps | DevSecOps | en @295DevOps 🖼 Content Creator. No se puede crecer si no estas dispuesto a saltar a la zona de peligro 🔥