Oracle fait évoluer Java dans son Coin

Il y a quelques temps, j'évoquai dans un article les évolutions à venir de Java 7 concernant le cloud computing.

D'un point de vue plus terre-à-terre, le projet Coin a pour but d'apporter quelques améliorations au JDK actuel. Certaines ont d'ores-et-déjà commencé à être implémentées dans Netbeans 7 béta et Eclipse 3.7 (à venir dans l'année). Le but ici n'est pas de révolutionner le langage mais de lui apporter quelques touches plus "fraîches" dans l'optique de le rendre toujours plus agréable à lire et utiliser. Petit tour d'horizon

Underscores dans les literals

L'intention ici est de simplement rendre le code plus lisible par l'ajout d'underscores dans les entiers par exemple ou les expressions hexadécimales. Exemples :

// Ecriture classique
int i = 1234567890;
// Avec Coin
int i = 1_234_567_890;
// Ou encore
String hexRed = 0xFFCC99;
// Avec Coin
String hexRed = 0xFF_CC_99;

Utilisation des String dans les switch

Encore maintenant, les switch ne sont utilisables qu'avec des types primitifs. L'intérêt est donc d'étendre leur utilisation pour éclaircir et améliorer les performances de certains extraits :

// Avec Java actuel
int monthNameToDays(String s, int year) {
if(s.equals("April") ||
s.equals("June") ||
s.equals("September") ||
s.equals("November"))
return 30;
if(s.equals("January") ||
s.equals("March") ||
s.equals("May") ||
s.equals("July") ||
s.equals("August") ||
s.equals("December"))
return 31;
if(s.equals("February"))
...
else
...
}
}
// Deviendra donc avec Coin
int monthNameToDays(String s, int year) {
switch(s) {
case "April":
case "June":
case "September":
case "November":
return 30;
case "January":
case "March":
case "May":
case "July":
case "August":
case "December":
return 31;
case "February":
...
default
...
}
}

Litéraux pour les collections

L'instanciation de collections est parfois fastidieuse lorsqu'il s'agit par exemple de créer une variable statique dans une classe. Le projet Coin propose donc une nouvelle utilisation :

List<List<String>> monthsInTwoLanguages =
{{"January", "February"},{"Gennaio", "Febbraio"}};

L'opérateur "Diamand"

Le but ici est de simplifier l'écriture des generics, parfois gourmande en caractères :

// Une variable "longiligne" du type :
List<List<List<List<String>>>> list =
new ArrayList<List<List<List<String>>>>();
// Deviendra
List<List<List<List<String>>>> list = new ArrayList<>();

Multi-catch

De la même façon, l'écriture de blocs try-catch peut parfois s'avérer lourde si l'on veut maintenir une bonne gestion des erreurs. Voici donc l'amélioration proposée :

// Un code classique
try {
// Reflective operations calling Class.forName,
// Class.newInstance, Class.getMethod,
// Method.invoke, etc.
} catch(ClassNotFoundException cnfe) {
log(cnfe);
throw cnfe;
} catch(InstantiationException ie) {
log(ie);
throw ie;
} catch(NoSuchMethodException nsme) {
log(nsme);
throw nsme;
} catch(InvocationTargetException ite) {
log(ite);
throw ite;
}
// Pourra s'alléger comme ceci
try {
// Reflective operations calling Class.forName,
// Class.newInstance, Class.getMethod,
// Method.invoke, etc.
} catch(ClassNotFoundException |
InstantiationException |
NoSuchMethodException |
InvocationTargetException e) {
log(e);
throw e;
}

Tout ceci n'est bien sûr qu'un aperçu de ce qui est évoqué dans le projet Coin, lui-même encore à l'état de proposition, mais on peut voir que bien des choses prometteuses sont à venir pour faciliter encore et toujours l'utilisation de Java!

Sources :


Fichier(s) joint(s) :

Du nouveau pour Scala avec Eclipse

Une fois n'est pas coutume, je publie ce simple billet dans le seul but d'informer sur la sortie d'un nouvel IDE destiné aux développements Scala sous Eclipse : Scala IDE for Eclipse.

Dans un précédent article, j'avais fait un comparatif des différents éditeurs actuellement disponibles pour Scala, en soulignant que sur ce point Eclipse avait pris du retard vis-à-vis de Netbeans.

On pourra donc remarquer, une nouvelle fois, l'effort produit par les développeurs afin de maintenir au goût du jour leur éditeur dans la course au support des langages en vogue.

