changeset 6070:f487abfe1990

RT-35237 When a Bidirectional binding fails, old value restoration may cause an exception hiding the real cause
author Martin Sladecek <martin.sladecek@oracle.com>
date Mon, 13 Jan 2014 13:29:44 +0100
parents 66411c75ff6b
children 838ab16784b0
files modules/base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java modules/base/src/test/java/com/sun/javafx/binding/BidirectionalBindingTest.java
diffstat 2 files changed, 123 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/modules/base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java	Mon Jan 13 09:41:14 2014 +0200
+++ b/modules/base/src/main/java/com/sun/javafx/binding/BidirectionalBinding.java	Mon Jan 13 13:29:44 2014 +0100
@@ -239,11 +239,21 @@
                             property1.set(newValue);
                         }
                     } catch (RuntimeException e) {
-                        if (property1 == sourceProperty) {
-                            property1.set(oldValue);
-                        } else {
-                            property2.set(oldValue);
-                        }
+                        try {
+                            if (property1 == sourceProperty) {
+                                property1.set(oldValue);
+                            } else {
+                                property2.set(oldValue);
+                            }
+                        } catch (Exception e2) {
+                            e2.addSuppressed(e);
+                            unbind(property1, property2);
+                            throw new RuntimeException(
+                                "Bidirectional binding failed together with an attempt"
+                                        + " to restore the source property to the previous value."
+                                        + " Removing the bidirectional binding from properties " +
+                                        property1 + " and " + property2, e2);
+                        } 
                         throw new RuntimeException(
                                 "Bidirectional binding failed, setting to the previous value", e);
                     } finally {
@@ -296,10 +306,20 @@
                             property1.set(newValue.doubleValue());
                         }
                     } catch (RuntimeException e) {
-                        if (property1 == sourceProperty) {
-                            property1.set(oldValue.doubleValue());
-                        } else {
-                            property2.set(oldValue.doubleValue());
+                        try {
+                            if (property1 == sourceProperty) {
+                                property1.set(oldValue.doubleValue());
+                            } else {
+                                property2.set(oldValue.doubleValue());
+                            }
+                        } catch (Exception e2) {
+                            e2.addSuppressed(e);
+                            unbind(property1, property2);
+                            throw new RuntimeException(
+                                "Bidirectional binding failed together with an attempt"
+                                        + " to restore the source property to the previous value."
+                                        + " Removing the bidirectional binding from properties " +
+                                        property1 + " and " + property2, e2);
                         }
                         throw new RuntimeException(
                                         "Bidirectional binding failed, setting to the previous value", e);
@@ -353,10 +373,20 @@
                             property1.set(newValue.floatValue());
                         }
                     } catch (RuntimeException e) {
-                        if (property1 == sourceProperty) {
-                            property1.set(oldValue.floatValue());
-                        } else {
-                            property2.set(oldValue.floatValue());
+                        try {
+                            if (property1 == sourceProperty) {
+                                property1.set(oldValue.floatValue());
+                            } else {
+                                property2.set(oldValue.floatValue());
+                            }
+                        } catch (Exception e2) {
+                            e2.addSuppressed(e);
+                            unbind(property1, property2);
+                            throw new RuntimeException(
+                                "Bidirectional binding failed together with an attempt"
+                                        + " to restore the source property to the previous value."
+                                        + " Removing the bidirectional binding from properties " +
+                                        property1 + " and " + property2, e2);
                         }
                         throw new RuntimeException(
                                 "Bidirectional binding failed, setting to the previous value", e);
@@ -410,10 +440,20 @@
                             property1.set(newValue.intValue());
                         }
                     } catch (RuntimeException e) {
-                        if (property1 == sourceProperty) {
-                            property1.set(oldValue.intValue());
-                        } else {
-                            property2.set(oldValue.intValue());
+                        try {
+                            if (property1 == sourceProperty) {
+                                property1.set(oldValue.intValue());
+                            } else {
+                                property2.set(oldValue.intValue());
+                            }
+                        } catch (Exception e2) {
+                            e2.addSuppressed(e);
+                            unbind(property1, property2);
+                            throw new RuntimeException(
+                                "Bidirectional binding failed together with an attempt"
+                                        + " to restore the source property to the previous value."
+                                        + " Removing the bidirectional binding from properties " +
+                                        property1 + " and " + property2, e2);
                         }
                         throw new RuntimeException(
                                         "Bidirectional binding failed, setting to the previous value", e);
@@ -467,10 +507,20 @@
                             property1.set(newValue.longValue());
                         }
                     } catch (RuntimeException e) {
-                        if (property1 == sourceProperty) {
-                            property1.set(oldValue.longValue());
-                        } else {
-                            property2.set(oldValue.longValue());
+                        try {
+                            if (property1 == sourceProperty) {
+                                property1.set(oldValue.longValue());
+                            } else {
+                                property2.set(oldValue.longValue());
+                            }
+                        } catch (Exception e2) {
+                            e2.addSuppressed(e);
+                            unbind(property1, property2);
+                            throw new RuntimeException(
+                                "Bidirectional binding failed together with an attempt"
+                                        + " to restore the source property to the previous value."
+                                        + " Removing the bidirectional binding from properties " +
+                                        property1 + " and " + property2, e2);
                         }
                         throw new RuntimeException(
                                 "Bidirectional binding failed, setting to the previous value", e);
@@ -524,10 +574,20 @@
                             property1.setValue(newValue);
                         }
                     } catch (RuntimeException e) {
-                        if (property1 == sourceProperty) {
-                            property1.setValue(oldValue);
-                        } else {
-                            property2.setValue(oldValue);
+                        try {
+                            if (property1 == sourceProperty) {
+                                property1.setValue(oldValue);
+                            } else {
+                                property2.setValue(oldValue);
+                            }
+                        } catch (Exception e2) {
+                            e2.addSuppressed(e);
+                            unbind(property1, property2);
+                            throw new RuntimeException(
+                                "Bidirectional binding failed together with an attempt"
+                                        + " to restore the source property to the previous value."
+                                        + " Removing the bidirectional binding from properties " +
+                                        property1 + " and " + property2, e2);
                         }
                         throw new RuntimeException(
                                 "Bidirectional binding failed, setting to the previous value", e);
@@ -581,10 +641,20 @@
                             property1.setValue((T)newValue);
                         }
                     } catch (RuntimeException e) {
-                        if (property1 == sourceProperty) {
-                            property1.setValue((T)oldValue);
-                        } else {
-                            property2.setValue(oldValue);
+                        try {
+                            if (property1 == sourceProperty) {
+                                property1.setValue((T)oldValue);
+                            } else {
+                                property2.setValue(oldValue);
+                            }
+                        } catch (Exception e2) {
+                            e2.addSuppressed(e);
+                            unbind(property1, property2);
+                            throw new RuntimeException(
+                                "Bidirectional binding failed together with an attempt"
+                                        + " to restore the source property to the previous value."
+                                        + " Removing the bidirectional binding from properties " +
+                                        property1 + " and " + property2, e2);
                         }
                         throw new RuntimeException(
                                         "Bidirectional binding failed, setting to the previous value", e);
--- a/modules/base/src/test/java/com/sun/javafx/binding/BidirectionalBindingTest.java	Mon Jan 13 09:41:14 2014 +0200
+++ b/modules/base/src/test/java/com/sun/javafx/binding/BidirectionalBindingTest.java	Mon Jan 13 13:29:44 2014 +0100
@@ -64,11 +64,13 @@
     private PropertyMock<T> op1;
     private PropertyMock<T> op2;
     private PropertyMock<T> op3;
+    private PropertyMock<T> op4;
     
     public BidirectionalBindingTest(Functions<T> func, T[] v) {
         this.op1 = func.create();
         this.op2 = func.create();
         this.op3 = func.create();
+        this.op4 = func.create();
         this.func = func;
         this.v = v;
     }
@@ -276,6 +278,28 @@
             }
         }
         
+        @Test
+        public void testDoubleBrokenBind() {
+            func.bind(op1, op2);
+            op1.bind(op3);
+            op4.setValue(v[0]);
+            
+            thrown.expect(RuntimeException.class);
+            try {
+                op2.bind(op4);
+            } finally {
+                assertEquals(op4.getValue(), op2.getValue());
+                assertEquals(op3.getValue(), op1.getValue());
+                // Test that bidirectional binding was unbound in this case
+                op3.setValue(v[0]);
+                op4.setValue(v[1]);
+                assertEquals(op4.getValue(), op2.getValue());
+                assertEquals(op3.getValue(), op1.getValue());
+                assertEquals(v[0], op1.getValue());
+                assertEquals(v[1], op2.getValue());
+            }
+        }
+        
     @Parameterized.Parameters
     public static Collection<Object[]> parameters() {
         final Boolean[] booleanData = new Boolean[] {true, false, true, false};