Upcoming property changes

This week I pushed the last two major changes in the JavaFX properties implementation, that were planned for this release. These changes may easily be overlooked, because the public API changes only slightly, but the possibilities they enable are way cool, I think, and I am very excited about them. Here is what you can expect in the upcoming beta drop.

Introducing Observable

This is one of those changes that seem so obvious once you do them, that you wonder why it took you so long to notice it. What it basically does, is to separate observability from all other functionality. What we have right now are ObservableValue, ObservableList, and ObservableMap. Plus in a later release we plan to introduce ObservableSet. All of these classes are observable, but all of them also define additional functionality the other classes do not offer and they do not have a common ancestor. As I said, when you look at it now, it just seems obvious, that a common interface is needed to describe the similarities. And that is what the new interface Observable does.

The interface Observable “steals” two methods to add and remove InvalidationListeners from ObservableValue. The full interface looks like this:

public interface Observable {
    public void addListener(InvalidationListener listener);
    public void removeListener(InvalidationListener listener);
}

The ChangeListeners were left in the current interfaces, because they differ, and extracting the common functionality would have made things much more complicated without adding much value. As a consequence of moving these methods to Observable, the definition of InvalidationListener has changed, too. The source passed to the invalidated method is now an Observable and InvalidationListener is not generic anymore. Here is the new definition:

public interface InvalidationListener {
    public void invalidated(Observable observable);
}

The change in InvalidationListener is very important to note, because it is an incompatible change. If you defined an InvalidationListener somewhere, your code will be broken once you switch to the new version and you need to update it.

The cool thing about this change is, that you can now observe lists, map, and simple values with the same code block. The first usage (and the main driver for this change) are dependencies in Bindings. All bindings accept Observable now as their dependency, in other words you can use ObservableList, ObservableMap, and your own implementations of Observable as a dependency in bindings now.

Here is a practical example of what is possible now. The following class defines an IntegerBinding, that contains the size of an ObservableList. And this IntegerBinding can be used in more complex binding expressions, e.g. IntegerBinding listSize = new ObservableListSize(list); Bindings.when(listSize.lessThan(100)).then(…).otherwise(…).

public class ObservableListSize extends IntegerBinding {
    private final ObservableList<?> list;
    public ObservableListSize(ObservableList<?> list) {
        this.list = list;
        bind(list);
    }
    @Override
 protected int computeValue() {
        return list.size();
    }
}

Another example with a map. An instance of this class contains the mapping of a given key.

public class MappedValue<K, V> extends ObjectBinding<V> {
    private final ObservableMap<?, V> map;
    private final Object key;
    public MappedValue<V> (ObservableMap<K, V>, K key) {
        this.map = map;
        this.key = key;
        bind(map);
    }

    @Override
    protected V computeValue() {
        return map.get(key);
    }
}

One could extend this example to use an ObservabeValue<K> for the key, which would allow to observe the map and the key for changes. And there are many more possibilities. I plan to add a bunch of these classes into the standard library, but unfortunately not in this release. You can track this feature request in JIRA. Certainly you are most welcome to add your own ideas.

Reorder Property Hierarchy

The second change does not have major immediate effects, but I believe, it will make everybody happy who is concerned about the dynamic footprint of our properties. I will use BooleanProperty here as an example, the same changes were applied to the other properties, too.

At the top of the hierarchy is BooleanProperty, which is a new abstract class. It defines all methods of a BooleanProperty, but it does not contain any fields. This provides you with much more flexibility, if you want to write your own implementation of properties. Most importantly, it does not force any kind of memory usage upon, which allows to optimize for minimal footprint.

The class SimpleBooleanProperty is a full implementation of BooleanProperty. If you just want a property without any special functionality, this is the class you will want to instantiate.

There is a third class BooleanPropertyBase which is somewhere between BooleanProperty and SimpleBooleanProperty. It is a full implementation of BooleanProperty, except for the getName() and getBean() methods. This class is most useful, if you want the basic functionality, but slightly extend it. I will write about this class more in another blog post.

