Schnelles Hinzufügen des PropertyChangeSupport mit Eclipse

veröffentlicht am 05. August 2012

Ich arbeite derzeit an einer Swing Anwendung, bei der verschiedene Komponenten per Beans Binding (JSR 295) miteinander über entsprechende Model Klassen synchronisiert werden sollen. Ohne das Hinzufügen des PropertyChangeSupport zu den entsprechenden Model Klassen ist jedoch nur eine unidirektionale Synchronisierung möglich. So werden zwar z.B. Texteingaben in der Oberfläche mit dem Model synchronisiert, jedoch Änderungen am Model nicht automatisch mit gebundenen Komponenten abgeglichen. Also musste eine Methode zum schnellen Hinzufügen des PropertyChangeSupport her, damit auch eine bidirektionale Synchronisierung realisiert werden kann.

Zunächst habe ich eine abstrakte Klasse entwickelt (liegt im selben Package wie die Model Klassen, deshalb package-private), die den PropertyChangeSupport implementiert und von der alle gewünschten Model Klassen erben:

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

/**
 * Abstract class to provide PropertyChangeSupport for JavaBeans.
 * 
 * @author Patrick Gotthard
 * 
 */
abstract class AbstractBindableModel {

	/**
	 * Should be transient to not conflict with serialization.
	 */
	private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

	/**
	 * Adds a property change listener.
	 * 
	 * @param listener The property change listeter
	 */
	public void addPropertyChangeListener(final PropertyChangeListener listener) {
		propertyChangeSupport.addPropertyChangeListener(listener);
	}

	/**
	 * Removes a property change listener.
	 * 
	 * @param listener The property change listener
	 */
	public void removePropertyChangeListener(final PropertyChangeListener listener) {
		propertyChangeSupport.removePropertyChangeListener(listener);
	}

	/**
	 * Convenience method to fire property change events.
	 * 
	 * @param propertyName Name of the property
	 * @param oldValue Old value of the property
	 * @param newValue New value of the property
	 */
	protected void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue) {
		propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
	}

}

Falls es nicht möglich sein sollte, von dieser Klasse zu erben (weil bereits von einer anderen Klasse geerbt wird), muss entweder der Code in die entsprechende Model Klasse übernommen werden oder die Elternklasse von der Klasse erben.

Eine Model Klasse könnte nun wie folgt aussehen:

public class User extends AbstractBindableModel {

	private String firstName;
	private String lastName;

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(final String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(final String lastName) {
		this.lastName = lastName;
	}

}

Damit registrierte Komponenten auch über Änderungen am Model informiert werden, müssen die gewünschten Setter ein PropertyChangeEvent feuern. Der Setter für den Vornamen würde dann so aussehen:

public void setFirstName(final String firstName) {
	firePropertyChange("firstName", this.firstName, this.firstName = firstName);
}

Bei einer einzigen Property kann der Quellcode noch recht schnell geschrieben werden, bei vielen Properties sollte man sich jedoch der Suchen-und-Ersetzen Funktion von Eclipse bedienen:

  • Strg + F drücken
  • Find: (this.+) = (\w+);
  • Replace with: firePropertyChange(„$2“, $1, $1 = $2);
  • Regular expressions ankreuzen
  • Replace all ausführen

Schon wird der PropertyChangeSupport für alle Properties erzeugt. Die eben gezeigte Klasse sieht dann wie folgt aus:

public class User extends AbstractBindableModel {

	private String firstName;
	private String lastName;

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(final String firstName) {
		firePropertyChange("firstName", this.firstName, this.firstName = firstName);
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(final String lastName) {
		firePropertyChange("lastName", this.lastName, this.lastName = lastName);
	}

}

Quellen und weiterführende Links

Hinterlasse einen Kommentar