JBang
est une commande ligne permettant de programmer et d’exécuter du code Java
très simplement comme on peut le faire avec du Shell
.
On n’a alors plus besoin de la sacro-saint arborescence src/main/java
ou même d’un fichier pom.xml
puisque toute les informations du projet Java se trouvent contenues dans un ou plusieurs fichiers Java.
J’ai découvert JBang en Mai 2020 et nous verrons dans ce billet les apports principaux de JBang pour le développeur Java ou l’ingénieur qualité, que celui-ci soit novice ou débutant.
1. Installer JBang
1.1 Avec liar
Personnellement j’installe JBang
avec liar
, une commande ligne que j’ai écrite pour installer des archives:
$ liar -l install jbang https://github.com/jbangdev/jbang/releases/download/v0.68.0/jbang-0.68.0.zip
Le flag -l
permet de créer un lien symbolique dans $HOME/bin
afin de disposer de la commande JBang dans le PATH
.
Vous pouvez aussi utiliser la complétion Bash
de liar pour avoir la dernière version de JBang:
$ liar -l install jbang <TAB>
1.2 Avec SDKMan
Si vous utilisez SDKMan
, vous pouvez installer JBang
comme suit:
$ sdk install jbang
1.3 Configurer la complétion Bash
$ jbang completion | sed 's/+o default/-o default/' > jbang
$ sudo cp jbang /etc/bash_completion.d
La modification du script de complétion faites ici avec sed
permet d’éviter un problème dans ce script.
Une fois votre terminal redémarré, vous disposez de JBang
et de la complétion pour Bash
:
$ jbang
jbang is a tool for building and running .java/.jsh scripts and jar packages.
Usage: jbang [-hV] [--verbose | --quiet] [-o | [--fresh]] [COMMAND]
jbang init hello.java [args...]
(to initialize a script)
...
2. Un premier script
Comme évoqué en introduction, JBang
permet de faire des « scripts » en Java
comme on le fait en Shell
ou en Python
.
Voyons comment on commence avec un classique HelloWorld:
$ jbang init --template=hello Hello.java
[jbang] File initialized. You can now run it with 'jbang Hello.java' or edit it using 'jbang edit --open=[editor] Hello.java' where [editor] is your editor or IDE, e.g. 'idea'
Voyons ce que JBang nous a généré:
$ cat Hello.java
///usr/bin/env jbang "$0" "$@" ; exit $?
// //DEPS <dependency1> <dependency2>
import static java.lang.System.*;
public class Hello {
public static void main(String... args) {
out.println("Hello World");
}
}
La première ligne doit vous rappeler les scripts Shell ou Python. C’est un Shebang qui permet de dire au Shell quel programme est en charge de ce fichier.
Vous voyez ensuite une ligne d’exemple pour déclarer les dépendances du programme (pas de fichier pom.xml
).
Finalement vient le code de la classe elle-même, sans nom de package qui ne nous apporterait rien dans un « script ».
2.1 Exécuter le script
Pour exécuter le script, rien de plus simple:
$ ./Hello.java
[jbang] Building jar...
Hello World
On bien:
$ jbang Hello.java
Hello World
Le script était déjà compilé par JBang
, c’est pourquoi la ligne « Building jar » n’est pas apparue la deuxième fois.
On peut aussi utiliser:
$ jbang run Hello.java
La commande run
est facultative mais il est intéressant de savoir que c’est elle qui se lance, en particulier pour connaître les paramètres qu’elle accepte:
$ jbang run --help
Usage: jbang run -o [-hnV] [--[no-]cds] [--ea] [--esa] [--fresh] [--insecure]
[--interactive] [--jsh] --quiet --verbose [-r
[=<flightRecorderString>]] [-d=<debugString>]
[-j=<javaVersion>] [-m=<main>] [--cp=<classpaths>]...
[-D=<String=String>]... [--deps=<dependencies>]...
[--javaagent=<String=Optional>]... <scriptOrFile>
[<userParams>...]
On peut par exemple spécifier la version de Java à utiliser, des propriétés systèmes, le fait d’utiliser le Java Flight Recorder
ou encore activer le mode verbeux de JBang.
2.2 Ajouter des paramètres
Si vous avez regardé attentivement le Shebang généré par JBang
ou les paramètres possibles de la commande run, vous aurez compris qu’on peut passer des paramètres à notre script.
Changeons dans notre fichier source la ligne de code du main
:
out.println("Hello World: " + Arrays.deepToString(args));
Et exécutons le avec des paramètres:
$ ./Hello.java i use jbang
[jbang] Building jar...
Hello World: [i, use, jbang]
2.3 Editer le script avec IDEA
Pour modifier le script, on ne va pas le faire avec vi
. Je n’ai rien contre vi mais pour du Java on peut faire autrement !
On va dire à JBang
que l’on souhaiter éditer notre script avec IDEA
:
$ jbang edit --open=idea Hello.java
[jbang] Running `sh -c idea /home/pyfourmond/.jbang/cache/projects/Hello.java_jbang_3ffb56a92041a06bde360de31f0251136fcb1e61a9e3fd412a3fd1b8ff833715/Hello`
/home/pyfourmond/.jbang/cache/projects/Hello.java_jbang_3ffb56a92041a06bde360de31f0251136fcb1e61a9e3fd412a3fd1b8ff833715/Hello
JBang va alors générer un projet IDEA, Gradle
ou Maven
, permettant d’éditer notre fichier avec toutes les dépendances résolues (dans cette exemple simple, nous n’en avons pas) et nous pourrons le modifier en bénéficiant de la coloration syntaxique, la complétion, la compilation automatique, etc …
Si vous n’utilisez pas IDEA, sachez que JBang supporte aussi Visual Studio Code
, Eclipse
, Netbeans
…
3. Une autre version de Java
Par défaut, JBang
utilise la version de Java disponible dans votre environnement, i.e. votre PATH
.
Mais il permet aussi d’utiliser une version précise de Java ou une version minimale, par exemple en ajoutant en début de script:
//JAVA 14+
JBang va alors s’occuper de télécharger le JDK
requis pour vous et l’utiliser pour l’exécution de ce script:
$ ./Hello.java i learn jbang
[jbang] Downloading JDK 14. Be patient, this can take several minutes...
[jbang] Installing JDK 14...
De la même façon on peut préciser les options de java
ou de javac
comme suit:
//JAVAC_OPTIONS --enable-preview -source 14 (1)
//JAVA_OPTIONS --enable-preview // (2)
Ce qui permet notamment d’utiliser les « features » Java qui sont encore en « preview » dans le JDK utilisé.
PS: Attention à ne pas mettre d’espace après les deux slashs, sinon JBang prendra la ligne pour un commentaire.
4. Déclarer les dépendances
Pour déclarer les dépendances dans un script JBang
, on utilise la syntaxe suivante:
//DEPS groupId:artifactId:version
par exemple, pour Picocli:
//DEPS info.picocli:picocli:4.5.0
puisque JBang se passe de fichier pom.xml
.
4.1 Chercher les dépendances
Pour trouver le groupId
, artifactId
et la version
d’une dépendance pour JBang
, il est possible d’utiliser le script gavsearch
disponible dans le catalogue jbangdev:
$ jbang gavsearch@jbangdev -q -f jbang picocli
Searching for `picocli` on search.maven.org...
[jbang]
//DEPS info.picocli:picocli:4.6.1
...
5. Utiliser plusieurs fichiers source
JBang
a été initialement écrit pour exécuter un fichier Java
, que son extension soit .java
ou pas.
Comme un seul fichier contenant plusieurs classes internes peut rapidement devenir important et difficile à gérer, on peut maintenant utiliser plusieurs fichiers sources Java dans un même script JBang:
Par exemple le script suivant GitGet hérite d’une classe abstraite AbstractGit et on le précise à JBang avec la syntaxe //SOURCES
:
$ more GitGet.java
///usr/bin/env jbang "$0" "$@" ; exit $?
...
//DEPS info.picocli:picocli:4.5.0
...
//SOURCES AbstractGit.java
...
@Command(name = "GitGet", mixinStandardHelpOptions = true, version = "GitGet 0.1", description = "A command to get one o
r more files (or directories) from a Git repository")
class GitGet extends AbstractGit {
Le script GitGet
s’exécute alors comme un script JBang normal et JBang va se charger de résoudre les fichiers référencés par la directive //SOURCES
.
6. Utiliser les alias et les catalogues
Dans l’exemple du paragraphe 4.1, on a utilisé sans le savoir les notions d’alias et de catalogue !
Dans la commande:
$ jbang gavsearch@jbangdev
On a utilisé l’alias
gavsearch du catalogue
jbangdev.
Un catalogue est un ensemble de scripts JBang.
Pour en voir le contenu:
$ jbang catalog list jbangdev
Aliases:
--------
bouncinglogo@jbangdev = https://github.com/jbangdev/jbang-catalog/blob/HEAD/bouncinglogo.java
env@jbangdev = Dump table of Environment Variables
gavsearch@jbangdev = Search search.maven.org for maven artifacts.
...
Les scripts contenus dans le catalogue sont décrits dans le fichier https://github.com/jbangdev/jbang-catalog/blob/master/jbang-catalog.json.
Dans cet exemple, le catalogue est distant mais vous pouvez aussi définir des catalogues locaux qui référencent des scripts présents sur votre machine.
On peut faire beaucoup de choses avec les alias et les catalogues, n’hésitez pas à lire la documentation.
7. Conclusion
JBang
est un outil formidable pour le développeur Java, très orienté pour les projets de petite taille, d’où la notion de « script » souvent utilisée.
Le projet est très actif comme son créateur Max Rydahl Andersen, les releases sont régulières et de nouvelles fonctionnalités sont ajoutées chaque mois.
La possibilité de générer très simplement une image native d’une application avec GraalVM
, non décrite dans ce billet, est particulièrement intéressante.
Néanmoins, certaines choses peuvent manquer comme par exemple la possibilité d’éditer un catalogue, celle d’éditer les scripts comportant plusieurs sources (//SOURCES
) ou encore d’accéder aux catalogues privés via SSH.
En outre, l’édition des fichiers dans un répertoire autre que celui d’origine interdit l’utilisation de Git
dans le répertoire d’édition.
Cela dit, le développeur Java en 2021 doit absolument tester et utiliser JBang, ne serait-ce que pour appréhender les nouveautés du JDK ou tester très rapidement les possibilités d’une API qu’il envisage d’utiliser prochainement dans un projet ou un produit.