Même si, après quelques tests, ce nouveau plugin n'offre pas encore beaucoup d'améliorations (pas de complétion, refactor inactif...), il faut cependant remarquer sa meilleure stabilité dans l'environnement et une compilation bien plus efficace.

Affaire à suivre donc!


Fichier(s) joint(s) :



JSF : rafraichir une page après un téléchargement

Imaginons une action disponible dans une application web, qui, dans un premier temps, modifie l'état d'objets sur le serveur et dans un second temps propose un fichier en téléchargement. Il faut donc qu'à la fin du téléchargement, la page courante soit rafraîchie pour voir les nouveaux états des objets...

Dans l'absolu, ceci est impossible en une seule action, puisque le protocole HTTP lui-même est basé sur un principe de requête-réponse unique. Il faudrait donc lancer deux requêtes successives, respectivement pour télécharger le fichier et rafraîchir ensuite la page.

Mais il est cependant possible de contourner ce problème en utilisant les headers HTTP : c'est ainsi le navigateur qui, à leur réception, prendra l'initiative de rafraîchir la page courante. Voici la méthode qui permet de faire ceci :

 public static void downloadFile(File toDL, String newName, boolean refreshAfterDownload) throws IOException {
  byte[] bbuf = new byte[1024];
  int length = 0;
  FileInputStream in = new FileInputStream(toDL);
  FacesContext context = FacesContext.getCurrentInstance();
  HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
  response.setContentType(determineContentType(toDL));
  response.setContentLength(in.available());
  response.setHeader("Content-Disposition", "attachment; filename=\"" + newName + "\"");
  if (refreshAfterDownload) {
   response.addHeader("refresh", "0.1");
  }
  ServletOutputStream sop = response.getOutputStream();
  while ((in != null) && ((length = in.read(bbuf)) != -1)) {
   sop.write(bbuf, 0, length);
  }
  in.close();
  sop.flush();
  context.responseComplete();
 }

Comme on peut le voir, c'est le header "Refresh" qui permettra d'indiquer au navigateur que la page doit être rafraîchie après réception du fichier.

Note :

Il est possible de spécifier au header Refresh, en plus du temps avant rafraîchissement, l'url vers laquelle se rediriger :

response.addHeader("refresh", "0.1;url="+newURL);

Cependant cela peut poser certains problèmes. J'ai en effet pu remarquer un comportement non expliqué sous certains navigateurs : avec Firefox par exemple, lorsque le fichier est proposé en téléchargement, si l'utilisateur choisi l'option "Ouvrir le fichier", tout se déroulera correctement, alors que s'il choisi l'option "Enregistrer", le navigateur semble perdre le FacesContext courant et n'arrive pas à accéder à la page indiquée... De la même façon, si l'utilisateur annule le téléchargement, la page ne sera pas actualisée.

Je n'ai pas assez approfondi mes recherches quant à la configuration du FacesContext ou au comportement du navigateur selon les cas, mais toute aide sera la bienvenue!


Fichier(s) joint(s) :



Quand les IDEs deviendront plus intelligents que nous...

Under the right circumstances, groups are remarkably intelligent and are often better than the smartest person in them.
– James Surowiecki: Wisdom of the Crowds

Les équipes de la fondation Eclipse se sont lancées dans un nouveau projet des plus ambitieux : comment rendre les IDEs plus "intelligents"?

Au début de cette réflexion, vient l'analogie avec le web lui-même. Qu'est-ce qui l'a rendu plus "intelligent" ces dernières années? L'aspect communautaire, collaboratif, l'interconnexion des données, l'apprentissage des usages... En somme, le web 2.0. Ainsi viennent de naitre les IDE 2.0!

Pour commencer, un graphique qui permet de résumer l'essentiel de cette idée :

Le but est donc de centraliser les informations sur les usages courants des utilisateurs au sein des IDEs afin d'améliorer leur analyse du code en cours d'écriture. C'est un apport considérable en termes d'aide au développement, tous points confondus :

Recommandations de code

Lors de l'utilisation de l'auto-completion, il est souvent ennuyeux de voir apparaître une liste barbante exhaustive de TOUTES les méthodes disponibles sur l'objet (provenant de l'héritage, du framework...). La fonctionnalité de recommandation de code va permettre de n'afficher, dans un premier temps, qu'un ensemble de méthodes pertinentes, selon le contexte courant et l'usage qu'en ont fait d'autres développeurs dans le même contexte :

Moteurs de templates intelligents

