Il y a 8 ans -
Temps de lecture 9 minutes
Tester le REPL du futur JDK9 avant sa sortie
Java 9 est prévu pour septembre 2016 mais il est possible de l’essayer à l’avance grâce au programme early access release. Aujourd’hui, nous allons tester une fonctionnalité que quasiment tous les langages proposent : jshell, le REPL pour Java (Read Eval Print Loop). Issue de la JEP 222 jshell, le projet kulla a pour objectif d’intégrer un REPL dans la première version du JDK 9.
L’article a été rédigé pour être suivi sur OS X ou Linux/Unix.
La spec
La JEP 222 a pour objectif d’offrir un outil interactif pour évaluer des instructions Java (déclarations, assertions, expressions, etc.) sans avoir besoin de créer et compiler une classe. Le jshell conserve un historique de chaque instruction exécutée. Il offre aussi quelques fonctionnalités simplifiant l’écriture de snippets comme la completion, la gestion des imports ou bien l’ajout automatique des points virgules en fin de ligne.
Enfin, il est possible d’exécuter des commandes permettant d’enregistrer et donc récupérer des snippets de code (entre autres). Ces commandes sont préfixées par le caractère slash.
Installation
Disclaimer : le projet étant en constante évolution, il se peut que l’installation soit différente d’une version à l’autre. C’est d’ailleurs ce qui se passe entre la version du tutorial d’Arun Gupta et celle présentée ci dessous : vous n’êtes plus obligé d’intégrer jline2 car il a été intégré a kulla.
Nous allons d’abord installer le JDK 9. Pour cela, télécharger et installer la version qui correspond à votre environnement puis vérifier l’installation :
[bash]$ java -version
java version "1.9.0-ea"
Java(TM) SE Runtime Environment (build 1.9.0-ea-b68)
Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b68, mixed mode)[/bash]
L’installation du REPL se fait à partir des sources du projet car il n’est pas encore intégrer au JDK (mercurial doit être installé sur votre machine) :
[bash]$ hg clone http://hg.openjdk.java.net/kulla/dev kulla[/bash]
Ensuite, il faut exécuter un script permettant de télécharger toutes les ressources nécessaires à la compilation et l’exécution du REPL :
[bash]$ cd kulla
$ chmod +x ./get_source.sh
$ ./get_source.sh[/bash]
Maintenant, nous allons modifier le fichier de compilation puis l’exécuter :
[bash]$ cd langtools/repl
$ vi scripts/compile.sh[/bash]
Modifions la première ligne #!/usr/bin/sh par une valeur qui correspond à notre environnement. Pour mon cas, j’utilise Mac OS X donc j’ai utilisé la valeur #!/bin/sh. Puis, lançons la compilation du projet de la sorte :
[bash]$ chmod +x ./scripts/compile.sh
$ ./scripts/compile.sh[/bash]
Attention : il est important de se placer dans le répertoire langtools/repl car le script compile.sh l’utilise comme base pour pointer vers d’autres répertoires. Ce sera d’ailleurs notre répertoire de travail pour la suite de l’article.
Modifions aussi le fichier ./scripts/run.sh puis lançons le REPL :
[bash]$ chmod +x ./scripts/run.sh
$ ./scripts/run.sh
| Welcome to JShell — Version 0.610
| Type /help for help
-> System.out.println("Installation terminée :-)");
Installation terminée :-)[/bash]
Voilà, l’installation est terminée, nous pouvons maintenant tester des morceaux de code simplement sans avoir à créer un nouveau projet avec une classe contenant une méthode main. Je vous propose maintenant de voir ce que nous pouvons faire avec le REPL.
Fonctionnalités
Plus besoin de créer une classe avec une méthode main, la compiler puis l’exécuter pour tester un bout de code ou une API. Jshell est fait pour ça !
Une fois démarré, vous pourrez commencer à jouer avec :
[bash]$ ./scripts/run.sh
| Welcome to JShell — Version 0.610
| Type /help for help
-> [/bash]
Vous pouvez aussi utiliser quelques raccourcis clavier pour vous faciliter le travail comme TAB pour la completion, CTRL+a (ou e) pour aller au début (à la fin) de la ligne, les flèches UP and DOWN pour naviguer dans les exécutions précédentes, CTRL+r pour rechercher une ancienne commande, etc.
Il est possible de faire deux types d’actions : exécuter des snippets de code ou une commande pour gérer vos snippets.
Snippets
Vous pouvez :
- exécuter des instructions :
[bash]-> System.out.println("Installation terminée :-)");
Installation terminée :-)[/bash]
- exécuter des opérations :
[bash]-> 2 + 2
| Expression value is: 4
| assigned to temporary variable $1 of type int[/bash]
- créer des variables :
[bash]-> String firstname = "Pierre-Jean"
| Added variable firstname of type String with initial value "Pierre-Jean"[/bash]
- créer des méthodes et les exécuter :
[bash]-> int add(int a, int b) {
>> return a + b;
>> }
| Added method add(int,int)
-> add(2,3)
| Expression value is: 5
| assigned to temporary variable $2 of type int[/bash]
- créer et utiliser des classes :
[bash]-> class Car {
>> private final String name;
>>
>> public Car(String name) {
>> this.name = name;
>> }
>>
>> public void klaxon() {
>> System.out.println("Tutut");
>> }
>> }
| Added class Car
-> Car vroum = new Car("Coccinelle")
| Added variable vroum of type Car with initial value Car@42f30e0a
-> vroum.klaxon()
Tutut[/bash]
Commandes
Les commandes permettent de gérer vos snippets de code comme par exemple lister les derniers snippets exécutés ou bien sauvegarder une suite de snippets. Voici une liste des commandes que vous pouvez exécuter :
[bash]-> /help
Type a Java language expression, statement, or declaration.
Or type one of the following commands:
/l or /list [all] — list the source you have typed
/seteditor <executable> — set the external editor command to use
/e or /edit <name or id> — edit a source entry referenced by name or id
/d or /drop <name or id> — delete a source entry referenced by name or id
/s or /save [all|history] <file> — save the source you have typed
/o or /open <file> — open a file as source input
/v or /vars — list the declared variables and their values
/m or /methods — list the declared methods and their signatures
/c or /classes — list the declared classes
/x or /exit — exit the REPL
/r or /reset — reset everything in the REPL
/f or /feedback <level> — feedback information: off, concise, normal, verbose, default, or ?
/p or /prompt — toggle display of a prompt
/cp or /classpath <path> — add a path to the classpath
/h or /history — history of what you have typed
/setstart <file> — read file and set as the new start-up definitions
/savestart <file> — save the default start-up definitions to the file
/? or /help — this help message
/! — re-run last snippet
/n — re-run n-th snippet
/-n — re-run n-th previous snippet
Supported shortcuts include:
<tab> — show possible completions for the current text
Shift-<tab> — for current method or constructor invocation, show a synopsis of the method/constructor
->[/bash]
Chaque commande débute par le caractère slash ‘/’ et existe en deux versions : une courte où le slash est suivi d’une lettre (généralement la première lettre de la version longue) et une longue qui contient le nom complet de la commande. Ici, j’ai exécuté la commande /help (version longue) mais j’aurais aussi pu exécuter /h.
Parmi les commandes les plus intéressantes, il est possible de :
- lister les variables (/vars), méthodes (/methods) ou classes (/classes) que vous avez créées,
- lister les snippets exécutés grâce à la commande /list (faites la commande /list all et vous verrez un résultat surprenant – qui ne l’est en fait pas), /history pour lister snippets et commandes écrits,
- gérer des ensembles de snippets de code en les enregistrant, modifiant ou les supprimant :
[bash]$ ./scripts/run.sh
| Welcome to JShell — Version 0.610
| Type /help for help
-> /classpath /Users/username/.m2/repository/junit/junit/4.12/junit-4.12.jar
| Path /Users/username/.m2/repository/junit/junit/4.12/junit-4.12.jar added to classpath
-> import static org.junit.Assert.assertTrue
-> void true_should_be_true() {
>> assertTrue(false);
>> }
| Added method true_should_be_true()
-> /save all test_import_junit
-> true_should_be_true()
| java.lang.AssertionError thrown
| at Assert.fail (Assert.java:86)
| at Assert.assertTrue (Assert.java:41)
| at Assert.assertTrue (Assert.java:52)
| at true_should_be_true (#9:2)
| at (#13:1)
-> /x[/bash]
Dans ce snippet de code, nous avons :
- ajouté la librairie junit au classpath,
- importé la classe Assert.java de junit,
- créé une méthode faisant appel à la classe importée,
- sauvegardé notre séquence de snippets (attention, les commandes ne sont pas sauvegardées !),
- exécuté la méthode (qui échoue),
- quitté le REPL.
[bash]$ ./scripts/run.sh
| Welcome to JShell — Version 0.610
| Type /help for help
-> true_should_be_true()
| Error:
| cannot find symbol
| symbol: method true_should_be_true()
| true_should_be_true()
| ^—————–^
-> /classpath /Users/username/.m2/repository/junit/junit/4.12/junit-4.12.jar
| Path /Users/username/.m2/repository/junit/junit/4.12/junit-4.12.jar added to classpath
-> /open test_import_junit
-> true_should_be_true()
| java.lang.AssertionError thrown
| at Assert.fail (Assert.java:86)
| at Assert.assertTrue (Assert.java:41)
| at Assert.assertTrue (Assert.java:52)
| at true_should_be_true (#9:2)
| at (#13:1)
-> /edit true_should_be_true
| Modified method true_should_be_true()
-> true_should_be_true()[/bash]
Dans ce snippet de code, nous avons :
- validé qu’aucun état n’est sauvegardé par le REPL sauf en utilisant la commande /save (cf. point 3 ci-dessus),
- ajouté la librairie junit au classpath (car les commandes ne sont pas sauvegardées par la commande /save),
- chargé le snippet de code sauvegardé précédemment,
- exécuté la méthode (qui échoue toujours),
- modifié cette méthode (ici, deux possibilités s’offrent à nous : utiliser la commande /edit qui ouvre un outil graphique pour modifier la méthode – ne pas oublier d’accepter les changements avant de quitter l’outil – ou recréer la méthode qui modifiera l’existante),
- ré-exécuté la méthode (qui passe).
Vous trouverez un peu plus d’exemples dans le tutorial suivant : https://java.net/downloads/adoptopenjdk/REPL_Tutorial.pdf.
Maintenant, à vous de jouer
Commentaire