User Tools

Site Tools


java:javabeans

Differences

This shows you the differences between two versions of the page.


Previous revision
java:javabeans [2022/12/02 22:02] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +====== Java Beans ======
 +
 +===== Introducción =====
 +
 +Los Java Beans -en castellano granos de café java- no son otra cosa que un modelo de componentes para Java. Se estandariza la forma de definir las propiedades (métodos get y set), cómo deben notificarse cambios en los estados del componente (propiedades ligadas, constraints) y cómo acceder a colecciones de elementos (propiedades índice). 
 +
 +Estas notas están sacadas del [[http://java.sun.com/docs/books/tutorial/javabeans/index.html|Tutorial de Java sobre java beans]] y he extraido aquello que se refiere sólamente al código fuente, dejando de lado los aspectos de diseño y visuales. 
 +
 +===== Propiedades sencilla ===== 
 +
 +Un java bean sencillo: 
 +
 +<code java>
 +
 +public class MyBean {
 +    
 +    /** Creates a new instance of MyBean */
 +    public MyBean() {
 +    }
 +
 +    /**
 +     * Holds value of property yourName.
 +     */
 +    private String yourName;
 +
 +    /**
 +     * Getter for property yourName.
 +     * @return Value of property yourName.
 +     */
 +    public String getYourName() {
 +        return this.yourName;
 +    }
 +
 +    /**
 +     * Setter for property yourName.
 +     * @param yourName New value of property yourName.
 +     */
 +    public void setYourName(String yourName) {
 +        this.yourName = yourName;
 +    }
 +    
 +}
 +
 +</code>
 +
 +Las propiedades exponen dos métodos públicos: getNombrePropiedad y setNombrePropiedad. El "set" siempre retorna void, el get siempre retorna el tipo de la propiedad. 
 +
 +===== Propiedades Indexadas =====
 +
 +Cuando una propiedad debe exponer una colección de elementos (el acceso a una lista de valores), los métodos a programar son cuatro: 
 +
 +  * String getNombrePropiedad( int index ) - devolverá el elemento de la enésima posición de la lista
 +  * String[] getNombrePropiedad() - devolverá una copia de la colección completa
 +  * void setNombrePropiedad( int index, String valor ) - establece el enésimo elemento de la lista
 +  * void setNombrePropiedad( String[] valores ) - establece la colección completa
 +
 +<code java>
 +
 +    /**
 +     * Holds value of property lines.
 +     */
 +    private String[] lines;
 +
 +    /**
 +     * Indexed getter for property lines.
 +     * @param index Index of the property.
 +     * @return Value of the property at index.
 +     */
 +    public String getLines(int index) {
 +        return this.lines[index];
 +    }
 +
 +    /**
 +     * Getter for property lines.
 +     * @return Value of property lines.
 +     */
 +    public String[] getLines() {
 +        return this.lines;
 +    }
 +
 +    /**
 +     * Indexed setter for property lines.
 +     * @param index Index of the property.
 +     * @param lines New value of the property at index.
 +     */
 +    public void setLines(int index, String lines) {
 +        this.lines[index] = lines;
 +    }
 +
 +    /**
 +     * Setter for property lines.
 +     * @param lines New value of property lines.
 +     */
 +    public void setLines(String[] lines) {
 +        this.lines = lines;
 +    }
 +
 +</code>
 +
 +===== Propiedades Ligadas =====
 +
 +Lo que haremos en este caso es utilizar un objeto [[http://java.sun.com/javase/6/docs/api/java/beans/PropertyChangeListener.html|PropertyChangeListener]] para que cada vez que una de las propiedades cambie, se mande un mensaje a aquellos objetos que se hayan registrado como "listeners ((Oyentes))" de nuestro bean. 
 +
 +<code java>
 +
 +import java.awt.Graphics;
 +import java.beans.PropertyChangeListener;
 +import java.beans.PropertyChangeSupport;
 +import java.io.Serializable;
 +import javax.swing.JComponent;
 +
 +/**
 + * Bean with bound properties.
 + */
 +public class MyBean
 +        extends JComponent
 +        implements Serializable
 +{
 +    private String title;
 +    private String[] lines = new String[10];
 +
 +    private final PropertyChangeSupport pcs = new PropertyChangeSupport( this );
 +
 +    public String getTitle()
 +    {
 +        return this.title;
 +    }
 +
 +    public void setTitle( String title )
 +    {
 +        String old = this.title;
 +        this.title = title;
 +        this.pcs.firePropertyChange( "title", old, title );
 +    }
 +
 +    public String[] getLines()
 +    {
 +        return this.lines.clone();
 +    }
 +
 +    public String getLines( int index )
 +    {
 +        return this.lines[index];
 +    }
 +
 +    public void setLines( String[] lines )
 +    {
 +        String[] old = this.lines;
 +        this.lines = lines;
 +        this.pcs.firePropertyChange( "lines", old, lines );
 +    }
 +
 +    public void setLines( int index, String line )
 +    {
 +        String old = this.lines[index];
 +        this.lines[index] = line;
 +        this.pcs.fireIndexedPropertyChange( "lines", index, old, lines );
 +    }
 +
 +    public void addPropertyChangeListener( PropertyChangeListener listener )
 +    {
 +        this.pcs.addPropertyChangeListener( listener );
 +    }
 +
 +    public void removePropertyChangeListener( PropertyChangeListener listener )
 +    {
 +        this.pcs.removePropertyChangeListener( listener );
 +    }
 +
 +}
 +
 +</code>
 +
 +
 +
 +
 +===== Propiedades ligadas y limitadas =====
 +
 +Existe también la posibilidad de que los listeners puedan "vetar" un cambio, que son lo que se llama "constrained properties" ((propiedades limitadas)).
 +
 +<code java>
 +
 +import java.io.Serializable;
 +import java.beans.PropertyChangeListener;
 +import java.beans.PropertyChangeSupport;
 +import java.beans.PropertyVetoException;
 +import java.beans.VetoableChangeListener;
 +import java.beans.VetoableChangeSupport;
 +import java.awt.Graphics;
 +import javax.swing.JComponent;
 +
 +/**
 + * Bean with constrained properties.
 + */
 +public class MyBean
 +        extends JComponent
 +        implements Serializable
 +{
 +    private String title;
 +    private String[] lines = new String[10];
 +
 +    private final PropertyChangeSupport pcs = new PropertyChangeSupport( this );
 +    private final VetoableChangeSupport vcs = new VetoableChangeSupport( this );
 +
 +    public String getTitle()
 +    {
 +        return this.title;
 +    }
 +/**
 + * This method was modified to throw the PropertyVetoException
 + * if some vetoable listeners reject the new title value
 + */
 +    public void setTitle( String title )
 +            throws PropertyVetoException
 +    {
 +        String old = this.title;
 +        this.vcs.fireVetoableChange( "title", old, title );
 +        this.title = title;
 +        this.pcs.firePropertyChange( "title", old, title );
 +    }
 +
 +    public String[] getLines()
 +    {
 +        return this.lines.clone();
 +    }
 +
 +    public String getLines( int index )
 +    {
 +        return this.lines[index];
 +    }
 +/**
 + * This method throws the PropertyVetoException
 + * if some vetoable listeners reject the new lines value
 + */
 +    public void setLines( String[] lines )
 +            throws PropertyVetoException
 +    {
 +        String[] old = this.lines;
 +        this.vcs.fireVetoableChange( "lines", old, lines );
 +        this.lines = lines;
 +        this.pcs.firePropertyChange( "lines", old, lines );
 +    }
 +
 +    public void setLines( int index, String line )
 +            throws PropertyVetoException
 +    {
 +        String old = this.lines[index];
 +        this.vcs.fireVetoableChange( "lines", old, line );
 +        this.lines[index] = line;
 +        this.pcs.fireIndexedPropertyChange( "lines", index, old, line );
 +    }
 +
 +    public void addPropertyChangeListener( PropertyChangeListener listener )
 +    {
 +        this.pcs.addPropertyChangeListener( listener );
 +    }
 +
 +    public void removePropertyChangeListener( PropertyChangeListener listener )
 +    {
 +        this.pcs.removePropertyChangeListener( listener );
 +    }
 +/**
 + * Registration of the VetoableChangeListener
 + */
 +    public void addVetoableChangeListener( VetoableChangeListener listener )
 +    {
 +        this.vcs.addVetoableChangeListener( listener );
 +    }
 +
 +    public void removeVetoableChangeListener( VetoableChangeListener listener )
 +    {
 +        this.vcs.removeVetoableChangeListener( listener );
 +    }
 +
 +    protected void paintComponent( Graphics g )
 +    {
 +        g.setColor( getForeground() );
 +
 +        int height = g.getFontMetrics().getHeight();
 +        paintString( g, this.title, height );
 +
 +        if ( this.lines != null )
 +        {
 +            int step = height;
 +            for ( String line : this.lines )
 +                paintString( g, line, height += step );
 +        }
 +    }
 +
 +    private void paintString( Graphics g, String str, int height )
 +    {
 +        if ( str != null )
 +            g.drawString( str, 0, height );
 +    }
 +}
 +
 +</code>
 +
 +
 +===== Persistencia: la vida más allá de la cpu =====
 +
 +Hay dos modos de que un java bean pueda alcanzar la persistencia: serialización y externalización. 
 +
 +La **serialización** se consigue implentando el interfaz Serializable, que podemos entender como un mero "marcador" que indica que nuestro componente es puede serializarse y por lo tanto ser almacenado en disco --o transferido por la red--. 
 +
 +Si la clase padre ya implementa Serializable, entonces la nuestra es también serializable. 
 +
 +Si queremos que una clase o método no se guarde en el proceso de serialización, usaremos el marcador "transient"
 +
 +Podemos hacer que la serialización no funcione por defecto implementando estos dos métodos en nuestra clase: 
 +
 +<code java>
 +
 +private void writeObject( java.io.ObjectOutputStream out) throws IOException; 
 +
 +private void readObject( java.io.ObjectInputStream out) throws IOException, ClassNotFoundException; 
 +
 +</code>
 +
 +La **externalización** exige de un mayor trabajo por nuestra parte, y está pensada para que el contenido del java bean se escriba en disco. 
 +
 +Se hace básicamente heredando el interfaz Externalizable e implementando a continuación los métodos readExternal y writeExternal. 
 +
 +La clase que implemente Externalizable tiene que tener un constructor sin argumentos. 
 +
 +===== Codificando y descodificando un objeto en XML =====
 +
 +La clase [[http://java.sun.com/j2se/1.4.2/docs/api/java/beans/XMLEncoder.html|XMLEncoder]] permite hacer esto. Ahí van dos ejemplos: 
 +
 +<code java>
 +XMLEncoder e = new XMLEncoder(
 +    new BufferedOutputStream(
 +        new FileOutputStream("Test.xml")));
 +e.writeObject(object);
 +e.close()
 +</code>
 +
 +<code java>
 +XMLDecoder decoder = new XMLDecoder( 
 +              new BufferedInputStream( 
 +              new FileInputStream( "Test.xml" ) ) ); 
 +Object object = decoder.readObject(); 
 +decoder.close();
 +</code>
 +