Hi, We have come across a possible issue that affects bind() over different types of properties. We are not sure if it's a bug or it behaves as it should be. Therefore, we are reaching out to the community for insight.
See these short code snippets below: Snippet 1. StringProperty (could be other like IntegerProperty) StringProperty a = new SimpleStringProperty(); StringProperty b = new SimpleStringProperty(); StringProperty c = new SimpleStringProperty(); c.addListener((obs, ov, nv) -> System.out.println("Change: " + nv)); c.bind(a); c.bind(b); b.set("One"); System.out.println("c contains: " + c.get()); ==== Snippet 2. ListProperty ListProperty<String> a = new SimpleListProperty<>(FXCollections.<String>observableArrayList()); ListProperty<String> b = new SimpleListProperty<>(FXCollections.<String>observableArrayList()); ListProperty<String> c = new SimpleListProperty<>(); c.addListener((ListChangeListener.Change<? extends String> change) -> System.out.println("Change: " + change)); c.bind(a); c.bind(b); b.add("One"); b.add("Two"); System.out.println("c contains: " + Arrays.toString(c.toArray())); ==== While snippet 1 produces: Change: One c contains: One as expected, snippet 2 produces: Change: { [] added at 0 } c contains: [] But the expected result is: Change: { [] added at 0 } Change: { [] added at 0 } Change: { [One] added at 0 } Change: { [Two] added at 1 } c contains: [One, Two] This expected result only happens by manually doing: c.bind(a); c.unbind(); // need to explicitly unbind c.bind(b); Summing up: when binding a new observable to a bound property, unbind is required if that property is a ListProperty, but not a StringProperty (or IntegerProperty). Explanation In the ListProperty.bind implementation [1] there is a check, and only when both current bound observable and new observable are equal, unbind() is applied. The equals is implemented in ReadOnlyListProperty::equals [2] and, being a list, follows the List::equals[3] contract, therefore, it compares by items of the list. This is not the case when using other properties like StringPropertyBase or IntegerPropertyBase, where bind() is implemented in the same way [4], but equals now uses Object::equals[5], so the comparison is now done with ==, instead of comparing by the content of each property. Is this a bug? Should StringProperty, IntegerProperty override equals to compare by content and not by object, like ListProperty does? Should ListProperty use == operator instead of equals? This difference in behavior should be at least documented, shouldn't it? Thanks for any input on this, Jose [1] https://github.com/openjdk/jfx/blob/22d4343fe8563c2931910b98e8f18c6fd4a48f05/modules/javafx.base/src/main/java/javafx/beans/property/ListPropertyBase.java#L268 [2] https://github.com/openjdk/jfx/blob/22d4343fe8563c2931910b98e8f18c6fd4a48f05/modules/javafx.base/src/main/java/javafx/beans/property/ReadOnlyListProperty.java#L110 [3] https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/List.java#L542 [4] https://github.com/openjdk/jfx/blob/22d4343fe8563c2931910b98e8f18c6fd4a48f05/modules/javafx.base/src/main/java/javafx/beans/property/StringPropertyBase.java#L161 [5] https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Object.java#L150 --