changeset 2815:7fa12f6c2e16

RT-28537 Bidirectional Binding does not maintain the invariant if one of the properties is bound
author Martin Sladecek <martin.sladecek@oracle.com>
date Wed, 06 Mar 2013 13:08:40 +0100
parents dd17e3699d72
children 3ec5209e2c07
files javafx-beans/src/com/sun/javafx/binding/BidirectionalBinding.java javafx-beans/test/com/sun/javafx/binding/BidirectionalBindingTest.java
diffstat 2 files changed, 90 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-beans/src/com/sun/javafx/binding/BidirectionalBinding.java	Wed Mar 06 12:48:54 2013 +0100
+++ b/javafx-beans/src/com/sun/javafx/binding/BidirectionalBinding.java	Wed Mar 06 13:08:40 2013 +0100
@@ -235,11 +235,19 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(sourceProperty)) {
+                        if (property1 == sourceProperty) {
                             property2.set(newValue);
                         } else {
                             property1.set(newValue);
                         }
+                    } catch (RuntimeException e) {
+                        if (property1 == sourceProperty) {
+                            property1.set(oldValue);
+                        } else {
+                            property2.set(oldValue);
+                        }
+                        throw new RuntimeException(
+                                "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
                         updating = false;
                     }
@@ -284,11 +292,19 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(sourceProperty)) {
+                        if (property1 == sourceProperty) {
                             property2.set(newValue.doubleValue());
                         } else {
                             property1.set(newValue.doubleValue());
                         }
+                    } catch (RuntimeException e) {
+                        if (property1 == sourceProperty) {
+                            property1.set(oldValue.doubleValue());
+                        } else {
+                            property2.set(oldValue.doubleValue());
+                        }
+                        throw new RuntimeException(
+                                        "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
                         updating = false;
                     }
@@ -333,11 +349,19 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(sourceProperty)) {
+                        if (property1 == sourceProperty) {
                             property2.set(newValue.floatValue());
                         } else {
                             property1.set(newValue.floatValue());
                         }
+                    } catch (RuntimeException e) {
+                        if (property1 == sourceProperty) {
+                            property1.set(oldValue.floatValue());
+                        } else {
+                            property2.set(oldValue.floatValue());
+                        }
+                        throw new RuntimeException(
+                                "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
                         updating = false;
                     }
@@ -382,11 +406,19 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(sourceProperty)) {
+                        if (property1 == sourceProperty) {
                             property2.set(newValue.intValue());
                         } else {
                             property1.set(newValue.intValue());
                         }
+                    } catch (RuntimeException e) {
+                        if (property1 == sourceProperty) {
+                            property1.set(oldValue.intValue());
+                        } else {
+                            property2.set(oldValue.intValue());
+                        }
+                        throw new RuntimeException(
+                                        "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
                         updating = false;
                     }
@@ -431,11 +463,19 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(sourceProperty)) {
+                        if (property1 == sourceProperty) {
                             property2.set(newValue.longValue());
                         } else {
                             property1.set(newValue.longValue());
                         }
+                    } catch (RuntimeException e) {
+                        if (property1 == sourceProperty) {
+                            property1.set(oldValue.longValue());
+                        } else {
+                            property2.set(oldValue.longValue());
+                        }
+                        throw new RuntimeException(
+                                "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
                         updating = false;
                     }
@@ -480,11 +520,19 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(sourceProperty)) {
-                            property2.setValue(property1.getValue());
+                        if (property1 == sourceProperty) {
+                            property2.setValue(newValue);
                         } else {
-                            property1.setValue(property2.getValue());
+                            property1.setValue(newValue);
                         }
+                    } catch (RuntimeException e) {
+                        if (property1 == sourceProperty) {
+                            property1.setValue(oldValue);
+                        } else {
+                            property2.setValue(oldValue);
+                        }
+                        throw new RuntimeException(
+                                "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
                         updating = false;
                     }
@@ -529,11 +577,19 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(sourceProperty)) {
-                            property2.setValue(property1.getValue());
+                        if (property1 == sourceProperty) {
+                            property2.setValue(newValue);
                         } else {
-                            property1.setValue((T)property2.getValue());
+                            property1.setValue((T)newValue);
                         }
+                    } catch (RuntimeException e) {
+                        if (property1 == sourceProperty) {
+                            property1.setValue((T)oldValue);
+                        } else {
+                            property2.setValue(oldValue);
+                        }
+                        throw new RuntimeException(
+                                        "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
                         updating = false;
                     }
@@ -610,7 +666,7 @@
                 } else {
                     try {
                         updating = true;
-                        if (property1.equals(observable)) {
+                        if (property1 == observable) {
                             try {
                                 property2.setValue(fromString(property1.getValue()));
                             } catch (Exception e) {
--- a/javafx-beans/test/com/sun/javafx/binding/BidirectionalBindingTest.java	Wed Mar 06 12:48:54 2013 +0100
+++ b/javafx-beans/test/com/sun/javafx/binding/BidirectionalBindingTest.java	Wed Mar 06 13:08:40 2013 +0100
@@ -38,6 +38,8 @@
 import java.util.Collection;
 
 import static org.junit.Assert.*;
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
 
 @RunWith(Parameterized.class)
 public class BidirectionalBindingTest<T> {
@@ -55,6 +57,9 @@
 
     private final Functions<T> func;
     private final T[] v;
+    
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
 
     private PropertyMock<T> op1;
     private PropertyMock<T> op2;
@@ -254,7 +259,23 @@
 	public void testUnbind_X_Self() {
 		func.unbind(op1, op1);
 	}
-	
+        
+        @Test
+        public void testBrokenBind() {
+            func.bind(op1, op2);
+            op1.bind(op3);
+            assertEquals(op3.getValue(), op1.getValue());
+            assertEquals(op2.getValue(), op1.getValue());
+            
+            thrown.expect(RuntimeException.class);
+            try {
+                op2.setValue(v[2]);
+            } finally {
+                assertEquals(op3.getValue(), op1.getValue());
+                assertEquals(op2.getValue(), op1.getValue());
+            }
+        }
+        
     @Parameterized.Parameters
     public static Collection<Object[]> parameters() {
         final Boolean[] booleanData = new Boolean[] {true, false, true, false};