- Eine Bean hat einen öffentlichen parameterlosen Konstruktor
- Die Bean implementiert Serialisierbarkeit.
- Für die Attribute existieren öffentliche Getter und ggf. auch Setter.
PropertyChange und Veto
Das Besondere an einer Bean ist, dass Änderungen an den Properties durch Ereirgnisse weiterleiten.Ein Attribut kann als Property verwendet werden, wenn es als privates Attribut definiert ist und passende Methoden existieren, die den Zugriff erlauben. Dazu ist konventionsgemäß folgende Benennung erforderlich:
- Das Attribunt ist private und kleingeschrieben, bspw. name
- Die Lesemethode beginnt mit get und es folgt der mit einem Großbuchstaben beginnende Name des Attributs, bspw. getName
- Die Schreibmethode muss nicht implementiert sein. Sie beginnt mit set. Es folgt der Name des Attributs, beginnend mit einem Großbuchstaben. Als Parameter wird der neue Wert des Attributs übergeben.
private String name = ""; public String getName() { return name; } public void setName(String str) { name = str; }
Beispiel: Person und Personenkontrolle
Die folgende Bean beschreibt eine Person. Sie hat die Property name, die durch die Methoden getName und setName gelesen und geschrieben werden können.Die Bean bietet Methoden an, um sich als PropertyChangeListener und als VetoableChangeListener einzutragen und wieder abzumelden. Der Unterschied zwischen beiden liegt darin, dass der erstere über eine Änderung der Property informiert wird. Der zweitere kann ein Veto einlegen und eine Änderung durch Werfen einer Exception unterbinden.
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.beans.VetoableChangeSupport; public class Person { private String name = ""; // Diese Eigenschaft soll ueberwacht werden public static final String NAME_ATTR = "NameAttribute"; private PropertyChangeSupport changes = new PropertyChangeSupport(this); private VetoableChangeSupport vetos = new VetoableChangeSupport(this); // Im Setter wird bei einer Aenderung ein Veto angeboten und // die Aenderung gemeldet. public void setName(String neuName) throws PropertyVetoException { String oldName = this.name; // sichere den Bestand // Informiere die Veto-Maechte, die ggf eine Exception // ausloesen, um die darauf folgenden Schritte zu vereiteln. vetos.fireVetoableChange(NAME_ATTR, oldName, neuName); this.name = neuName; // Die Aenderung erfolgt // Nun werden die angemeldeten Listener informiert: changes.firePropertyChange(NAME_ATTR, oldName, neuName); } // Der Getter ist voellig unauffaellig public String getName() { return name; } // Anmeldung fuer Aenderungs-Events des kompletten Objekts public void addPropertyChangeListener(PropertyChangeListener listener) { changes.addPropertyChangeListener(listener); } // Anmeldung fuer Aenderungs-Events eines speziellen Attributs public void addPropertyChangeListener(String propStr, PropertyChangeListener listener) { changes.addPropertyChangeListener(propStr, listener); } // Abmeldung public void removePropertyChangeListener(PropertyChangeListener listener) { changes.removePropertyChangeListener(listener); } // Anmeldung fuer den Widerspruch gegen eine Aenderung public void addVetoableChangeListener(VetoableChangeListener listener) { vetos.addVetoableChangeListener(listener); } // Abmeldung public void removeVetoableChangeListener(VetoableChangeListener listener) { vetos.removeVetoableChangeListener(listener); } }Die folgende Klasse zeigt, wie die Überwachung einer Property-Änderung funktioniert. Sie legt sich ein Objekt der Klasse Person an. Darüber meldet sie zunächst einen ChangeListener an, der hier einfach anzeigt, dass sich etwas geändert hat.
Im zweiten Schritt meldet sie sich für ein Veto an. Wie oben gesehen wird die Bean dieses Ereignis direkt vor einer Änderung abfeuern. So kann der Überwacher rechtzeitig eine Exception werfen, die eine Änderung verhindert.
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; /** * Kleines Programm zur Demonstration eines PropertyChangeListeners */ public class PersonenKontrolle { public PersonenKontrolle() { Person person = new Person(); // Anmelden fuer alle PropertyChangeEvents des Objekts person person.addPropertyChangeListener(new PropertyChangeListener() { // Im Falle eines firePropertyChange wird dies aufgerufen: @Override public void propertyChange(PropertyChangeEvent e) { System.out.println( "Aenderung an: " + e.getPropertyName() + "bisher: " + e.getOldValue() + " nun: " + e.getNewValue()); } }); // Anmeldung fuer fireVetoableChange zur Verhinderung einer Aenderung person.addVetoableChangeListener(new VetoableChangeListener() { @Override public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException { if (Person.NAME_ATTR.equals(e.getPropertyName())) { // Die Eigenschaft NAME_ATTR soll geaendert werden. String neuName = (String) e.getNewValue(); if (neuName.equals("Kevin")) { // Die Aenderung soll "Kevin" sein. // Das muss durch Werfen einer Exception verhindert werden. throw new PropertyVetoException( "Alles, nur nicht Kevin!", e); } } } }); // Nun testen wir die Aenderungs-Listener! try { // Es kann und wird Exceptions hageln! person.setName("Martin"); // Aenderung wird gemeldet person.setName("Martin"); // Keine Aenderung, keine Meldung person.setName("Kevin"); // Das duerfte am Veto scheitern person.setName("Matthias"); // Wird wegen der Exception nicht mehr erreicht } catch (PropertyVetoException e) { System.out.println(""+e.getMessage()); // Zeige mal den Kommentar! //e.printStackTrace(); // Komplette Exception darstellen } // Tatsächlich: Es bleibt bei Martin! System.out.println("Name ist nun: " + person.getName()); } public static void main(String[] args) { new PersonenKontrolle(); // Starte Instanz! } }