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) :



Ajouter un hook à la fermeture de la JVM

Certaines applications, sous la forme de clients lourds, posent parfois le problème de la gestion de leur fermeture par l'utilisateur. En effet, lorsqu'elles communiquent avec un serveur, il peut s'avérer indispensable de savoir quand l'utilisateur quitte son application afin par exemple de le déconnecter et terminer la session côté serveur. Ou tout simplement de sauvegarder l'état courant de l'application afin de le restaurer plus tard (comme le workspace Eclipse!). Mais il existe plusieurs possibilités pour fermer une application de ce genre : le bouton de l'interface système (la croix windows par ex), ou les touches Ctrl+C lors d'un lancement en ligne de commande...

Afin d'être certain d'intervenir au bon moment, il est possible d'ajouter un "shutdown hook" à la JVM : il sera exécuté juste avant sa fermeture, après qu'elle ait elle-même terminé toutes ses opérations. Pour ne pas plagier ou paraphraser un article existant, voici un lien vers celui que j'ai récemment utilisé, très clair et concis.

Un point important à noter tout de même : comme indiqué dans les commentaires de l'article cité, il est possible d'ajouter plusieurs hooks à la fermeture de la JVM, mais chacun d'eux est considéré comme un Thread indépedant et ils sont donc tous lancés en même temps. Attention donc aux effets de bords entre les actions!

Hope this helps!


Fichier(s) joint(s) :

Design patterns utilisés dans le JDK

Pour faire suite à mon précédent article sur les design patterns, j'ai trouvé intéressant, dans un souci de "culture générale", de publier un simple lien vers une liste quasi-exhaustive des différents patterns utilisé au sein-même du JDK, ainsi que leurs rôles. Bonne lecture!


Fichier(s) joint(s) :

Obtenir un graphique de dépendances Maven

Il arrive assez souvent d'avoir besoin de savoir quelle version de librairie est liée à quelle dépendance, afin par exemple de résoudre des conflits de versions... Pour ceci, il est nécessaire d'établir un arbre des dépendances du ou des projets en question. Voici trois méthodes qui devraient subvenir à tous les besoins :

La première et la plus simple tout d'abord. Maven fournit la possibilité d'afficher dans console tous les liens entres les librairies, par projets. Pour ce faire, rendez-vous à cette adresse pour configurer le POM du projet principal. Il ne reste ensuite plus qu'à lancer la ligne de commande : mvn dependency:tree pour afficher quelque chose du genre :

Ceci peut être utile pour avoir accès rapidement à certaines informations, mais il faut avouer que ce n'est pas très lisible... Qui plus est, ce bloc de dépendances est généré uniquement par projet, difficile donc de faire des croisements dans le cas des projets multi-modules (reactors).

Il est alors possible d'obtenir une version plus graphique et élégante des dépendances grâce au plugin Eclipse pour Maven m2Eclipse fournit par la société Sonatype (éditrice de Maven). La dernière version est devenue très stable et permet de combler les précédentes lacunes d'Eclipse vis-à-vis de Netbeans concernant l'intégration de Maven. Entre autres choses, il est aisé de générer des graphes du style :

Beaucoup plus intéressant! Mais là encore une fois, une limitation importante est l'impossibilité de créer un graphique inter-modules...

Note : L'update site indiqué sur le site officiel de m2eclipse pour son installation ne fonctionne que pour des version de l'IDE supérieures ou égales à Ganymede (3.5), comme l'indique le bug ouvert ici.

Pour finalement arriver à nos fins, il faut utiliser le plugin Maven "Maven Graph Plugin". Il est utilisable sous deux modes, dont "reactor", qui permettra de lancer la création de l'arbre depuis un POM parent contenant plusieurs modules :

Voici donc un panel d'outils qui vous permettra de créer des graphiques très pratiques et rapidement exploitables de vos dépendances.


Fichier(s) joint(s) :