Based on previous discussions, this PR attempts to improve the JavaFX property 
system by enforcing correct API usage in several cases that are outlined below. 
It also streamlines the API by deprecating untyped APIs in favor of typed APIs 
that better express intent.

### 1. Behavioral changes for regular bindings

var target = new SimpleObjectProperty(bean, "target");
var source = new SimpleObjectProperty(bean, "source");
target.bind(source);
target.bindBidirectional(source);

_Before:_ `RuntimeException` --> "bean.target: A bound value cannot be set."
_After:_ `IllegalStateException` --> "bean.target: Bidirectional binding cannot 
target a bound property."


var target = new SimpleObjectProperty(bean, "target");
var source = new SimpleObjectProperty(bean, "source");
var other = new SimpleObjectProperty(bean, "other");
source.bind(other);
target.bindBidirectional(source);

_Before:_ no error
_After:_ `IllegalArgumentException` --> "bean.source: Bidirectional binding 
cannot target a bound property."


var target = new SimpleObjectProperty(bean, "target");
var source = new SimpleObjectProperty(bean, "source");
target.bindBidirectional(source);
target.bind(source);

_Before:_ no error
_After:_ `IllegalStateException` --> "bean.target: Cannot bind a property that 
is targeted by a bidirectional binding."


### 2. Behavioral changes for content bindings

var target = new SimpleListProperty(bean, "target");
var source = new SimpleListProperty(bean, "source");
target.bindContent(source);
target.bindContentBidirectional(source);

_Before:_ no error
_After:_ `IllegalStateException` --> "bean.target: Bidirectional content 
binding cannot target a bound collection."


var target = new SimpleListProperty(bean, "target");
var source = new SimpleListProperty(bean, "source");
var other = new SimpleListProperty();
source.bindContent(other);
target.bindContentBidirectional(source);

_Before:_ no error
_After:_ `IllegalArgumentException` --> "bean.source: Bidirectional content 
binding cannot target a bound collection."


var target = new SimpleListProperty(bean, "target");
var source = new SimpleListProperty(bean, "source");
target.bindContentBidirectional(source);
target.bindContent(source);

_Before:_ no error
_After:_ `IllegalStateException` --> "bean.target: Cannot bind a collection 
that is targeted by a bidirectional content binding."


var target = new SimpleListProperty(bean, "target");
var source = new SimpleListProperty(bean, "source");
target.bindContent(source);
target.set(FXCollections.observableArrayList());

_Before:_ no error
_After:_ `IllegalStateException` --> "bean.target: Cannot set the value of a 
content-bound property."


var target = new SimpleListProperty(bean, "target");
var source = new SimpleListProperty(bean, "source");
target.bindContent(source);
target.add("foo");

_Before_: no error, but binding is broken because the lists are in an 
inconsistent state
_After:_ `RuntimeExeption` via `Thread.UncaughtExceptionHandler` --> "Illegal 
list modification: Content binding was removed because the lists are 
out-of-sync."


### 3. Align un-binding of unidirectional content bindings with regular 
unidirectional bindings
The API of unidirectional content bindings is aligned with regular 
unidirectional bindings because the semantics are similar. Like `unbind()`, 
`unbindContent(Object)` should not need an argument because there can only be a 
single content binding. For this reason, `unbindContent(Object)` will be 
deprecated in favor of `unbindContent()`:

  void bindContent(ObservableList<E> source);
+ void unbindContent();
+ boolean isContentBound();

+ @Deprecated(since = "18", forRemoval = true)
  void unbindContent(Object object);


### 4. Replace untyped binding APIs with typed APIs
The following untyped APIs will be marked for removal in favor of typed 
replacements:
In `javafx.beans.binding.Bindings`:

@Deprecated(since = "18", forRemoval = true)
void unbindBidirectional(Object property1, Object property2)

@Deprecated(since = "18", forRemoval = true)
void unbindContentBidirectional(Object obj1, Object obj2)

@Deprecated(since = "18", forRemoval = true)
void unbindContent(Object obj1, Object obj2)


In `ReadOnlyListProperty`, `ReadOnlySetProperty`, `ReadOnlyMapProperty`:

@Deprecated(since = "18", forRemoval = true)
void unbindContentBidirectional(Object object)


~~5. Support un-binding bidirectional conversion bindings with typed API
At this moment, `StringProperty` is the only property implementation that 
offers bidirectional conversion bindings, where the `StringProperty` is bound 
to a property of another type:~~

<U> void bindBidirectional(Property<U> other, StringConverter<U> converter)

~~The inherited `Property.unbindBidirectional(Property<String>)` API cannot be 
used to unbind a conversion binding, because it only accepts arguments of type 
`Property<String>`.
`StringProperty` solves this issue by adding an untyped overload: 
`unbindBidirectional(Object)`.~~

~~I propose to relax the definition of `Property.unbindBidirectional`:~~

- void unbindBidirectional(Property<T> other);
+ void unbindBidirectional(Property<?> other);

~~This allows property implementations to use the same API to un-bind regular 
bidirectional bindings, as well as converting bidirectional bindings. The 
`Property` typing is retained with a minimal impact on existing code (most 
_usages_ of this API will continue to compile, while classes that override 
`unbindBidirectional` will need to be changed to match the new API).~~

~~As a side-effect, this allows the option of easily adding conversion bindings 
for other property implementations as well.~~

-------------

Commit messages:
 - centralized Property.toString
 - test error message in content binding tests
 - fix whitespace issues
 - fix things that broke
 - Clean up content binding API
 - Rework exception messages
 - changes
 - Javadoc changes
 - replace Object with Property
 - fix merge
 - ... and 15 more: https://git.openjdk.java.net/jfx/compare/55faac49...244b76f2

Changes: https://git.openjdk.java.net/jfx/pull/590/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jfx&pr=590&range=00
  Issue: https://bugs.openjdk.java.net/browse/JDK-8268642
  Stats: 4696 lines in 95 files changed: 3102 ins; 822 del; 772 mod
  Patch: https://git.openjdk.java.net/jfx/pull/590.diff
  Fetch: git fetch https://git.openjdk.java.net/jfx pull/590/head:pull/590

PR: https://git.openjdk.java.net/jfx/pull/590

Reply via email to