How to Create a Read-Only Property in JavaFX - dummies

How to Create a Read-Only Property in JavaFX

By Doug Lowe

Although in JavaFX a read-only property has less functionality than a read/write property, it’s actually more complicated to implement. Why? Because internally — within the class that contains the read-only property — you need to be able to read or write the value of the property. But externally — that is, outside of the class that defines the read-only property — you must ensure that users can read but not write the property value.

You might think that omitting the setter method would be enough to create a read-only property. But the problem is that in addition to getter and setter methods, JavaFX properties also expose a property accessor method that provides direct access to the property object itself.

The following is an example of how not to create a read-only property:

StringProperty firstName = 
    new SimpleStringProperty(this,
        "firstName", ");
public final String getFirstName()
{
    return firstName.get();
}
public final StringProperty firstNameProperty()
{
    return firstName;
}

This code is the same as the code used to create a read/write property, except that it omitted the setFirstName method. Unfortunately, this property definition does not prevent users of the class that defines the property from modifying the property. To do so, all the user would need to do is access the property and then call the property’s set method directly.

For example, suppose this property is part of a class named Customer, an instance of which is referenced by the variable cust. The following code would set the value of the read-only property:

cust.getFirstName().set("Bogus Value");

To safely create a read-only property, you must actually create two copies of the property: a read-only version and a read/write version. The read-only version will be exposed to the outside world.

The read/write version will be used internally, within the class that defines the property. Then, you must synchronize these two properties so that whenever the value of the internal read/write property changes, the value of the external read-only property is updated automatically.

To accomplish this, JavaFX provides two additional classes for each property data type: a read-only property class and a read-only wrapper class. The read-only property class is the one you share with the outside world via the property accessor method. The read-only wrapper class is the one you use to create the private field used to reference the property within the program.

Here’s a complete example that implements a read-only integer property named customerNumber in a class named Customer:

public class Customer
{
    ReadOnlyIntegerWrapper customerNumber = 
        new ReadOnlyIntegerWrapper(this,
            "customerNumber", 0);
    public final Integer getCustomerNumber()
    {
        return customerNumber.get();
    }
    public final ReadOnlyIntegerProperty()
        customerNumberProperty()
    {
        return customerNumber.getReadOnlyProperty();
    }
    // more class details go here
}

The key to understanding how this works is realizing that the read-only wrapper class is an extension of the simple property class which adds just one new method: getReadOnlyProperty, which returns a read-only copy of the simple property. This read-only copy is automatically synchronized with the simple property, so that whenever a change is made to the underlying simple property, the value of the read-only property will be changed as well.