Poussons cette première idée encore plus loin : pourquoi simplement s'arrêter à la suggestion de méthodes quant il même possible de présenter des blocs de codes entiers couramment utilisés et répondant aux mêmes contraintes de contexte? C'est également possible avec ce nouveau système de templates, inférant l'usage le plus judicieux compte tenu du code déjà en place :

JavaDoc étendue

Tout le monde s'accordera sur le fait qu'il est assez fastidieux de rédiger la JavaDoc correspondante au code mis en place... Quand elle existe, elle est parfois peut détaillée ou peu explicite. De plus, dans le cas de la surcharge simple d'objets d'un framework, elle peut s'avérer peu pertinente. Alors plutôt que de ne s'appuyer que sur ce que les utilisateurs saisissent explicitement, pourquoi ne pas se baser directement sur leurs usages du code pour fournir une doc plus pertinente? C'est ce que fait cette nouvelle JavaDoc étendue :

Détection de bug intelligente

Dans le même principe que pour la JavaDoc, il est envisageable que l'IDE propose un ensemble de solutions à certains problèmes grâce à une analyse du code basée sur la recherche de différences avec des blocs de codes couramment utilisés (appels de méthodes manquants, manipulations d'objets incongrues...) :

Et ce, à l'exécution ou durant le développement :

Recherche de code intégrée

Certains sites comme Google Code Search ou Koders mettent en ligne des extraits de code dans le but de faciliter les recherches lorsqu'il s'agit de trouver, par exemple, comment accéder à certains objets d'un framework lors d'un développement spécifique. Leur principal inconvénient est justement de ne pas être intégrés aux IDEs. Problème une nouvelle fois résolu avec cette nouvelle fonctionnalité :

Recherche de piles d'erreurs

Dans la même lignée que la fonctionnalité précédente, il pourrait être intéressant de disposer d'un référentiel de piles d'exceptions qui permettrait, grâce à une recherche à partir d'une trace, de trouver un ensemble d'extraits de code ayant permis de la résoudre. Voici par exemple l'idée soulevée :

En résumé

Comme vous pouvez le constater, ce nouveau projet de la fondation Eclipse, "Eclipse Code Recommenders", fourmille d'idées ingénieuses et révolutionnaires qui vont à coup sûr modifier notre vision actuelle du développement : il ne s'agira plus de coder tout seul dans son coin et, dans le meilleur des cas, de publier ses solutions au sein de communautés, mais ce seront les usages de ces communautés qui permettront à chacun d'améliorer son travail... Que de perspectives intéressantes!

Sources :


Fichier(s) joint(s) :



Créer son propre IDE avec l'API de compilation Java

Depuis Java 6, il est possible de générer à la volée des classes et de les compiler. En effet, le package javax.tools donne accès à toute la panoplie nécessaire pour créer dynamiquement des classes à partir de simples String contenant le code : JavaCompiler qui est une implémentation du compilateur lui-même, JavaFileObject représentant de manière abstraite les fichiers (.java) et DiagnosticListener qui récupère en sortie toutes les informations de la compilation (erreurs, lignes, messages...).

Il est même possible de compiler (et exécuter) des classes virtuellement, uniquement en mémoire, sans avoir à physiquement créer les fichiers sources ou les fichiers compilés.

Pour tester et illustrer ceci, j'ai créé un petit projet d'IDE (sous Netbeans), qui permet de taper du code source Java qui sera introduit dans la méthode "main" d'une classe, puis compilé et exécuté (en mémoire ou physiquement). Les résultats de l'exécution (sorties standards ou erreurs de compilation) sont redirigés vers une "console" créée pour l'occasion.

Voici quelques captures :

Comme on peut le voir, il est tout à fait possible d'exécuter n'importe quel code... J'ai ici implémenté le choix entre l'exécution du code à partir d'une classe compilée sur le disque à partir du fichier .java ou en mémoire. La "console" (en réalité un simple JTextArea) récupère n'importe quelle sortie faite par System.out.println

On peut voir, à l'arrière-plan, la classe compilée (ici en dur DynamicCompilation) crée au sein du projet (destination elle-même pour l'exemple en dur).

Bien sûr cet exemple n'est qu'une ébauche de ce qui est faisable avec un IDE, mais cela laisse entrevoir les possibilités et permet de comprendre un peu plus le fonctionnement de nos outils quotidiens!

J'ai joint à cet article les sources de mon projet afin que vous puissiez les parcourir rapidement, mais je vous conseille d'aller consulter en détails les liens d'où je tire ces exemples. Bon courage!

Sources :


Fichier(s) joint(s) :