> This is an implementation of the proposal in 
> https://bugs.openjdk.java.net/browse/JDK-8274771 that me and Nir Lisker 
> (@nlisker) have been working on.  It's a complete implementation including 
> good test coverage.  
> 
> This was based on https://github.com/openjdk/jfx/pull/434 but with a smaller 
> API footprint.  Compared to the PoC this is lacking public API for 
> subscriptions, and does not include `orElseGet` or the `conditionOn` 
> conditional mapping.
> 
> **Flexible Mappings**
> Map the contents of a property any way you like with `map`, or map nested 
> properties with `flatMap`.
> 
> **Lazy**
> The bindings created are lazy, which means they are always _invalid_ when not 
> themselves observed. This allows for easier garbage collection (once the last 
> observer is removed, a chain of bindings will stop observing their parents) 
> and less listener management when dealing with nested properties.  
> Furthermore, this allows inclusion of such bindings in classes such as `Node` 
> without listeners being created when the binding itself is not used (this 
> would allow for the inclusion of a `treeShowingProperty` in `Node` without 
> creating excessive listeners, see this fix I did in an earlier PR: 
> https://github.com/openjdk/jfx/pull/185)
> 
> **Null Safe**
> The `map` and `flatMap` methods are skipped, similar to `java.util.Optional` 
> when the value they would be mapping is `null`. This makes mapping nested 
> properties with `flatMap` trivial as the `null` case does not need to be 
> taken into account in a chain like this: 
> `node.sceneProperty().flatMap(Scene::windowProperty).flatMap(Window::showingProperty)`.
>   Instead a default can be provided with `orElse`.
> 
> Some examples:
> 
>     void mapProperty() {
>       // Standard JavaFX:
>       label.textProperty().bind(Bindings.createStringBinding(() -> 
> text.getValueSafe().toUpperCase(), text));
> 
>       // Fluent: much more compact, no need to handle null
>       label.textProperty().bind(text.map(String::toUpperCase));
>     }
> 
>     void calculateCharactersLeft() {
>       // Standard JavaFX:
>       
> label.textProperty().bind(text.length().negate().add(100).asString().concat(" 
> characters left"));
> 
>       // Fluent: slightly more compact and more clear (no negate needed)
>       label.textProperty().bind(text.orElse("").map(v -> 100 - v.length() + " 
> characters left"));
>     }
> 
>     void mapNestedValue() {
>       // Standard JavaFX:
>       label.textProperty().bind(Bindings.createStringBinding(
>         () -> employee.get() == null ? ""
>             : employee.get().getCompany() == null ? ""
>             : employee.get().getCompany().getName(),
>         employee
>       ));
> 
>       // Standard JavaFX + Optional:
>       label.textProperty().bind(Bindings.createStringBinding(
>           () -> Optinal.ofNullable(employee.get())
>               .map(Employee::getCompany)
>               .map(Company::getName)
>               .orElse(""),
>          employee
>       ));
> 
>       // Fluent: no need to handle nulls everywhere
>       label.textProperty().bind(
>         employee.map(Employee::getCompany)
>                 .map(Company::getName)
>                 .orElse("")
>       );
>     }
> 
>     void mapNestedProperty() {
>       // Standard JavaFX:
>       label.textProperty().bind(
>         Bindings.when(Bindings.selectBoolean(label.sceneProperty(), "window", 
> "showing"))
>           .then("Visible")
>           .otherwise("Not Visible")
>       );
> 
>       // Fluent: type safe
>       label.textProperty().bind(label.sceneProperty()
>         .flatMap(Scene::windowProperty)
>         .flatMap(Window::showingProperty)
>         .orElse(false)
>         .map(showing -> showing ? "Visible" : "Not Visible")
>       );
>     }
> 
> Note that this is based on ideas in ReactFX and my own experiments in 
> https://github.com/hjohn/hs.jfx.eventstream.  I've come to the conclusion 
> that this is much better directly integrated into JavaFX, and I'm hoping this 
> proof of concept will be able to move such an effort forward.

John Hendrikx has updated the pull request incrementally with two additional 
commits since the last revision:

 - Expand flatMap javadoc with additional wording from Optional#flatMap
 - Add since tags to all new API

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

Changes:
  - all: https://git.openjdk.java.net/jfx/pull/675/files
  - new: https://git.openjdk.java.net/jfx/pull/675/files/e2703e6b..c3523903

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jfx&pr=675&range=14
 - incr: https://webrevs.openjdk.java.net/?repo=jfx&pr=675&range=13-14

  Stats: 9 lines in 2 files changed: 9 ins; 0 del; 0 mod
  Patch: https://git.openjdk.java.net/jfx/pull/675.diff
  Fetch: git fetch https://git.openjdk.java.net/jfx pull/675/head:pull/675

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

Reply via email to