public class BeanPathAdapter<B>
extends java.lang.Object
An adapter that takes a POJO bean and internally and recursively
binds/un-binds it’s fields to other Property
components. It allows a
<b><code>.</code></b> separated field path to be traversed on a bean until
the final field name is found (last entry in the <b><code>.</code></b>
separated field path). Each field will have a corresponding Property
that is automatically generated and reused in the binding process. Each
Property
is bean-aware and will dynamically update it’s values and
bindings as different beans are set on the adapter. Bean’s set on the adapter
do not need to instantiate all the sub-beans in the path(s) provided as long
as they contain a no-argument constructor they will be instantiated as
path(s) are traversed.
<h3>Examples:</h3> <ol> <li> <b>Binding bean fields to multiple JavaFX control properties of different types:</b>
<pre> Person person = new Person(); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); Slider sl = new Slider(); TextField tf = new TextField(); personPA.bindBidirectional("age", sl.valueProperty()); personPA.bindBidirectional("age", tf.valueProperty()); </pre>
</li> <li> <b>Binding beans within beans:</b>
<pre> Person person = new Person(); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); TextField tf = new TextField(); personPA.bindBidirectional("address.location.state", tf.valueProperty()); </pre>
</li> <li> <b>Binding non-primitive bean paths to JavaFX control properties of the same non-primitive type:</b>
<pre> Address a1 = new Address(); Address a2 = new Address(); a1.setStreet("1st Street"); a2.setStreet("2nd Street"); ComboBox<Address> cb = new ComboBox<>(); cb.getItems().addAll(a1, a2); Person person = new Person(); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); personPA.bindBidirectional("address", cb.valueProperty(), Address.class); </pre>
</li> <li> <b>Binding collections/maps fields to/from observable collections/maps (i.e. items in a JavaFX control):</b>
<pre> Person person = new Person(); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); ListView<String> lv = new ListView<>(); personPA.bindContentBidirectional("allLanguages", null, String.class, lv.getItems(), String.class, null, null); </pre>
</li> <li> <b>Binding collections/maps fields to/from observable collections/maps selections (i.e. selections in a JavaFX control):</b>
<pre> Person person = new Person(); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); ListView<String> lv = new ListView<>(); personPA.bindContentBidirectional("languages", null, String.class, lv .getSelectionModel().getSelectedItems(), String.class, lv .getSelectionModel(), null); </pre>
</li> <li> <b>Binding collection/map fields to/from observable collections/maps selections using an items from another observable collection/map as a reference (i.e. selections in a JavaFX control that contain the same instances as what are in the items being selected from):</b>
<pre> BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); ListView<String> lv = new ListView<>(); personPA.bindContentBidirectional("languages", null, String.class, lv .getSelectionModel().getSelectedItems(), String.class, lv .getSelectionModel(), "allLanguages"); </pre>
</li> <li> <b>Binding complex bean collection/map fields to/from observable collections/maps selections and items (i.e. selections in a JavaFX control that contain the same bean instances as what are in the items being selected):</b>
<pre> "allHobbies" are a collection/map // fields in person and each element within them contain an // instance of Hobby that has it’s own field called "name" // we can bind "allHobbies" and "hobbies" to the Hobby "name"s // for each Hobby in the items/selections (respectively) to/from // a ListView wich will only contain the String name of each Hobby // as it’s items and selections Person person = new Person(); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); ListView<String> lv = new ListView<>(); personPA.bindContentBidirectional("allHobbies", "name", Hobby.class, lv.getItems(), String.class, null, null); personPA.bindContentBidirectional("languages", "name", Hobby.class, lv.getSelectionModel().getSelectedItems(), String.class, lv.getSelectionModel(), "allHobbiess"); </pre>
</li> <li> <b>Binding bean collection/map fields to/from multiple JavaFX control observable collections/maps of the same type (via bean collection/map):</b>
<pre> Person person = new Person(); Hobby hobby1 = new Hobby(); hobby1.setName("Hobby 1"); Hobby hobby2 = new Hobby(); hobby2.setName("Hobby 2"); person.setAllHobbies(new LinkedHashSet<Hobby>()); person.getAllHobbies().add(hobby1); person.getAllHobbies().add(hobby2); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); ListView<String> lv = new ListView<>(); personPA.bindContentBidirectional("allHobbies", "name", Hobby.class, lv.getItems(), String.class, null, null); ListView<String> lv2 = new ListView<>(); personPA.bindContentBidirectional("allHobbies", "name", Hobby.class, lv2.getItems(), String.class, null, null); </pre>
</li> <li> <b>Binding bean collection/map fields to/from multiple JavaFX control observable collections/maps of the same type (via JavaFX control observable collection/map):</b>
<pre> Person person = new Person(); final ObservableList<String> oc = FXCollections.observableArrayList("Hobby 1", "Hobby 2", "Hobby 3"); BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); ListView<String> lv = new ListView<>(oc); personPA.bindContentBidirectional("allHobbies", "name", Hobby.class, lv.getItems(), String.class, null, null); ListView<String> lv2 = new ListView<>(); // <-- notice that oc is not passed personPA.bindContentBidirectional("allHobbies", "name", Hobby.class, lv2.getItems(), String.class, null, null); </pre>
</li> <li> <b>Switching beans:</b>
<pre> final Person person1 = new Person(); person1.setAge(1D); final Person person2 = new Person(); person2.setAge(2D); final BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person1); TextField tf = new TextField(); personPA.bindBidirectional("age", tf.valueProperty()); Button btn = new Button("Toggle People"); btn.setOnMouseClicked(new EventHandler<MouseEvent>() { public void handle(MouseEvent event) { // all bindings will show relevant person data and changes made // to the bound controls will be reflected in the bean that is // set at the time of the change personPA.setBean(personPA.getBean() == person1 ? person2 : person1); } }); </pre>
</li>
<li>
<b>Date
/Calendar
binding:</b>
<pre> final Person person = new Person(); final BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); CalendarPicker calendarPicker = new CalendarPicker(); personPA.bindBidirectional("dob", calendarPicker.calendarProperty(), Calendar.class); </pre>
</li>
<li>
<b>TableView
binding:</b>
<pre> final Person person = new Person(); final BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); TableView<Hobby> table = new TableView<>(); TableColumn<Hobby, String> nameCol = new TableColumn<>("Hobby Name"); nameCol.setMinWidth(100); nameCol.setCellValueFactory(new PropertyValueFactory<Hobby, String>("name")); TableColumn<Hobby, String> descCol = new TableColumn<>("Hobby Desc"); descCol.setMinWidth(100); descCol.setCellValueFactory(new PropertyValueFactory<Hobby, String>( "description")); table.getColumns().addAll(nameCol, descCol); personPA.bindContentBidirectional("hobbies", null, String.class, table.getItems(), Hobby.class, null, null); </pre>
</li> <li> <b>Listening for global changes:</b>
<pre> final BeanPathAdapter<Person> personPA = new BeanPathAdapter<>(person); personPA.fieldPathValueProperty().addListener( new ChangeListener<FieldPathValue>() { @Override public void changed( final ObservableValue<? extends FieldPathValue> observable, final FieldPathValue oldValue, final FieldPathValue newValue) { System.out.println("Value changed from: " + oldValue + " to: " + newValue); } }); </pre>
</li> </ol>
bindBidirectional(String, Property)
,
bindContentBidirectional(String, String, Class, ObservableList, Class,
SelectionModel, String)
,
bindContentBidirectional(String, String, Class, ObservableSet, Class,
SelectionModel, String)
,
bindContentBidirectional(String, String, Class, ObservableMap, Class,
SelectionModel, String)
Type | Property and Description |
---|---|
javafx.beans.property.ReadOnlyObjectProperty<BeanPathAdapter.FieldPathValue> |
fieldPathValue |
Modifier and Type | Class and Description |
---|---|
protected static class |
BeanPathAdapter.FieldBean<PT,BT>
A POJO bean extension that allows binding based upon a <b><code>.</code>
</b> separated field path that will be traversed on a bean until the
final field name is found.
|
static class |
BeanPathAdapter.FieldBeanOperation
BeanPathAdapter.FieldBean operations |
protected static class |
BeanPathAdapter.FieldHandle<T,F>
Field handle to
BeanPathAdapter.FieldHandle.getAccessor() and
BeanPathAdapter.FieldHandle.getSetter() for a given
BeanPathAdapter.FieldHandle.getTarget() . |
static class |
BeanPathAdapter.FieldPathValue
|
static class |
BeanPathAdapter.FieldPathValueType
BeanPathAdapter.FieldPathValue types used for FieldPathValueProperty
changes |
static class |
BeanPathAdapter.FieldProperty<BT,T,PT>
A
Property extension that uses a bean’s getter/setter to define
the Property 's value. |
protected static class |
BeanPathAdapter.FieldStringConverter<T>
Coercible
StringConverter that handles conversions between
strings and a target class when used in the binding process
Bindings.bindBidirectional(Property, Property, StringConverter) |
Modifier and Type | Field and Description |
---|---|
static char |
COLLECTION_ITEM_PATH_SEPARATOR |
static char |
PATH_SEPARATOR |
Constructor and Description |
---|
BeanPathAdapter(B bean)
Constructor
|
Modifier and Type | Method and Description |
---|---|
void |
addFieldPathValueTypes(BeanPathAdapter.FieldPathValueType... types)
Adds
BeanPathAdapter.FieldPathValueType (s) BeanPathAdapter.FieldPathValueType (s) that
{link notifyProperty()} will use |
void |
bindBidirectional(java.lang.String fieldPath,
javafx.beans.property.BooleanProperty property) |
void |
bindBidirectional(java.lang.String fieldPath,
javafx.beans.property.Property<java.lang.Number> property) |
<T> void |
bindBidirectional(java.lang.String fieldPath,
javafx.beans.property.Property<T> property,
java.lang.Class<T> propertyType)
Binds a
Property by traversing the bean’s field tree |
void |
bindBidirectional(java.lang.String fieldPath,
javafx.beans.property.StringProperty property) |
<E> void |
bindContentBidirectional(java.lang.String fieldPath,
java.lang.String itemFieldPath,
java.lang.Class<?> itemFieldPathType,
javafx.collections.ObservableList<E> list,
java.lang.Class<E> listValueType,
javafx.scene.control.SelectionModel<E> selectionModel,
java.lang.String selectionModelItemMasterPath)
Binds a
ObservableList by traversing the bean’s field tree. |
<K,V> void |
bindContentBidirectional(java.lang.String fieldPath,
java.lang.String itemFieldPath,
java.lang.Class<?> itemFieldPathType,
javafx.collections.ObservableMap<K,V> map,
java.lang.Class<V> mapValueType,
javafx.scene.control.SelectionModel<V> selectionModel,
java.lang.String selectionModelItemMasterPath)
Binds a
ObservableMap by traversing the bean’s field tree. |
<E> void |
bindContentBidirectional(java.lang.String fieldPath,
java.lang.String itemFieldPath,
java.lang.Class<?> itemFieldPathType,
javafx.collections.ObservableSet<E> set,
java.lang.Class<E> setValueType,
javafx.scene.control.SelectionModel<E> selectionModel,
java.lang.String selectionModelItemMasterPath)
Binds a
ObservableSet by traversing the bean’s field tree. |
javafx.beans.property.ReadOnlyObjectProperty<BeanPathAdapter.FieldPathValue> |
fieldPathValueProperty() |
B |
getBean() |
protected BeanPathAdapter.FieldBean<java.lang.Void,B> |
getRoot() |
boolean |
hasFieldPathValueTypes(BeanPathAdapter.FieldPathValueType... types)
Determines if the
BeanPathAdapter.FieldPathValueType (s) are being used by the
{link notifyProperty()} |
protected static <T> java.lang.Class<T> |
propertyValueClass(javafx.beans.property.Property<T> property)
Provides the underlying value class for a given
Property |
void |
removeFieldPathValueTypes(BeanPathAdapter.FieldPathValueType... types)
Removes
BeanPathAdapter.FieldPathValueType (s) BeanPathAdapter.FieldPathValueType (s) that
{link notifyProperty()} will use |
void |
setBean(B bean)
Sets the root bean of the
BeanPathAdapter . |
<T> void |
unBindBidirectional(java.lang.String fieldPath,
javafx.beans.property.Property<T> property)
Unbinds a
Property by traversing the bean’s field tree |
public final javafx.beans.property.ReadOnlyObjectProperty<BeanPathAdapter.FieldPathValue> fieldPathValueProperty
public static final char PATH_SEPARATOR
public static final char COLLECTION_ITEM_PATH_SEPARATOR
public BeanPathAdapter(B bean)
Constructor
bean
- the bean the BeanPathAdapter
is forpublic void bindBidirectional(java.lang.String fieldPath, javafx.beans.property.BooleanProperty property)
public void bindBidirectional(java.lang.String fieldPath, javafx.beans.property.StringProperty property)
public void bindBidirectional(java.lang.String fieldPath, javafx.beans.property.Property<java.lang.Number> property)
public <E> void bindContentBidirectional(java.lang.String fieldPath, java.lang.String itemFieldPath, java.lang.Class<?> itemFieldPathType, javafx.collections.ObservableList<E> list, java.lang.Class<E> listValueType, javafx.scene.control.SelectionModel<E> selectionModel, java.lang.String selectionModelItemMasterPath)
Binds a ObservableList
by traversing the bean’s field tree. An
additional item path can be specified when the path points to a
Collection
that contains beans that also need traversed in order
to establish the final value. For example: If a field path points to
<code>phoneNumbers</code> (relative to the getBean()
) where
<code>phoneNumbers</code> is a Collection
that contains
<code>PhoneNumber</code> instances which in turn have a field called
<code>areaCode</code> then an item path can be passed in addition to the
field path with <code>areaCode</code> as it’s value.
fieldPath
- the <b><code>.</code></b> separated field paths relative to
the getBean()
that will be traverseditemFieldPath
- the <b><code>.</code></b> separated field paths relative to
each item in the bean’s underlying Collection
that
will be traversed (empty/null when each item value does not
need traversed)itemFieldPathType
- the Class
of that the item path points tolist
- the ObservableList
to bind to the field class type of
the propertylistValueType
- the class type of the ObservableList
valueselectionModel
- the SelectionModel
used to set the values within the
ObservableList
<b>only applicable when the
ObservableList
is used for selection(s) and therefore
cannot be updated directly because it is read-only</b>selectionModelItemMasterPath
- when binding to SelectionModel
items, this will be the
optional path to the collection field that contains all the
items to select frompublic <E> void bindContentBidirectional(java.lang.String fieldPath, java.lang.String itemFieldPath, java.lang.Class<?> itemFieldPathType, javafx.collections.ObservableSet<E> set, java.lang.Class<E> setValueType, javafx.scene.control.SelectionModel<E> selectionModel, java.lang.String selectionModelItemMasterPath)
Binds a ObservableSet
by traversing the bean’s field tree. An
additional item path can be specified when the path points to a
Collection
that contains beans that also need traversed in order
to establish the final value. For example: If a field path points to
<code>phoneNumbers</code> (relative to the getBean()
) where
<code>phoneNumbers</code> is a Collection
that contains
<code>PhoneNumber</code> instances which in turn have a field called
<code>areaCode</code> then an item path can be passed in addition to the
field path with <code>areaCode</code> as it’s value.
fieldPath
- the <b><code>.</code></b> separated field paths relative to
the getBean()
that will be traverseditemFieldPath
- the <b><code>.</code></b> separated field paths relative to
each item in the bean’s underlying Collection
that
will be traversed (empty/null when each item value does not
need traversed)itemFieldPathType
- the Class
of that the item path points toset
- the ObservableSet
to bind to the field class type of
the propertysetValueType
- the class type of the ObservableSet
valueselectionModel
- the SelectionModel
used to set the values within the
ObservableSet
<b>only applicable when the
ObservableSet
is used for selection(s) and therefore
cannot be updated directly because it is read-only</b>selectionModelItemMasterPath
- when binding to SelectionModel
items, this will be the
optional path to the collection field that contains all the
items to select frompublic <K,V> void bindContentBidirectional(java.lang.String fieldPath, java.lang.String itemFieldPath, java.lang.Class<?> itemFieldPathType, javafx.collections.ObservableMap<K,V> map, java.lang.Class<V> mapValueType, javafx.scene.control.SelectionModel<V> selectionModel, java.lang.String selectionModelItemMasterPath)
Binds a ObservableMap
by traversing the bean’s field tree. An
additional item path can be specified when the path points to a
Collection
that contains beans that also need traversed in order
to establish the final value. For example: If a field path points to
<code>phoneNumbers</code> (relative to the getBean()
) where
<code>phoneNumbers</code> is a Collection
that contains
<code>PhoneNumber</code> instances which in turn have a field called
<code>areaCode</code> then an item path can be passed in addition to the
field path with <code>areaCode</code> as it’s value.
fieldPath
- the <b><code>.</code></b> separated field paths relative to
the getBean()
that will be traverseditemFieldPath
- the <b><code>.</code></b> separated field paths relative to
each item in the bean’s underlying Collection
that
will be traversed (empty/null when each item value does not
need traversed)itemFieldPathType
- the Class
of that the item path points tomap
- the ObservableMap
to bind to the field class type of
the propertymapValueType
- the class type of the ObservableMap
valueselectionModel
- the SelectionModel
used to set the values within the
ObservableMap
<b>only applicable when the
ObservableMap
is used for selection(s) and therefore
cannot be updated directly because it is read-only</b>selectionModelItemMasterPath
- when binding to SelectionModel
items, this will be the
optional path to the collection field that contains all the
items to select frompublic <T> void bindBidirectional(java.lang.String fieldPath, javafx.beans.property.Property<T> property, java.lang.Class<T> propertyType)
Binds a Property
by traversing the bean’s field tree
fieldPath
- the <b><code>.</code></b> separated field paths relative to
the getBean()
that will be traversedproperty
- the Property
to bind to the field class type of the
propertypropertyType
- the class type of the Property
valuepublic <T> void unBindBidirectional(java.lang.String fieldPath, javafx.beans.property.Property<T> property)
Unbinds a Property
by traversing the bean’s field tree
fieldPath
- the <b><code>.</code></b> separated field paths relative to
the getBean()
that will be traversedproperty
- the Property
to bind to the field class type of the
propertypublic B getBean()
BeanPathAdapter
public void setBean(B bean)
Sets the root bean of the BeanPathAdapter
. Any existing
properties will be updated with the values relative to the paths within
the bean.
bean
- the bean to setprotected final BeanPathAdapter.FieldBean<java.lang.Void,B> getRoot()
BeanPathAdapter.FieldBean
public final javafx.beans.property.ReadOnlyObjectProperty<BeanPathAdapter.FieldPathValue> fieldPathValueProperty()
protected static <T> java.lang.Class<T> propertyValueClass(javafx.beans.property.Property<T> property)
Provides the underlying value class for a given Property
property
- the Property
to checkProperty
public void addFieldPathValueTypes(BeanPathAdapter.FieldPathValueType... types)
Adds BeanPathAdapter.FieldPathValueType
(s) BeanPathAdapter.FieldPathValueType
(s) that
{link notifyProperty()} will use
types
- the BeanPathAdapter.FieldPathValueType
to addpublic void removeFieldPathValueTypes(BeanPathAdapter.FieldPathValueType... types)
Removes BeanPathAdapter.FieldPathValueType
(s) BeanPathAdapter.FieldPathValueType
(s) that
{link notifyProperty()} will use
types
- the BeanPathAdapter.FieldPathValueType
(s) to removepublic boolean hasFieldPathValueTypes(BeanPathAdapter.FieldPathValueType... types)
Determines if the BeanPathAdapter.FieldPathValueType
(s) are being used by the
{link notifyProperty()}
types
- the BeanPathAdapter.FieldPathValueType
(s) to check forBeanPathAdapter.FieldPathValueType
(s) exist