1 

JavaBeans : Première approche

I. Qu'est ce que les Java-Beans ?

Les développeur cherche au maximum à construire des applications à composants c'est-à-dire créer des modules afin de les réutiliser et d'améliorer leur productivité, leur développement et la robustesse de leurs programmes. Java, grâce aux Java-Beans répond parfaitement à cette attente, de façon simple et efficace.
Plusieurs tentatives de gestion de composants avaient été développées par IBM ou OpenDoc d'Apple mais elles ont toutes été des échecs.
Nous utiliserons le programme "BeanBox" qui est un utilitaire de visualisation / test / debug de Beans, développé par Sun et téléchargeable sur leur site (http://www.java.sun.com). Ce programme est écrit en java et se veut donc portable aussi bien sous Windows et que sous Unix/Linux. Nous expliquerons en détail son fonctionnement au moment voulu.

Les Java-Beans représentent en fait un Design Pattern particulier. Vous ne serez pas surpris de savoir que vous en avez surement déjà utilisés ... En effet les librairies awt ou encore mieux swing sont totalement basés sur ce concept. Cela n'est pas étonnant car ces librairies proposent des composants réutilisables et complètements personnalisables.
Cependant un Java-Beans n'est rien d'autre qu'une classe et donc un objet. C'est cette simplicité qui fait que les Beans se développe rapidement. Vous connaissez peut être le développement d'ActiveX (ocx), objet COM ... qui se révèle impossible ç développer car l'étendu des connaissances à avoir avant de pouvoir l'utiliser correctement est trop importante, Java supprime tout ça !

II. Utilisation de BeanBox

Nous allons étudier l'utilisation de l'application d'aide au développement de Beans par Sun. Ci dessous une copie d'écran de la fenêtre principale de l'application :

L'application se compose de plusieurs fenêtres :

  • Fenêtre principale avec le menu qui permet de contrôler les tests, importer vos beans ...
  • Fenêtre toolbox qui récapitule l'ensemble des beans importés.
  • Fenêtre de tracer de méthode (permet de tracer vos propres évènements)
  • Fenêtre propriétés du composant sélectionné
  • Console de sortie

Voici le premier beans qui va nous permettre de tester les fonctionnalités de base de BeanBox :

import java.awt.Canvas;
import java.awt.*;

public class AfficheCouleur extends Canvas {
    
    private int rouge;
    private int vert;
    private int bleu;

    public AfficheCouleur() {
    }

    // surcharge de paint
    public void paint(Graphics g) {
        g.setColor(new Color(rouge, vert, bleu));
        g.fillRect(0, 0, getWidth(), getHeight());
    }

    // setters
    public void setRouge(int rouge) {
        this.rouge = rouge;
    }

    public void setVert(int vert) {
        this.vert = vert;
    }

    public void setBleu(int bleu) {
        this.bleu = bleu;
    }

    // getters
    public int getRouge() {
        return rouge;
    }

    public int getVert() {
        return vert;
    }

    public int getBleu() {
        return bleu;
    }
}

Pour utiliser le bean, le plus pratique est de créer une archive .jar qui contiendra les .class de votre beans (ici AfficheCouleur.class).
ATTENTION : vous devez indiquer dans le manifest que votre jar est un Bean ! pour cela créer un fichier AfficheCouleur.mf ( mf pour manifest) :

Manifest-Version: 1.0
Name: AfficheCouleur.class
Java-Bean: True

Si votre class AfficheCouleur est dans un package vous devrez changer le "Name" en package.souspackage.AfficheCouleur (en changeant respectivant package.souspackage par l' arborescence de votre package).
Une fois le manifest créé, vous pouvez créer votre jar via la commande : jar cvfm AfficheCouleur.jar AfficheCouleur.mf AfficheCouleur.class.

Vous pouvez récupérer l'archive toute faite ici.

Vous pouvez maintenant tester votre Beans avec BeanBox. Il vous suffit d'importer votre .jar via File -> Loaded.jar. Une fois importé vous retrouver votre composant dans la fenêtre TooBox. Cliquez dessus et insérez le dans la zone d'édition de la fenêtre principale. Vous voyez alors apparaitre votre composant et les propriétés associées dans la fenêtre (cf. image ci-dessous)

Vous pouvez remarquer que dans les propriétés vous avez : bleu, rouge et vert. Essayer de jouer sur les getters et les setters (supprimer les méthodes) de la classe AfficheCouleur et regarder le résultat dans BeanBox.

Vous avez également la possiblité d'ajouter plusieurs composants et de gérer des évènements entre eux (sans effectuer une seule ligne de code !) il vous suffit d'aller dans Edit -> Events, choisir un évènement et finalement lié cet évènement à un autre composant (avec la souris !). BeanBox vous demandera alors quelle méthode appeler lorsque l'évènement sera lancé. Ceci est très pratique pour vérifier que votre gestion d'évènement marche correctement.

Vous allez mieux comprendre comment marche ces beans grâce à l'étude du design pattern associé.


III. Explication du Design Pattern

Un design pattern n'est rien d'autre qu'un modèle de programmation d'un concept. Nous allons donc détailler ici celui d'un Java-Beans.

La première chose à respecter est les "setters" et les "getters". En effet c'est grâce à ces méthodes publiques que l'on va pouvoir récupérer ou paramétrer une propriété du Bean. Dans notre exemple de l'afficheur de couleur, nous avons 3 propriétés qui sont rouge, vert et bleu (les composantes de la couleur affichée). Bien entendu nous avons mis ces membres en "private" afin que chaque modification soit faite via les setters.
Nos 3 propriétés sont en lecture/écriture car chaque membre a son propre getter et setter. Si nous omettons le setter setRouge par exemple, le membre rouge ne sera qu'en lecture seule (ceci peut parfois être pratique).

La seconde chose concerne les évènements.
Voici un petit rappel sur le concept des évènements en java.
La gestion d'évènements en java suit un design pattern précis. L' évènement est représenté par un objet. Le type d'évènement est décrit par une interface qui permettra d'être implémentée lors de la gestion de l'évènement dans un programme. Afin de respecter les conventions voici comment vous devez nommer vos classes :

  • XxxListener pour l'interface de votre évènement.
  • XxxEvent pour l'objet qui décrira votre évènement.

De plus, votre classe XxxListener doit hériter de EventListener et votre classe XxxEvent doit hériter de EventObject.
Par exemple si vous ajouter un événement s'appelant nouvelleHeure (par exemple pour une montre) vous devrez créer un prototype nouvelleHeure ( NouvelleHeureEvent nhe ) dans votre NouvelleHeureListener interface.

Si vous souhaitez créer un nouveau type d'évènement dans votre composant vous devrez gérer l'ajout de listener et leur suppression. Afin de respecter les conventions, vous définirez les méthodes : addXxxListener (XxxListener xl) et removeXxxListener (XxxListener xl). Voici un schéma récapitulatif sur la gestion des évènements :

Cependant il faut utiliser la création de nouveaux évènements avec parcimonie et bien vérifier que l'évènement n'existe pas déjà. Dans notre exemple de la montre il est préférable de passer par un PropertyChangeEvent. Pour cela vous utiliserez l'objet PropertyChangeSupport (qui contient principalement les méthodes addPropertyChangeListener et removePropertyChangeListener) qui vous aideront à gérer ces évènements.

Si l'on crée une instance PropertyChangeSupport pcs dans notre classe, nous pouvons utiliser pcs.firePropertyChange ( "nom_propriete", ancienneValeur, nouvelleValeur ) pour "lancer" l'évènement et donc appeler les différentes actions qui auront été préalablement ajoutées (via les addXxxListener et addXxxListener méthodes).

IV. Exemple de beans

Nous allons, afin de bien comprendre comment marche les beans, développer un sélecteur de couleur très simple. Voici à quoi nous allons arriver :

Cette application se compose :

  • de trois scrollbares qui identifient les composantes rouge, vert et bleu (RVB).
  • d'un évènement personnalisées qui indique que la couleur a changé (nous aurions cependant dû faire cela via un PropertyChange). Il nous faudra donc créer nos classes et interfaces pour cet évènement.

Voici le code globale que nous allons commenter par la suite :

/* Classe principale du beans (interface graphique)
*    
*/

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import java.beans.*;
import java.util.*;

public class ColorSelector extends JPanel implements AdjustmentListener, Serializable {
    
    private JScrollBar jscRouge = new JScrollBar(JScrollBar.HORIZONTAL);
    private JScrollBar jscVert = new JScrollBar(JScrollBar.HORIZONTAL);
    private JScrollBar jscBleu = new JScrollBar(JScrollBar.HORIZONTAL);
    private GridLayout gridLayout1 = new GridLayout(4, 1);

    // event
    private ArrayList tabChangedColorListeners = new ArrayList();

    public ColorSelector() {
        try {
            jbInit();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void jbInit() throws Exception {
        // layout
        this.setLayout(gridLayout1);

        // parametre
        jscBleu.setMaximum(255);
        jscRouge.setMaximum(255);
        jscVert.setMaximum(255);

        // adding
        this.add(jscRouge, null);
        this.add(jscVert, null);
        this.add(jscBleu, null);

        // listeners
        jscBleu.addAdjustmentListener(this);
        jscRouge.addAdjustmentListener(this);
        jscVert.addAdjustmentListener(this);
    }

    /**
     * adjustmentValueChanged of scrollbars
     *
     * @param e AdjustmentEvent
     */
    public void adjustmentValueChanged(AdjustmentEvent e) {

        // Nouvel objet nouvelle couleur
        Color newColor = new Color(jscRouge.getValue(), jscVert.getValue(), jscBleu.getValue());

        // Nouveau event
        fireChangedColor(getBackground(), newColor);
        // Change la couleur du fond
        setBackground(newColor);
    }

    // event ChangedColorListener
    public void addChangedColorListener(ChangedColorListener ccl) {
        tabChangedColorListeners.add(ccl);
    }

    public void removeChangedColorListener(ChangedColorListener ccl) {
        tabChangedColorListeners.remove(ccl);
    }

    public void fireChangedColor(Color oldColor, Color newColor) {
        ChangedColorEvent tmpEvent = new ChangedColorEvent(this, newColor);
        for (int i = 0; i < tabChangedColorListeners.size(); i++) {
            ((ChangedColorListener) tabChangedColorListeners.get(i)).changedColor(tmpEvent);
        }
    }

    // setters
    public void setColor(Color col) {
        jscRouge.setValue(col.getRed());
        jscVert.setValue(col.getGreen());
        jscBleu.setValue(col.getBlue());

        setBackground(col);
    }

    // getters
    public Color getColor() {
        return getBackground();
    }
}


/* Objet évènement pour notre évènement personnalisé
*
*/

import java.util.EventObject;
import java.awt.*;

public class ChangedColorEvent extends EventObject {

    private Color color;

    // Constructeur
    public ChangedColorEvent(Object source, Color col) {
        super(source);
        color = col;
    }

    // getter
    public Color getColor() {
        return this.color;
    }
}


/* Interface pour l'évènement personnalisé
*
*/

import java.util.EventListener;

public interface ChangedColorListener extends EventListener {
    public void changedColor(ChangedColorEvent cce);
}

Vous pouvez récupérer le code ici.
La classe ColorSelector est celle qui représente le composant graphiquement, on lui a ajouté 3 scrollbares et on utilise le gridLayout pour les placer. Notez que nous avons nos 3 méthodes et un ArrayList:

  • addChangedColorListener(ChangedColorListener ccl)
  • removeChangedColorListener(ChangedColorListener ccl)
  • fireChangedColor (Color oldColor, Color newColor)
  • ArrayList tabChangedColorListeners

qui servent à la gestion de notre évènement personnalisé (fireChangedColorListener est optionnelle mais elle permet de mieux structuré le code, ce que l'on cherche par l'utilisation de design pattern). Le membre : tabChangedColorListeners permet de stocker les différentes actions à effectuer lorsque la couleur change (c'est la méthode fireChangedColor qui permettra d'effectuer cette tâche).

La classe ChangedColorEvent représente l'objet évènement qui est utilisé pour décrire notre évènement de changement de couleur. La méthode getColor permet de récupérer la nouvelle couleur.

L'interface ChangedColorListener représente les différentes actions disponibles pour cette évènements (via les prototypes des méthodes qu'il faudra implémenter lors de l'utilisation). Ici nous en avons qu'une seule : changedColor.

Comme vous pouvez le voir la création de Java Beans est vraiment très simple. Nous allons maintenant voir comment intégrer notre beans dans une application concrète.

V. Intégration d'un JavaBeans dans une application

Nous allons tout simplement utilisez le Java Beans crée au IV et l'intégrer dans une Frame. Un Java Beans est un composant comme un autre, il vous suffit donc de l'utiliser comme un JLabel. Voici le code qui nous permet de tester notre sélecteur de couleur.

import javax.swing.JFrame;
import java.awt.HeadlessException;
// Import de notre Java Beans à ne pas oublier
import com.labosun.cj.javabeans.colorselector.*;
import javax.swing.*;
import java.awt.*;

public class ColorSelectorFrameTest extends JFrame {

    ColorSelector cs;
    JLabel lblTest;

    public ColorSelectorFrameTest() throws HeadlessException {
        // Inits
        cs = new ColorSelector();
        lblTest = new JLabel("Couleur");

        // Quitte l'application quand on ferme
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(100, 300);
        this.getContentPane().setLayout(new BorderLayout());

        // add
        this.getContentPane().add(cs, BorderLayout.CENTER);
        this.getContentPane().add(lblTest, BorderLayout.SOUTH);

        // Listener
        cs.addChangedColorListener(new ChangedColorListener() {
            /**
             * changedColor
             *
             * @param cce ChangedColorEvent
             */
            public void changedColor(ChangedColorEvent cce) {
                lblTest.setText(cce.getColor().toString());
            }
        });
    }

    // main
    public static void main(String[] args) {
        new ColorSelectorFrameTest().show();
    }
}

Vous pouvez remarquer que nous n'avons pas de particularités dans le code, nous utilisons notre sélecteur de couleur comme un JLabel ou un JButton (ajout de listeners, paramétrage du composant)... Vous pourrez trouver le code source ici et le jar executable de l'application ici.

Conclusion

Nous avons vu les bases de la création de Java Beans. Vous avez pu remarquer comme il est simple de créer ses propres composants. Les Beans sont très intégrés dans java car ils sont faciles d'emploi, de création et très modulable. Maintenant que vous savez les créer vous pourrez également développer des interfaces pour les personnaliser (nous avons vu que BeanBox en génère à la volée pour chaque composant ... bien entendu nous pouvons générer nos propres interfaces de personnalisation (via l'interface Customizer) pour aller plus loin : http://java.sun.com/products/javabeans/.


1 

Retrouvez ci-dessous les autres sections du Laboratoire Sun
Evènements
Java Sun Net Talk LIVE CHAT le 2 Avril à 16h303/29/08
SolarisSunDécouvrez les nouveaux Sun Fire sous Intel10/11/07
JavaValtech Days10/9/07
JavaApacheCon du 1 au 4 mai à Amsterdam2/13/07

Exemples de code
JavaManipuler les looks and feel (lister et affecter)10/15/07
JavaFaire sa propre injection de dépendance avec les annotations5/9/06
JavaSplash screen avec progress Bar5/5/06
JavaFaire un splash screen en swing5/5/06

Actualités
SunProjet Kenai: une nouvelle forge open source10/3/08
SunSun Microsystems en forme !8/4/08
SunOpenDS un ldap 100% java7/24/08
SunSun et Fujitsu annoncent un nouveau Sparc647/16/08
SunVisualVM, un outil de surveillance des applications Java7/10/08

Tips du laboratoire
EclipseVisual Editor avec Eclipse Europa, c'est possible3/28/08
EclipseGérer les projets dans un workspace.10/16/07
JavaManager votre server d'application avec Eclipse4/21/07
JavaVue des sub-packages avec Eclipse4/21/07
JavaGlisser-déposer avec Eclipse4/21/07

Laboratoire SUPINFO des technologies Sun
labo-sun@supinfo.com


Conditions d'utilisation et © Copyright SUPINFO International University
23, rue de Château Landon - 75010 PARIS - Tél : +33 (0) 153359700 Fax : +33 (0) 153359701
Respect de la vie privée