I just had a nice "gotcha" experience debugging a wierd problem where a Binding, that can never be null in any circumstances, gets restored to null because somewhere along the chain of changes a Bidirectional binding failed.
From a user standpoint I basically see:
1) I set some value to X
2) Some ChangeListener acts on the value X
3) Without further intervention, the value gets set to null (the previous value) ---> BIG surprise, I never ever set it to null...
4) The same ChangeListener acts on the value null (which is illegal), throws NPE.
Step 5, which is never reached, turns out to be:
5) throw new RuntimeException("Bidirectional binding failed, setting to the previous value", e);
Which would explain the problem... however, because the code that restores the value triggers another exception, this gets lost.
The problem turns out to be in this piece of code in BidirectionalBinding.TypedGenericBidirectionalBinding:
try {
updating = true;
if (property1 == sourceProperty) {
property2.setValue(newValue);
} else {
property1.setValue(newValue);
}
} catch (RuntimeException e) {
if (property1 == sourceProperty) {
property1.setValue(oldValue);
} else {
property2.setValue(oldValue); // <<<<<< Triggers NPE further down the line!
}
throw new RuntimeException(
"Bidirectional binding failed, setting to the previous value", e);
} finally {
updating = false;
}
I marked the line which triggers the eventual NPE. IMHO, this piece of error handling must be further wrapped in a try-catch block so that the real cause ("Bidirectional binding failed") can be properly reported to the user.
From a user standpoint I basically see:
1) I set some value to X
2) Some ChangeListener acts on the value X
3) Without further intervention, the value gets set to null (the previous value) ---> BIG surprise, I never ever set it to null...
4) The same ChangeListener acts on the value null (which is illegal), throws NPE.
Step 5, which is never reached, turns out to be:
5) throw new RuntimeException("Bidirectional binding failed, setting to the previous value", e);
Which would explain the problem... however, because the code that restores the value triggers another exception, this gets lost.
The problem turns out to be in this piece of code in BidirectionalBinding.TypedGenericBidirectionalBinding:
try {
updating = true;
if (property1 == sourceProperty) {
property2.setValue(newValue);
} else {
property1.setValue(newValue);
}
} catch (RuntimeException e) {
if (property1 == sourceProperty) {
property1.setValue(oldValue);
} else {
property2.setValue(oldValue); // <<<<<< Triggers NPE further down the line!
}
throw new RuntimeException(
"Bidirectional binding failed, setting to the previous value", e);
} finally {
updating = false;
}
I marked the line which triggers the eventual NPE. IMHO, this piece of error handling must be further wrapped in a try-catch block so that the real cause ("Bidirectional binding failed") can be properly reported to the user.
- relates to
-
JDK-8116862 Bidirectional Binding does not maintain the invariant if one of the properties is bound
- Resolved