JavaFX est sorti hier et ce sera sans aucun doute le buzz de la prochaine semaine. Si j'avoue jusque là ne pas avoir eu vraiment le temps de me pencher sur ce Framework RIA, concurrent de Flex et Silverlight, j'ai décidé aujourd'hui de soulever le capot de JavaFX.
Avec le temps j'ai appris à lire dans le code source des Framework de présentation, que ce soit AWT, Swing, Silverlight, Flex, GWT, Windows Forms ou WPF, toutes ces API ont bien souvent en commun de nombreuses briques techniques, à savoir :
Suite:
- Un modèle de composant (une "super" classe composant : JComponent en Swing, Component en AWT, Control en Silverlight/WPF, UIComponent en Flex, Widget en GWT) sur lequel viennent se greffer des sous-classes représentant les widgets.
- Des layouts : les gestionnaires de placement permettent de placer les contrôles avec une politique de placement spécifique.
- Medias : pour la vidéo et l'audio, les flux multi-media de toutes sortes
- Animations : pour les transitions et la gestion de la timeline (si chère aux graphistes et souvent oublié par les développeurs)
- Un moteur de rendu (bitmap ou vectoriel)
- Un runtime : les éléments constituant la JVM
J'ai donc décompilé les classes de JavaFX contenues dans le fichier javafx-rt.jar (je n'ai pas réussi à faire un checkout des sources via un SVN anonyme). Le schéma précédent en est le résultat. Concrètement, on peut s'apercevoir que JavaFX "n'est rien de plus" qu'un n-ième Framework graphique Java. On a bien affaire ici à une API Java (dans tous les cas compatible avec du byte code Java) comme le montre la copie d'écran suivante sous l'outil JD-GUI d'Emmanuel Dupuy.
Pourquoi dans ce cas Sun ne s'est-il pas appuyé sur les API existantes (Swing) ?
En pratique, JavaFX est ce qu'on pourait appeler un sous-ensemble des API du JDK. Swing est essentiellement un modèle orienté bitmap. Là où Flex et Silverlight tirent partie du Vectoriel, il aurait été difficile pour Sun de concurrencer ces deux Framework sans apport technique supplémentaire. Par ailleurs, Swing n'est pas vraiment adapté aux environnements médias mixant audio, vidéo et timeline. JavaFX reprend donc certains composants de Swing (dans le package javafx.ext.swing) et les enrichit pour les adapter à la sauce JavaFX.
En revanche, on sent vraiment qu'il y a dans le fond un vrai problème de Design à vouloir prendre le meilleur de chaque monde. Prenons par exemple le JTextfield. Cette classe dérive du JTextField de Swing (qui rappelons le, utilise du painting bitmap, donc non vectoriel) et le combine ensuite avec le gestionnaire de scène (j'y reviens plus loin) pour construire le background du composant. Regardez la méthode paintComponent(), elle mixe plusieurs framework (Swing + AWT + JavaFX) bitmap et vectoriel conçus à l'origine pour des besoins différents. On a là un vrai souci de Design.
package javafx.ext.swing;
import com.sun.javafx.scene.BackgroundSupport;
import com.sun.javafx.scene.BackgroundSupport.BackgroundSupportable;
import java.awt.Graphics;
import java.awt.Paint;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class JTextFieldImpl extends JTextField
implements BackgroundSupport.BackgroundSupportable
{
private boolean borderless = false;
private BackgroundSupport bgs;
public JTextFieldImpl()
{
this.bgs = new BackgroundSupport(this);
}
public void setBorderless(boolean paramBoolean)
{
this.borderless = paramBoolean;
if (paramBoolean)
setBorder(new EmptyBorder(0, 0, 0, 0));
else
setBorder(new JTextField().getBorder());
}
public boolean isBorderless()
{
return this.borderless;
}
public void setBackgroundPaint(Paint paramPaint)
{
this.bgs.setBackgroundPaint(paramPaint);
}
public Paint getBackgroundPaint()
{
return this.bgs.getBackgroundPaint();
}
public void setColumns(int paramInt)
{
int i = getColumns();
super.setColumns(paramInt);
firePropertyChange("columns", i, getColumns());
}
public void paintComponent(Graphics paramGraphics)
{
this.bgs.paintBackground(paramGraphics);
super.paintComponent(paramGraphics);
}
On peut aussi se poser la question de l'intérêt de réutiliser AWT dans un Framework RIA. Microsoft a entièrement revu son moteur de rendu pour WPF et Silverlight. Pourquoi Sun continue t-il à réutiliser l'AWT là où il pourrait concevoir un Framework totalement homogène de bout en bout basé sur du "vrai" Vectoriel.
Pour bien comprendre les incidences de ces choix techniques, cliquez sur ce lien JNLP censé constituer une des démos les plus célèbres de JavaFX. Une fois téléchargée, essayez de faire un Zoom x1600 sur l'image affichée. Vous pouvez changer le libellé du bouton dans le code source. Le résultat est sans appel. Alors que les axes X et Y restent d'une netteté impeccable, le bouton est complètement flou, son contenu aussi. On voit là toutes les limites de ce mélange de modèle. Aucune des démos proposées sur javafx.com ne proposent de loupe, CQFD.
Langage de Scripting - JavaFX Script
Dans la même lignée, je me suis toujours demandé pourquoi JavaFX avait cherché à copier Flex en réinventant un n-ième langage de Script à la ActionScript. L'éditeur rétorque que Java n'est pas forcément adapté à la construction d'IHM. Soit. Mais dans ce cas, pourquoi ne pas proposer (vu que le code in-fine exécuté par le Runtime est du Byte-code 100% Java) la possibilité de coder dans l'un ou l'autre langage. On pourrait ainsi proposer aux développeurs (plus enclin à faire du Java) un langage structuré statique maîtrisé par une large communauté et dans l'autre un langage de Script destiné aux graphistes. Techniquement, ce serait très simple. Mais il n'existe de la part de Sun aucune recommandation, ni exemples de code permettant ce cas d'utilisation.
Evaluation dynamique de Script
La plateforme RIA de Microsoft fût une des premières à prendre le risque d'intégrer nativement un noyau dynamique (la DLR) dans son Runtime. JavaFX de son côté n'a pu faire ce saut technologique du fait de son adhérence à la JVM Java existante et du jeu d'instruction en place dans cette JVM. Il y a pourtant un minimum de dynamique puisqu'on est capable d'évaluer une expression JavaFX (comme le montre l'exemple du PAD). Là encore, en cherchant dans les sources, je suis tombé sur la classe Evaluator. C'est une sorte d'API qui encapsule le compilateur javafx en chargeant dynamiquement le byte-code. Rien à voir avec la DLR de Microsoft, beaucoup plus puissante puisque permettant de naviguer dans l'AST généré dynamiquement. L'API Scripting de Java est expliquée dans cet article.
package javafx.util;
import com.sun.javafx.api.JavaFXScriptEngine;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
class Evaluator
{
static Object eval(String paramString)
throws ScriptException
{
ScriptEngineManager localScriptEngineManager = new ScriptEngineManager();
ScriptEngine localScriptEngine = localScriptEngineManager.getEngineByExtension("javafx");
JavaFXScriptEngine localJavaFXScriptEngine = (JavaFXScriptEngine)localScriptEngine;
if (localJavaFXScriptEngine == null)
throw new ScriptException("no scripting engine available");
return localJavaFXScriptEngine.eval(paramString);
}
}
Les feuilles de style CSS
Je rappelle que je n'ai pas lu de documentation officielle de JavaFX. Seule la lecture du code source me guide dans cette analyse. A y regarder de plus près, JavaFX permet de styler des composants à la sauce CSS via un Parser maison pour peu que le composant dérive de la classe Stylable. Je n'ai trouvé que peu de composants dérivant de cette interface (en tout cas pas assez pour prétendre représenter une application business dans la richesse de ses contrôles). Lorsqu'il s'agira plus tard de donner aux composants Swing existants des capacités CSS, il risque d'y avoir un vrai clash d'API. Une situation qui n'est pas sans rappeler celle de Silverlight, livré en version 1.0 complètement démunie de contrôles graphiques évolués.
Le moteur de Scène vectoriel
Finalement, l'une des rares originalités de JavaFX est d'intégrer un moteur de scène, proposé dans le package javafx.scene. Même si dans la pratique, il ne l'utilise que trop peu.
Ce moteur de scène remplit les conditions minimum pour créer une structure d'interface vectorielle avec des Noeuds, des Groupes, etc ... Certains sources s'appuient sur SVG pour représenter des chemins. D'ailleurs, on peut se demander pourquoi Sun n'a pas simplement intégré un parser SVG avec un modèle de composants SVG-Swing, Batik aurait très bien pu faire l'affaire, d'autant plus qu'il fournit déjà des bindings Swing.
N'est pas lambda expression qui veut
Parmi les curiosités de cette exploration, je suis tombé sur une sorte de simulation de lambda expression. La JVM n'est pas encore parée pour les lambda expressions à la mode .NET. Un changement du jeu d'instruction est nécessaire. Du coup, lorsque j'ai vu ce package, mes cheveux se sont dressés sur la tête :-). Les pointeurs de fonction (et oui JavaFX, comme toute technologie RIA use et abuse des délégués et classes anonymes) sont déclarés de manière générique avec 8 fois (pourquoi 8 d'ailleurs?) la classe FunctionX.class avec des paramètres croissants. Je n'ai pas essayé de créer des fonctions anonymes à 9 paramètres...
Conclusion
Cette petite exploration de JavaFX m'a été très instructive. Pour comprendre les mécanismes internes du compilateur, mais aussi pour jauger de la maturé et la cohérence du design interne de ce Framework, prédit semble t-il à un bel avenir.
Pour ma part, je reste encore très partagé. Construit sur les fondations de la JVM, on ne peut s'empêcher de comparer le temps de chargement de JavaFX avec celui des Runtime Flex et Silverlight. Dans ce domaine, JavaFX est encore trop lent pour prétendre soutenir la comparaison. Sans compter que sa trop forte dépendance avec les API du JDK n'aidera pas à alléger cette charge.
Par ailleurs, côté périmètre fonctionnel (richesse des composants), on est encore très (très) loin de pouvoir développer une application business avec de multiples contrôles (DataGrid, Listes complexes, Arbres, Onglets, ...) en mode full vectoriel. Et pourquoi diable Sun ne s'est-il pas appuyé sur Processing (parcourez simplement le site de démo des primitives), seul en mesure de mettre KO les Flash et consort ...
Finalement, tout comme Silverlight à une époque, ce Framework est sorti dans la précipitation et les premiers clients essuieront les plâtres. En 2009, les seuls Framework matures RIA resteront Flex et Silverlight. Ce dernier recueille tous mes suffrages, pour la cohérence de son API et sa marge de progression. J'y reviendrais dans un prochain billet.
Je voulais essayer Silverlight, mais j'ai l'impression qu'on ne peut développer qu'avec Windows, c'est impossible de créer des applications Silverlight sous Mac ? (puis j'ai horreur de VS ;p)