Search code examples
javafxdata-bindingjavafx-bindings

JavaFX: Initial value of bidirectional binding


What happens when I do binding for these two properties?

ObjectProperty<Object> propertyA = new SimpleObjectProperty<>();
ObjectProperty<Object> propertyB = new SimpleObjectProperty<>();

propertyA.set(new ObjectA());
propertyB.set(new ObjectB());

Bindings.bindBidirectional(propertyA, propertyB);

If both properties are supposed to hold the same object reference, then after this binding, would both properties be holding the reference of ObjectA or ObjectB?


Solution

  • When you call:

    Bindings.bindBidirectional(propertyA, propertyB);
    

    The value of propertyA will be set to the value of propertyB.

    So in this case, as propertyB already refers to ObjectB, after the call, both properties will refer to: ObjectB

    Test Code

    import javafx.beans.binding.Bindings;
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    
    public class HellBound {
        public static void main(String[] args) {
            ObjectProperty<Object> propertyA = new SimpleObjectProperty<>();
            ObjectProperty<Object> propertyB = new SimpleObjectProperty<>();
    
            propertyA.set(new ObjectA());
            propertyB.set(new ObjectB());
    
            Bindings.bindBidirectional(propertyA, propertyB);
    
            System.out.println("propertyA = " + propertyA);
            System.out.println("propertyB = " + propertyB);
        }
    
        private static class ObjectA {
        }
    
        private static class ObjectB {
        }
    }
    

    Test Output

    propertyA = ObjectProperty [value: appCC.xyzzy.HellBound$ObjectB@7c3df479]
    propertyB = ObjectProperty [value: appCC.xyzzy.HellBound$ObjectB@7c3df479]
    

    Binding implementation source

    Note the call property1.setValue(property2.getValue());:

    public static <T> BidirectionalBinding bind(Property<T> property1, Property<T> property2) {
        checkParameters(property1, property2);
        final BidirectionalBinding binding =
                ((property1 instanceof DoubleProperty) && (property2 instanceof DoubleProperty)) ?
                        new BidirectionalDoubleBinding((DoubleProperty) property1, (DoubleProperty) property2)
                : ((property1 instanceof FloatProperty) && (property2 instanceof FloatProperty)) ?
                        new BidirectionalFloatBinding((FloatProperty) property1, (FloatProperty) property2)
                : ((property1 instanceof IntegerProperty) && (property2 instanceof IntegerProperty)) ?
                        new BidirectionalIntegerBinding((IntegerProperty) property1, (IntegerProperty) property2)
                : ((property1 instanceof LongProperty) && (property2 instanceof LongProperty)) ?
                        new BidirectionalLongBinding((LongProperty) property1, (LongProperty) property2)
                : ((property1 instanceof BooleanProperty) && (property2 instanceof BooleanProperty)) ?
                        new BidirectionalBooleanBinding((BooleanProperty) property1, (BooleanProperty) property2)
                : new TypedGenericBidirectionalBinding<T>(property1, property2);
        property1.setValue(property2.getValue());
        property1.addListener(binding);
        property2.addListener(binding);
        return binding;
    }
    

    Answers to additional questions

    I'm just wondering why the javadoc doesn't tell us this kind of useful information.

    Because the javadoc is written by humans and not gods. Sometimes humans make unfathomable omissions. Perhaps gods do too :-)

    I agree that it is useful info that should be in the Javadoc.

    A bug report could be filed to improve the doc (http://bugreport.java.com). Or a post to the openjfx-dev developer list might get a developer with commit privileges to improve it. You could submit a patch yourself, but, for most people, unless they are already a JDK committer who has signed the OCA, it's probably not worth it.

    I'm assuming this should also be the same for ObservableLists, such that Bindings.bindContentBidirectional() should work in the same way?

    Yeah, the source for that method has the following code:

    list1.setAll(list2);