java:javabeans
Differences
This shows you the differences between two versions of the page.
| Previous revision | |||
| — | java:javabeans [2022/12/02 21: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:// | ||
| + | |||
| + | ===== 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; | ||
| + | } | ||
| + | | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | Las propiedades exponen dos métodos públicos: getNombrePropiedad y setNombrePropiedad. El " | ||
| + | |||
| + | ===== 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; | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | ===== Propiedades Ligadas ===== | ||
| + | |||
| + | Lo que haremos en este caso es utilizar un objeto [[http:// | ||
| + | |||
| + | <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( " | ||
| + | } | ||
| + | |||
| + | 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( " | ||
| + | } | ||
| + | |||
| + | public void setLines( int index, String line ) | ||
| + | { | ||
| + | String old = this.lines[index]; | ||
| + | this.lines[index] = line; | ||
| + | this.pcs.fireIndexedPropertyChange( " | ||
| + | } | ||
| + | |||
| + | public void addPropertyChangeListener( PropertyChangeListener listener ) | ||
| + | { | ||
| + | this.pcs.addPropertyChangeListener( listener ); | ||
| + | } | ||
| + | |||
| + | public void removePropertyChangeListener( PropertyChangeListener listener ) | ||
| + | { | ||
| + | this.pcs.removePropertyChangeListener( listener ); | ||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== Propiedades ligadas y limitadas ===== | ||
| + | |||
| + | Existe también la posibilidad de que los listeners puedan " | ||
| + | |||
| + | <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( " | ||
| + | this.title = title; | ||
| + | this.pcs.firePropertyChange( " | ||
| + | } | ||
| + | |||
| + | 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( " | ||
| + | this.lines = lines; | ||
| + | this.pcs.firePropertyChange( " | ||
| + | } | ||
| + | |||
| + | public void setLines( int index, String line ) | ||
| + | throws PropertyVetoException | ||
| + | { | ||
| + | String old = this.lines[index]; | ||
| + | this.vcs.fireVetoableChange( " | ||
| + | this.lines[index] = line; | ||
| + | this.pcs.fireIndexedPropertyChange( " | ||
| + | } | ||
| + | |||
| + | 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 ); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | ===== Persistencia: | ||
| + | |||
| + | Hay dos modos de que un java bean pueda alcanzar la persistencia: | ||
| + | |||
| + | La **serialización** se consigue implentando el interfaz Serializable, | ||
| + | |||
| + | Si la clase padre ya implementa Serializable, | ||
| + | |||
| + | Si queremos que una clase o método no se guarde en el proceso de serialización, | ||
| + | |||
| + | 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, | ||
| + | |||
| + | </ | ||
| + | |||
| + | 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:// | ||
| + | |||
| + | <code java> | ||
| + | XMLEncoder e = new XMLEncoder( | ||
| + | new BufferedOutputStream( | ||
| + | new FileOutputStream(" | ||
| + | e.writeObject(object); | ||
| + | e.close() | ||
| + | </ | ||
| + | |||
| + | <code java> | ||
| + | XMLDecoder decoder = new XMLDecoder( | ||
| + | new BufferedInputStream( | ||
| + | new FileInputStream( " | ||
| + | Object object = decoder.readObject(); | ||
| + | decoder.close(); | ||
| + | </ | ||
| + | |||
