Creating read-only properties in JavaFX

The JavaFX runtime provides two possibilities to create read-only properties. You can either use a wrapper (e.g. ReadOnlyDoubleWrapper) or you can extend an abstract base class (e.g. ReadOnlyDoublePropertyBase). This article shows how these two approaches can be implemented.

In this example we want to create a read-only property “size” of type double. According to the convention, we have to implement the following two methods in the class that contains the property:

public final double getSize();
public final ReadOnlyDoubleProperty sizeProperty();

Listing 1: The “interface” of a read-only property

One might be tempted to create a regular DoubleProperty and return that in sizeProperty(). Never do this! Although DoubleProperty extends ReadOnlyDoubleProperty and the compiler would not complain, this creates a serious security issue. Malicious code can simply cast the returned read-only property back to a DoubleProperty and change the value.

Instead you can use one of the following two approaches.

Using a Wrapper

If you create a wrapper, two properties are created, which are synchronized (see Fig. 1). One of the properties is writable, the other one is read-only. The writable property should only be used internally. You have to make sure, that it never escapes your internal implementation. The read-only property is passed to the outside world. Every time you change the writable property from your internal components, the read-only property is updated.

Concept of a Wrapper for read-only Properties
Concept of a Wrapper for read-only Properties

This approach gives you internally the full functionality of a regular property. Especially you can bind it to other observable values. At the same time there is no way for the outside world to change the value of the property.

The size property can be implemented like this:

private final ReadOnlyDoubleWrapper size = new ReadOnlyDoubleWrapper();

public final double getSize() {
    return size.get();
}

public final ReadOnlyDoubleProperty sizeProperty() {
    return size.getReadOnlyProperty();
}

Listing 2: Implementing a read-only property with a wrapper

It is important to make sure, that you return size.getReadOnlyProperty() in the second method. If you forget to call getReadOnlyProperty() and return size directly, a developer can cast size to DoubleProperty and access the value.

Using a Base Class

Using a wrapper is simple, but it has one major drawback. In memory two property objects are created. They share some of the internal state, but still… Extending a base class on the other hand requires some more work on your part, but it uses less memory. The concept can be seen in Fig. 2. For a base class to work, two pieces of functionality have to be implemented. The base class needs to know how to get the current value of the property and it needs to be notified, when that value changes.

Concept of a Base Class for read-only Properties
Concept of a Base Class for read-only Properties

Getting the current value is done by implementing the abstract getter of the base class. It is notified about a change by calling the method fireValueChangedEvent(). Here is an example of how the size property can be implemented with a base class:

private class SizeClass extends ReadOnlyDoublePropertyBase {

    private double size;

    @Override
    public final double get() {
        return size;
    }

    private void set(double newValue) {
        size = newValue;
        fireValueChangedEvent();
    }

    @Override
    public Object getBean() {
        return OuterClass.this;
    }

    @Override
    public String getName() {
        return "size";
    }
}

private SizeClass size = new SizeClass();

public final double getSize() {
    return size.get();
}

public final ReadOnlyDoubleProperty sizeProperty() {
    return size;
}

Listing 3: Implementing a read-only property extending a base class

SizeClass looks like a regular property, it has a getter and a setter. But the setter is private, you can only access it from the enclosing class and it can safely be passed to the outside world.

Conclusion

If you create read-only properties in your own code, make sure that the object you pass out is really a read-only property. The simplest way to do this is to use the approaches provided by the JavaFX runtime, either by using a wrapper or by extending a base class.

4 responses to “Creating read-only properties in JavaFX”

  1. SebastienBordes Avatar

    Thank you to show us the second approach because in some case performances really matter !!

  2. […] Michael Heinrichs has blogged about creating read-only properties in JavaFX. […]

  3. Ilias Tsagklis Avatar

    Hi Michael,

    Nice blog! Is there an email address I can contact you in private?

    1. Mike Avatar

      Hi Ilias,

      thanks! Always glad to hear when people like my blog.

      I was not aware that my mail address is not visible. Will fix it as soon as I am back from my vacation. It is: michael at netopyr.com.

      – Michael