On Fri, 14 May 2021 22:30:16 GMT, Michael Strauß <mstra...@openjdk.org> wrote:

>> The internal BidirectionalBinding class implements bidirectional bindings 
>> for JavaFX properties. The design intent of this class is to provide 
>> specializations for primitive value types to prevent boxing conversions (cf. 
>> specializations of the Property class with a similar design intent).
>> 
>> However, the primitive BidirectionalBinding implementations do not meet the 
>> design goal of preventing boxing conversions, because they implement 
>> ChangeListener.
>> 
>> ChangeListener is a generic SAM interface, which makes it impossibe to 
>> invoke an implementation of ChangeListener::changed with a primitive value 
>> (i.e. any primitive value will be auto-boxed).
>> 
>> The boxing conversion happens, as with all ChangeListeners, at the 
>> invocation site (for example, in ExpressionHelper). Since the boxing 
>> conversion has already happened by the time any of the BidirectionalBinding 
>> implementations is invoked, there's no point in using primitive 
>> specializations of BidirectionalBinding after the fact.
>> 
>> This issue can be solved by having BidirectionalBinding implement 
>> InvalidationListener instead, which by itself does not incur a boxing 
>> conversion. Because bidirectional bindings are eagerly evaluated, the 
>> observable behavior remains the same.
>> 
>> I've filed a bug report with the same title.
>
> Michael Strauß has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   added missing oldValue assignments

modules/javafx.base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java
 line 157:

> 155: 
> 156:         property1.setValue((T)property2.getValue());
> 157:         property1.addListener(binding);

About lines 156-158:

        property1.setValue(property2.getValue());
        property1.addListener(binding);
        property2.addListener(binding);

The bindings added do not validate the properties anymore as it is an 
invalidation listener now instead of a change listener.  This doesn't matter 
for `property2` as its `getValue` is called which will force its revalidation, 
but for `property1` this is not the case.  This small program demonstrates this:

    SimpleDoubleProperty p = new SimpleDoubleProperty(2);

    InvalidationListener invalidationListener = obs -> 
System.out.println("Invalidated");

    p.addListener(invalidationListener);

    p.setValue(3);
    p.setValue(4);

The program as expected only prints `invalidated` once.

-------------

PR: https://git.openjdk.java.net/jfx/pull/454

Reply via email to