Re-examine the risks of JDK-8264770 breaking third party libraries and applications.
John Hendrikx
hjohn at xs4all.nl
Sat Aug 28 21:00:54 UTC 2021
This actually isn't an issue because adding an invalidation listener
revalidates the property as well (I'm not sure why, but I noticed this
before while working on fluent bindings).
However, there is another issue. When I recreate a bidirectional with
two invalidation listeners with special logic to ignore my own
invalidation listener triggering again when the other property gets
updated.
When you include this logic (using the "updating" field in the current
code) in combination with invalidation listeners, the field that was
just updated does NOT get revalidated. Any further changes to that
field will therefore not trigger an invalidation event and the
bidirectional nature of the binding breaks.
Try this example:
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.stage.Stage;
public class TestBug8264770 extends Application {
public static void main(String[] args) {
Application.launch(args);
}
static SimpleDoubleProperty p1 = new SimpleDoubleProperty(2);
static SimpleDoubleProperty p2 = new SimpleDoubleProperty(3);
@Override
public void start(Stage stage) throws Exception {
InvalidationListener invalidationListener = obs -> invalidated(obs);
p1.addListener(invalidationListener);
p2.addListener(invalidationListener);
p1.setValue(4);
p2.setValue(5);
// Prints p1 = 4.0 (!!)
System.out.println("Expect p1 to be 5, but was: " + p1.getValue());
}
private boolean updating = false;
private void invalidated(Observable source) {
if (!updating) {
try {
updating = true;
if(source == p1) {
System.out.println("Setting p2 to " + p1.get());
p2.set(p1.get());
}
else {
System.out.println("Setting p1 to " + p2.get());
p1.set(p2.get());
}
}
finally {
updating = false;
}
}
}
}
--John
On 28/08/2021 22:14, John Hendrikx wrote:
> Was it taken into account that when you register an invalidation listener:
>
> property1.setValue(property2.getValue());
> property1.addListener(binding);
> property2.addListener(binding);
>
> ... that if property2 is currently invalid it will not send any further
> invalidations?
>
> Property1 is revalidated (because of the getValue call), but property2
> (if already invalid) will not become valid with that setValue call.
>
> Before when they were ChangeListeners, both properties became valid
> after a bidirectional binding, now that doesn't seem to be the case
> anymore.
>
> --John
>
>
> On 26/08/2021 09:29, Frederic Thevenet wrote:
>> Hi,
>>
>> A change was introduced In JDK-8264770 that swaps the use of
>> ChangeListeners to InvalidationListeners within the internal
>> implementation of BidirectionalBinding [1].
>>
>> While this change shouldn't normally affect third party applications, it
>> turned out to break the scrolling facilities used by the widely used
>> rich text widget RichTextFX [2].
>>
>> After a short investigation, I believe the root cause lies within
>> another library by the same author called ReactFX [3], which aims to
>> bring reactive programming techniques to JavaFX; in order to do so it
>> seems to expands on but also sometime overrides the built-in bindings
>> and events mechanisms.
>>
>> Now, I do believe that this is probably an exceptional case, and it is
>> also quite possible that it is the result of an unsafe/incorrect use of
>> internal implementations by the third party library, but with that said
>> I can't help but feeling a bit nervous about the wider implications of
>> that change with regard to compatibility of existing apps and OpenJFX
>> 17. At the very least I believe it is important to raise awareness about
>> potential compatibility issues among the community.
>>
>> For your information, I reached out to the maintainers of RichTextFX and
>> proposed a workaround (replacing the use of a bidirectional binding by a
>> pair of explicit ChangeListeners), which, while not very elegant, seems
>> to fix the particular issue I discovered [4], but unfortunately it seems
>> development on the underlying ReactFX is no longer active (last commit
>> in 2016).
>>
>> -- Fred
>>
>> [1] https://bugs.openjdk.java.net/browse/JDK-8264770
>>
>> [2] https://github.com/FXMisc/RichTextFX
>>
>> [3] https://github.com/ReactFX/reactfx.github.io
>>
>> [4] https://github.com/FXMisc/Flowless/issues/97
>>
>
More information about the openjfx-dev
mailing list