10 responses to “Upcoming property changes”

  1. Osvaldo Doederlein Avatar

    Does the last item mean that property declarations will become even more verbose, i.e. “new SimpleBooleanProperty”? Verbosity is already a major complain from some critics of JavaFX 2.0’s properties… maybe we could go with terse class names at least for the most common types, e.g. “PBoolean” would be basically as short as current Java code.

    I have some mixed feelings about the split of BooleanProperty / SimpleBooleanProperty. For one thing, it spoils the above suggestion a bit, because I would want to instantiate my PBoolean but not use its as the declaration type, so I’d suck the verbose BooleanProperty anyway. Second reason, if I want to keep my code clean in that respect (using the higher-level, interface-like type in declaration when possible), now I have two types to import instead of one. A trivial FX model class that uses a handful of property types will need half a page of imports (as wildcard import is evil and forbidden any decent style…). One (Eclipse-inspired) idea would be IBoolean for the high-level type, but in this case it’s not an interface (well, at least we don’t have the horrendous ‘Abstract’ prefixes that some frameworks insist to put in every single abstract class…).

    The second problem is the polymorphism in all get/set operations for the vastly-dominant case of using the stock SimpleBooleanProperty. We already have this cost in the current design as the get/set methods are not final; but adding class hierarchy complexity may add yet another grain of sand to the JIT’s work (CHA, devirtualization…). These optimizations are never free, they have costs like guard code in each call site, risk of failure in some important megamorphic sites (always inside reusable libraries), warmup time, mobile/embedded platforms with weaker JIT, etc. Well maybe I’m worrying too much because properties already have other significant overheads (even with tricks like caching / lazy allocation) so the above will not add significantly to it…

    1. Mike Avatar

      Osvaldo Doederlein,

      thank you very much for your input. I always enjoy to challenge design decisions we made. If the length of the names and the number of import statements are the major issues, the whole design cannot be too bad. 😉

      Verbosity in code is a bad thing and should be avoided. But longer code is not automatically more verbose, if the additional information seems necessary. At which point code becomes verbose is a matter of personal taste IMO.

      With the upcoming API, a boolean property can be defined like this:
      BooleanProperty foo = new SimpleBooleanProperty();
      If I understand your suggestion correctly, you would prefer:
      IBoolean foo = new PBoolean();

      The JavaFX statement is certainly longer, but is it also more verbose? I think not, because the additional information adds value. Somebody, who deals with properties on a daily base, may prefer the short syntax, but for the occasional viewer, the JavaFX statement is much easier to understand IMO.

      I see your point about polymorphism being an issue in all get/set operations, though I think having the possibility to provide your own implementation of properties far outweighs the costs you mentioned. For example in the runtime we were able to reduce memory footprint significantly by using specialized property implementations.

  2. […] Michael Heinrichs, an engineer in the JavaFX team at Oracle, has blogged about upcoming changes to the properties API. […]

  3. […] Michael Heinrichs, an engineer in the JavaFX team at Oracle, has blogged about upcoming changes to the properties API. […]

  4. Tbee Avatar
    Tbee

    Is there also a “Property” interface, which defines all common methods of a property, e.g.:
    – set / get
    – Observable

    1. Mike Avatar

      TBee,

      there is javafx.beans.property.Property, which defines get/set, adding InvalidationListeners and ChangeListeners, plus it even defines the methods needed to bind unidirectional and bidirectional.

  5. Cowra Avatar
    Cowra

    In JavaFX 1.x script, we can do that:

    public var frequency = .05s on replace {
    emitTimeline.playFromStart();
    }

    //specifies when a new particle should be added to the scene
    var emitTimeline = Timeline{
    repeatCount: Timeline.INDEFINITE;
    keyFrames: KeyFrame{
    time: bind frequency;
    action: emit
    }
    }

    But, it seems like we can only do that by JavaFX 2.0 API:

    ……
    emitTimeline = new Timeline();
    emitTimeline.setCycleCount(Timeline.INDEFINITE);
    KeyFrame emitKeyFrame = new KeyFrame(Duration.millis(50), new EventHandler(){
    @Override
    public void handle(ActionEvent ae) {
    emit();
    }
    });
    emitTimeline.getKeyFrames().add(emitKeyFrame);
    ……
    frequencySlider.setMin(10.0);
    frequencySlider.setMax(500.0);
    frequencySlider.valueProperty().addListener(new ChangeListener(){
    @Override
    public void changed(ObservableValue observable,
    Number oldValue, Number newValue) {
    emitTimeline.setRate(50 / newValue.doubleValue());
    }

    });

    But, I think this is a clumsy approach, just like the traditional Swing style. Now that JavaFX 1.x script can using binding solution, why can’t JavaFX 2.0 API ?

    Would you please give me an elegant binding solution to dynamically alter the duration of a KeyFame?

    1. Mike Avatar

      The animation classes were very flexible in JavaFX 1.x – too flexible as it turned out. The underlying implementation was extremely difficult and contained many errors when you pushed it to the limits. For a lot of cases, the correct behavior was undefined, often it was not even clear what consistent behavior would mean.

      To be able to deal with this and provide a consistent and stable library, we took a radical approach. We went through the API and looked for places where we could reduce functionality to make the API more consistent overall and simplify the implementation. Our goal was to remove rarely used functionality that imposed huge complexity on the library. One of the results was to make KeyValue and KeyFrame immutable. Instances of these classes were rarely changed, but their mutability caused a lot of pain.

      Your JavaFX Script is now one of these rare cases, where a KeyFrame is changed. Unfortunately you cannot do that anymore. But there are other possibilities:

      1) I like your idea to change the rate of the Timeline instead. You can do that in a binding, instead of attaching a listener to the frequencySlider. The binding would look something like this:
      emitTimeline.rateProperty().bind(Bindings.divide(50.0, frequencySlider.valueProperty());

      2) The reason your case is not so well supported is, that the Timeline class is actually not intended for this kind of usage. The main purpose of Timeline is to change properties over a period of time. You are kind of “misusing” Timeline to define a timer. Maybe it is simpler to use a java.util.Timer instead. Just be careful with the threading, because Timer does not run on the JavaFX Application thread. You can use Platform.runLater() to get back on the JavaFX Application thread.

      3) Extend the AnimationTimer class. It is called in every frame. (There is a feature request to allow changing the frequency, but this will not be implemented in the 2.0 release.) Until then you have to do the comparison with the target frequency yourself. If you define it as a JavaFX Property (e.g. javafx.beans.property.DoubleProperty), you can bind it the same way you did it in the JavaFX Script.

      I hope that helps. Please let me know, if you have any more questions.

  6. Peter Avatar
    Peter

    Hi Michael,

    thanks for that informative post. Somewhat OT, but do you have some more information on how to bind non-String typed properties to e.g. a TextField? I can’t find any information on converters or validators in the Java FX 2 documentation, so how would one implement this sort of binding?

    Thanks,

    –Peter

    1. Mike Avatar

      Hi Peter,

      I assume you mean a bidirectional binding, right? For bidirectional bindings there is nothing available yet. Such classes are planned, but for now you have to implement them yourself. One possibility is to attach a listener to both properties, that synchronizes them. An interesting topic to blog about. 🙂

      – Michael