Synchronizing Properties with Beans Binding (JSR 295) Blog

Version 2



    Beans Binding is a Java platform library defined by Java Specification Request 295. JSR 295 is an open source project that tries to simplify how developers synchronize two properties, usually in two different objects. The JSR has a reference implementation available as the Beans Binding project on Additionally, NetBeans IDE 6 includes the latest release of the Beans Binding library, making it easy for NetBeans users to try out the new library.

    Of course, you can use the Beans Binding library regardless of your IDE. Download the reference implementation, compile the source, and package the Java Archive (JAR) file directly with your own projects. Alternatively, you can download compiled libraries with source and documentation packages from the host site. This article will show you how to get the reference implementation, include it in your projects, and use its libraries to connect and synchronize properties from different objects.

    Synchronization Without Beans Binding

    To appreciate the problem that Beans Binding tries to solve, you should first consider how developers usually synchronize two properties. AWT and Swing user interface components already have the ability to add event listeners, and they fire events when specific properties change values. However, when you create your own Java Bean components, you may have to create all those basic abilities yourself. In other words, depending on what type of bean you create, you may have to write your own methods to add event listeners, store those listeners, and fire property change events when necessary. You may also need to create new event listener interfaces and implement those as "glue" code that connects two or more components.

    Writing this glue code is often tedious. Programmers often duplicate this code to create change events and propagate them to listeners. In a large application, you might duplicate some of these same design patterns dozens or even hundreds of times. Fortunately, you can use thejava.beans.PropertyChangeSupport class to reduce the effort. However, to support custom beans and their properties, you still have to add the typical addSomePropertyListenerand removeSomePropertyListener methods to your beans.

    The following code sample shows a simplePersonWithPropertySupport class that provides its own property change support. The PropertyChangeSupportclass provides most of property support, as shown here:

    public class PersonWithPropertySupport { private String name; private int age; private PropertyChangeSupport props = new PropertyChangeSupport(this); public PersonWithPropertySupport() { } public PersonWithPropertySupport(String name, int age) { = name; this.age = age; } public void setName(String newName) { String oldName =; = newName; props.firePropertyChange("name", oldName, newName); } public String getName() { return name; } public void setAge(int newAge) { int oldAge = this.age; this.age = newAge; props.firePropertyChange("age", oldAge, newAge); } public int getAge() { return age; } public void addPropertyChangeListener(PropertyChangeListener l) { props.addPropertyChangeListener(l); } public void addPropertyChangeListener(String propName, PropertyChangeListener l) { props.addPropertyChangeListener(propName, l); } public void removePropertyChangeListener(PropertyChangeListener l) { props.removePropertyChangeListener(l); } public void removePropertyChangeListener(String propName, PropertyChangeListener l) { props.removePropertyChangeListener(propName, l); } }

    Note that the basic class is quite simple. A large portion of the code supports the registration of event listeners and the firing of appropriate events at the correct time. As classes and their relationships become more complex, the management of properties, change events, and event listeners can easily represent the majority of a bean's source code.

    The Beans Binding libraries help this situation by factoring out the common design patterns and activities involved in keeping properties synchronized. The new library helps you quickly connect properties from different objects, and even helps you avoid writing the same boilerplate code over and over again.

    Beans Binding Setup

    The Beans Binding API and libraries are available from the Beans Binding project. If you select the Documents & Files link on the page, you will see the the latest version of the source, documentation, and precompiled binaries, as seen in Figure 1. The project has reached version 1.2.1, and most of the API is stable at this point.

    Beans Binding hosted files.
    Figure 1. The Beans Binding project hosts the binaries, source, and documentation for the library

    Getting the prepackaged binaries and source bundles is convenient and easy. However, you can get the source code directly from the Subversion repository too. Access to the source repository requires a registered username on the project's website. If you have the Subversion tool in your shell's command path, the following command will check out a current version of the project:

    svn checkout beansbinding --username <username> 

    The project is Ant-based, so you will also need a current copy of the Ant build tool if you want to build the project yourself. Additionally, you should haveJava SE 5 or later. To build the JAR and Javadoc targets, use the following command:

    ant jar javadoc 

    You may also be able to use the project's Ant configuration files in your IDE. For example, you can access all the project's build targets from either the NetBeans IDE or Eclipse. Other IDEs should work as well.

    Once you have the library JAR file, you should include this file in your compiler and environment classpath. The technical notes for the Java SE Development Kit (JDK) have more information about the Java platform tools and utilities, including information about setting the classpath.

    The Beans Binding authors hope to include the API in a future version of the JDK. At this point, however, you must download the API separately. For now, the API has theorg.jdesktop.beansbinding package name, but expect that to change when the API becomes a standard addition to the JDK.


    The Beans Binding API defines an abstract Propertyclass. This Property class defines a uniform way to set or get a property value. A concrete Property class implementation lets you represent a specific property in a source object. All methods of this class require a sourceargument because the methods can access this same property across multiple different objects.

    The concrete implementations of this abstract class include the following:

    • org.jdesktop.beansbinding.ObjectProperty
    • org.jdesktop.beansbinding.BeanProperty
    • org.jdesktop.beansbinding.ELProperty

    An ObjectProperty instance represents an immutable, read-only property. A BeanProperty instance is useful for both readable and writable properties; it also provides support for change event listeners. An ELProperty instance allows you to create dynamic or synthetic properties using Expression Language (EL) syntax originating from the GlassFish project. Examples of this language will be provided later in this article.

    In the following example code, a simplified Personclass has name and age properties with the appropriate getter and setter methods that are typical of a Java Bean component. Notice that the class doesnot explicitly support bound properties and event listeners.

    public class Person { private String name; private int age; public Person() { } public Person(String name, int age ) { = name; this.age = age; } public void setName(String name) { = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } } 

    You can use the BeanProperty class to represent thename and age properties. Even though thePerson class doesn't directly provide support for bound properties, you can use the BeanProperty class to add that functionality. In the following example, thePersonPropertyTest class creates a Personobject and uses a BeanProperty instance to represent the age property. Additionally, the example shows how to add a property state listener for the age property. The PropertyStateListener andPropertyStateEvent classes are also part of the Beans Binding API.

    import org.jdesktop.beansbinding.*; public class PersonPropertyTest { private Person person; public PersonPropertyTest() { person = new Person("John", 21); } void run() { Property ageProperty = BeanProperty.create("age"); ageProperty.addPropertyStateListener(person, new PropertyStateListener() { public void propertyStateChanged(PropertyStateEvent pse) { Person p = (Person) pse.getSourceObject(); System.out.printf("Happy Birthday, %s! " + "You're %d years old.\n", p.getName(), p.getAge()); } }); for (int x = 35; x < 45; x++) { ageProperty.setValue(person, x); } } public static void main(String[] args) { PersonPropertyTest test = new PersonPropertyTest();; } } 

    Notice that the BeanProperty class has a staticcreate method. Use this create method to instantiate BeanProperty instances. You can now use this example's ageProperty variable to access anage property in any object that actually provides that property and conforms to the access method naming conventions for JavaBeans.

    A PropertyStateEvent object represents a change in property state for a specific object. APropertyStateListener defines the interface you should implement to receive notification of property state changes.

    The simple test application iterates through a range of integers and repeatedly updates the age property for a specificPerson instance. Fortunately, annual age updates for people in real life don't occur as rapidly. Each time the code calls the property's setValue method, the property state listener reports the new value:

    Happy Birthday, John! You're 35 years old. Happy Birthday, John! You're 36 years old. Happy Birthday, John! You're 37 years old. ... 

    The ELProperty class allows you to create properties using ELsyntax. The EL definition is part of the JavaServer Pages 2.1 specification. This language allows you to create more complex, synthetic properties even when those actual properties don't exist in a target object. For example, you can create a "middle-aged" property for the Person class using the following code and expression:

    ELProperty middleAgedProperty = ELProperty.create("${age > 45}"); 

    The middleAgedProperty variable now represents a Boolean property that is true whenever a bean's ageproperty is greater than 45. Of course, your definition of "middle age" may vary. The online American Heritage Dictionary of the English Language suggests that middle age is that period of life between ages 40 and 60. The Oxford English Dictionary claims this period of life starts at age 45. This author will take sides with the youthful British for this particular example.

    In order to fully use the ELProperty class, you must ensure that your Java Bean class supports property change listeners for all referenced properties in the expression. In this case, the expression uses the bean's age property to determine whether someone is middle-aged. Since theELProperty instance references the ageproperty, you must modify the Person class to support change listeners. The followingPersonWithPropertySupport class adds change listener support for both the name and ageproperties:

    import java.beans.*; public class PersonWithPropertySupport extends Person { private PropertyChangeSupport props = new PropertyChangeSupport(this); public PersonWithPropertySupport() { } public PersonWithPropertySupport(String name, int age) { super(name, age); } @Override public void setName(String newName) { String oldName = getName(); super.setName(newName); props.firePropertyChange("name", oldName, newName); } @Override public void setAge(int newAge) { int oldAge = getAge(); super.setAge(newAge); props.firePropertyChange("age", oldAge, newAge); } public void addPropertyChangeListener(PropertyChangeListener l) { props.addPropertyChangeListener(l); } public void addPropertyChangeListener(String propName, PropertyChangeListener l) { props.addPropertyChangeListener(propName, l); } public void removePropertyChangeListener(PropertyChangeListener l) { props.removePropertyChangeListener(l); } public void removePropertyChangeListener(String propName, PropertyChangeListener l) { props.removePropertyChangeListener(propName, l); } } 

    Now you can use the synthetic middleAgedProperty to determine when a person reaches middle age. The following code uses an ELProperty instance and a listener to alert you when a Person instance reaches "middle-aged" status:

    import org.jdesktop.beansbinding.*; public class PersonELPropertyTest { private Person person; private ELProperty middleAgedProperty; private BeanProperty ageProperty; public PersonELPropertyTest() { person = new PersonWithPropertySupport("John", 40); ageProperty = BeanProperty.create("age"); middleAgedProperty = ELProperty.create("${age > 45}"); } void run() { ageProperty.addPropertyStateListener(person, new PropertyStateListener() { public void propertyStateChanged(PropertyStateEvent pse) { Person p = (Person) pse.getSourceObject(); System.out.printf("%s is %d years old.\n", p.getName(), p.getAge()); } }); middleAgedProperty.addPropertyStateListener(person, new PropertyStateListener() { public void propertyStateChanged(PropertyStateEvent pse) { Person p = (Person) pse.getSourceObject(); System.out.printf("%s is middle-aged. Sigh...\n", p.getName()); } }); int age = person.getAge(); for (int x = age; x < age + 10; x++) { ageProperty.setValue(person, x); } } public static void main(String[] args) { PersonELPropertyTest test = new PersonELPropertyTest();; } } 

    The PersonELPropertyTest prints the following:

    ... John is 44 years old. John is 45 years old. John is middle-aged. Sigh... John is 46 years old. John is 47 years old. ... 

    The middleAgedProperty fires once in this example. Clearly, the property itself defines a booleansynthetic property that is true when a person's age is greater than 45. Why doesn't the property fire repeatedly as the age increments through 46, 47, and above? Although the property itself is true, the property state doesn't change after its initial change at age 45. The property becomes true at age 45 and remains true thereafter. Since the state doesn't change, no additional PropertyStateEvent objects are needed.


    To bind one property to another means that you synchronize the properties in some way: a change in one property affects the other. For an example, imagine that a slider component is connected to a colored panel so that changing the slider values will also change the panel's color tint. In other words, the slider's value and the panel's tint are synchronized. To create this binding yourself, you must ensure that both the slider and panel components listen and respond to the correct change events. You must create code that listens to changes in the slider and propagates those changes to the panel. Depending on the component, you might even create your own custom events, listener interfaces, and glue code between the components.

    The Beans Binding API simplifies this binding task. The following example demonstrates how to use the binding functionality to synchronize a Swing JSlider component's value with a custom TintedPanel component's background color. For simplicity, the only custom feature of the TintedPanelclass is a tint property. The TintedPanelclass has the typical getter and setter methods that are common for a bean. In this case, those methods are setTint andgetTint. The tint can range in values from 0 through 100, representing a color tint percentage. The demo configures the slider with values from 0 though 100 to represent percentage values. As you move the slider, the colored panel should change tint to match the slider setting. Figure 2 shows the panel and slider beans that are bound together.

    The colored panel tint
    Figure 2. The colored panel tint is synchronized to the slider value through the binding API

    This Tint Bind Demo contains two beans: a minimally customized TintedPanel component and an unmodifiedJSlider component. The TintedPanel code is shown here in part:

    public class TintedPanel extends javax.swing.JPanel { /** Creates new form TintedPanel */ public TintedPanel() { initComponents(); setTint(0); } public void setTint(int tint) { assert(tint >= 0 && tint <= 100); this.tint = tint; int colorValue = 255 - (tint*255/100); this.setBackground(new Color(colorValue, colorValue, 255)); } public int getTint() { return tint; } private void initComponents() { // ... } private int tint = 0; } 

    The following TintBindingTest class createsJSlider and TintedPanel instances and binds them. The code uses the BeanProperty.createmethod to create new properties. The Bindings class provides the factory method for creating a binding between the properties: tint and value. ThetintValue variable represents the panel'stint property. The slideValue represents the slider's value property.

    public class TintBindingTest extends javax.swing.JFrame { private Binding tintBinding; private Property slideValue; private Property tintValue; /** Creates new form TintBindingTest */ public TintBindingTest() { initComponents(); slideValue = BeanProperty.create("value"); tintValue = BeanProperty.create("tint"); tintBinding = Bindings.createAutoBinding(UpdateStrategy.READ, tintSlider, slideValue, tintedPanel, tintValue); tintBinding.bind(); tintSlider.setValue(0); } private void initComponents() { // ... ); public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new TintBindingTest().setVisible(true); } }); } private javax.swing.JSlider tintSlider; private com.joconner.bindingdemo.TintedPanel tintedPanel; } 

    When you create a binding between properties, you must associate an update strategy. The strategy will determine how the properties will synchronize. You have three choices:

    • UpdateStrategy.READ_ONCE
    • UpdateStrategy.READ
    • UpdateStrategy.READ_WRITE

    The READ_ONCE strategy tells the binding to update the target property only once. The READ strategy tells the binding to update the target whenever the source property changes. The READ_WRITE strategy tells the binding to update both properties when either changes.

    Binding Conversions

    Sometimes synchronized properties don't have matching types. Consider how you might synchronize a JToggleButton and a JLabel component. The button has aselected property that is a boolean. If you want to bind this property to the label'sbackground color, you will need to convert from one property type to another. Figure 3 shows these two components used as a simple light switch and a light bulb. The button represents the switch; the label represents the bulb.

    Figure 3. Sometimes you may have to convert property types in a binding

    The Converter Demo code shows how to bind these properties with a converter:

     public class ConverterDemo extends JFrame { JLabel lightBulb; JToggleButton lightSwitch; BindingGroup bindingGroup; Converter<Boolean, Color> converter; /** Creates new form ButtonBinding */ public ConverterDemo() { converter = new Converter<Boolean, Color>() { @Override public Color convertForward(Boolean isSelected) { return isSelected ? Color.YELLOW : Color.BLACK; } @Override public Boolean convertReverse(Color arg0) { return arg0 == Color.YELLOW; } }; initComponents(); } private void initComponents() { lightBulb = new javax.swing.JLabel(); lightSwitch = new javax.swing.JToggleButton(); bindingGroup = new BindingGroup(); Binding binding = Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, lightSwitch, ELProperty.create("${selected}"), lightBulb, BeanProperty.create("background")); binding.setConverter(converter); bindingGroup.addBinding(binding); bindingGroup.bind(); // ... } //... }

    As you can see in the anonymous inner class, you create aConverter by implementing the abstractConverter class. You will override two methods:

    • convertForward
    • convertReverse

    As you might imagine, the convertForward method will convert from a source property to a target property. TheconvertReverse method does the reverse; it converts from a target property to a source property. This demo class implements the two methods by converting to and from aColor type value and a Boolean type value. The Boolean value comes from the button'sselected property. The Color value comes from the label's background property.


    You can use the Beans Binding API to quickly and easily synchronize properties in different objects. The API allows you to add and remove property change listeners, create synthetic properties, and to even bind Swing components to database result sets.

    Sometimes your bindings must convert values from one type to another type. In that situation, you should implement a customConverter class to convert to and from dissimilar properties. By implementing your own Converter class, you allow a Binding instance to convert from one property type to another.

    Consider using the Beans Binding API in your next project. You may be able to save considerable time and effort binding and synchronizing properties between two different Java Bean components. The API allows you all the benefits of synchronized properties but minimizes the amount of code you write for event listening and propagation.


    The following resources will be helpful as you research and use this API: