JavaBeans PropertyChangeSupport Trick

I’ve always written bound properties like this:

public class Rect {
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private int width;

  public void setWidth(int width) {
    int old = this.width;
    this.width = width;
    changes.firePropertyChange("width", old, width);
  }
}

I just realized that the 3-line setWidth(...) method can be compressed to a single line:

public void setWidth(int width) {
  changes.firePropertyChange("width", this.width, this.width = width);
}

It seems like this might reduce a significant amount of boilerplate code for some types of apps.

UPDATE

As pointed out in the comments, for non-primitive properties, null values (both old and new) will trigger unwanted events. Although generally harmless, firing too many events can cause significant performance problems, particularly if you trigger repainting in the GUI for properties that didn’t really change.

So you might want to do this:

public void setName(String name) {
  if (this.name != null || name != null) {
    changes.firePropertyChange("name", this.name, this.name = name);
  }
}

Or this, depending on your style:

public void setName(String name) {
  if (this.name == null && name == null) {
    return;
  }
  changes.firePropertyChange("name", this.name, this.name = name);
}

It’s a bit dense, but I like to use this pattern too. One benefit is that you can easily use your favourite IDE’s template mechanism to generate setters, because you don’t have to declare local variables.

And neither is correct since you don’t check that the new value is different from the old one (hence the property *change* listener).

@Kirill: A programmer does not need the check if the values are different. This is part of the implementation. E.g. for Objects:

public void firePropertyChange( String propertyName, Object oldValue, Object newValue )
{
if ( oldValue != null && newValue != null && oldValue.equals( newValue ) )
{
return;
}
firePropertyChange( new PropertyChangeEvent( source, propertyName, oldValue, newValue ) );
}

As a side note: It is very important to have a valid equals() method on Objects! So StringBuffer is a difficult one.

Eric Burke Says:

@Kirill, that’s really not correct. PropertyChangeSupport does this for you. If my code included comparisons between old and new value, that would actually degrade, rather than improve performance, because PropertyChangeSupport would then perform a redundant comparison.

My bad. I’m so used to the internal Swing code not using PropertyChangeSupport that i’ve missed that part.

Danno Ferrin Says:

No, there is a bug…

firePropertyChange(’propertyName’, null, null)

This will fire a non-change :(

–Danno

deans4j Says:

I think the most compact way is to use AOP to handle this problem : )

Casper Bang Says:

Yeah I use it all the time too. It doesn’t provide native property support but as a shorthand notation it’s great.

Danno Ferrin Says:

An even more elegant comparison to bumper the call with the direct comparison…

public void setName( name) {
if (this.name != name) changes.firePropertyChange(”name”, this.name, this.name = name);
}

This will handle the null/null case as well as the same-string case. The PropertyChangeSupport will handle the equivalent string case via a call to .equals(Object)

Paulo Says:

This is neat, i thought that methods first collected all the arguments references into an intermediary structure and called the method “atomically”. Is this specified by the Java Virtual Machine? Can it be JVM dependent?

On second thought even so this makes sense, since what is passes is a “reference”. Cool anyway.

Also i don’t think direct comparison will work for non final and non cached classes. Just IMNHO.

Paulo Says:

And classes that redefine the == operator. This means Strings and … BigInteger, Double …?

Paulo Says:

I must say that this project reCaptcha is very, very interesting. Finally a positive justification for spam.

Put down those pitchforks, i’m leaving.

Tim Says:

I made a quick post at my blog on how to automate adding these things in eclipse with this technique:

http://www.weheartcode.com/2008/04/29/easily-add-propertychangesupport-to-beans-in-eclipse/

Thasso Says:

I have written a small plugin taht you can use to generate bound getters/setters in eclipse.

http://java.randgestalten.de/?p=10