Skip to content

Commit 35880ce

Browse files
committedMay 7, 2024
8331616: ChangeListener is not triggered when the InvalidationListener is removed
Reviewed-by: mstrauss, kcr
1 parent 36e65e8 commit 35880ce

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed
 

‎modules/javafx.base/src/main/java/com/sun/javafx/binding/ExpressionHelper.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,22 @@ protected void fireValueChangedEvent() {
355355

356356
try {
357357
locked = true;
358+
359+
final T oldValue = currentValue;
360+
361+
if (curChangeSize > 0) {
362+
363+
/*
364+
* Because invalidation listeners may get removed during notification, this may
365+
* change the Helper type from Generic to SingleChange. When this transition
366+
* occurs, it is essential the correct current value is passed to the new
367+
* SingleChange instance. This is why the currentValue is already obtained
368+
* before notifying the invalidation listeners.
369+
*/
370+
371+
currentValue = observable.getValue();
372+
}
373+
358374
for (int i = 0; i < curInvalidationSize; i++) {
359375
try {
360376
curInvalidationList[i].invalidated(observable);
@@ -363,8 +379,6 @@ protected void fireValueChangedEvent() {
363379
}
364380
}
365381
if (curChangeSize > 0) {
366-
final T oldValue = currentValue;
367-
currentValue = observable.getValue();
368382
final boolean changed = (currentValue == null)? (oldValue != null) : !currentValue.equals(oldValue);
369383
if (changed) {
370384
for (int i = 0; i < curChangeSize; i++) {

‎modules/javafx.base/src/test/java/test/com/sun/javafx/binding/ExpressionHelperTest.java

+51-1
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ public void shouldNotForgetCurrentValueWhenMovingFromGenericToSingleChangeImplem
682682
StringProperty p = new SimpleStringProperty("a") {
683683
@Override
684684
protected void invalidated() {
685-
removeListener(invalidationListener);
685+
removeListener(invalidationListener); // this removal occurs before notification
686686
}
687687
};
688688

@@ -693,6 +693,56 @@ protected void invalidated() {
693693

694694
assertFalse(invalidated.get()); // false because the invalidation listener was removed before called
695695
assertEquals("b", currentValue.get());
696+
697+
p.set("a"); // if current value wasn't copied correctly (it is still "a") then this wouldn't trigger a change
698+
699+
assertEquals("a", currentValue.get());
700+
}
701+
702+
@Test
703+
public void shouldNotForgetCurrentValueWhenMovingFromChangeListenerAndInvalidationListenerToSingleChangeListener() {
704+
AtomicReference<String> currentValue = new AtomicReference<>();
705+
StringProperty p = new SimpleStringProperty("a");
706+
InvalidationListener invalidationListener = new InvalidationListener() {
707+
@Override
708+
public void invalidated(Observable obs) {
709+
p.removeListener(this); // this removal occurs during notification
710+
}
711+
};
712+
713+
p.addListener(invalidationListener);
714+
p.addListener((obs, old, current) -> currentValue.set(current));
715+
716+
p.set("b");
717+
718+
assertEquals("b", currentValue.get());
719+
720+
p.set("a"); // if current value wasn't copied correctly (it is still "a") then this wouldn't trigger a change
721+
722+
assertEquals("a", currentValue.get());
723+
}
724+
725+
@Test
726+
public void shouldNotForgetCurrentValueWhenMovingFromTwoChangeListenersToSingleChangeListener() {
727+
AtomicReference<String> currentValue = new AtomicReference<>();
728+
StringProperty p = new SimpleStringProperty("a");
729+
ChangeListener<String> changeListener = new ChangeListener<>() {
730+
@Override
731+
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
732+
p.removeListener(this);
733+
}
734+
};
735+
736+
p.addListener(changeListener);
737+
p.addListener((obs, old, current) -> currentValue.set(current));
738+
739+
p.set("b");
740+
741+
assertEquals("b", currentValue.get());
742+
743+
p.set("a"); // if current value wasn't copied correctly (it is still "a") then this wouldn't trigger a change
744+
745+
assertEquals("a", currentValue.get());
696746
}
697747

698748
@Test

0 commit comments

Comments
 (0)
Please sign in to comment.