B
- the type of the adapted beanpublic final class PropertyAdapter<B> extends AbstractValueModel
The constructors accept either a property name or a triple of (property name, getter name, setter name). If you just specify the property name, the adapter uses the standard Java Bean introspection to lookup the available properties and how to read and write the property value. In case of custom readers and writers you may specify a custom BeanInfo class, or as a shortcut use the constructors that accept the optional getter and setter name. If these are specified, introspection will be bypassed and a PropertyDescriptor will be created for the given property name, getter and setter name.
Optionally the PropertyAdapter can observe changes in bound
properties as described in section 7.4 of the Bean specification.
You can enable this feature by setting the constructor parameter
observeChanges
to true
.
If the adapter observes changes, it will fire value change events,
i.e. PropertyChangeEvents for the property "value"
.
Even if you ignore property changes, you can access the adapted
property value via #getValue()
.
It's just that you won't be notified about changes.
The PropertyAdapter provides two access styles to the target bean
that holds the adapted property: you can specify a bean directly,
or you can use a bean channel to access the bean indirectly.
In the latter case you specify a ValueModel
that holds the bean that in turn holds the adapted property.
If the adapted bean is null
the PropertyAdapter can
neither read nor set a value. In this case #getValue
returns null
and #setValue
will silently
ignore the new value.
This adapter throws three PropertyChangeEvents if the bean changes:
beforeBean, bean and afterBean. This is useful
when sharing a bean channel and you must perform an operation before
or after other listeners handle a bean change. Since you cannot rely
on the order listeners will be notified, only the beforeBean
and afterBean events are guaranteed to be fired before and
after the bean change is fired.
Note that #getBean()
returns the new bean before
any of these three PropertyChangeEvents is fired. Therefore listeners
that handle these events must use the event's old and new value
to determine the old and new bean.
The order of events fired during a bean change is:
Note:
PropertyAdapters that observe changes have a PropertyChangeListener
registered with the target bean. Hence, a bean has a reference
to any PropertyAdapter that observes it. To avoid memory leaks
it is recommended to remove this listener if the bean lives much longer than
the PropertyAdapter, enabling the garbage collector to remove the adapter.
To do so, you can call setBean(null)
or set the
bean channel's value to null.
As an alternative you can use event listener lists in your beans
that implement references with WeakReference
.
Setting the bean to null has side-effects, for example the adapter fires
a change event for the bound property bean and other properties.
And the adpter's value may change.
However, typically this is fine and setting the bean to null
is the first choice for removing the reference from the bean to the adapter.
Another way to clear the reference from the target bean is
to call #release
. It has no side-effects, but the adapter
must not be used anymore once #release has been called.
Constraints: If property changes shall be observed, the bean class must support bound properties, i. e. it must provide the following pair of methods for registration of multicast property change event listeners:
public void addPropertyChangeListener(PropertyChangeListener x); public void removePropertyChangeListener(PropertyChangeListener x);PropertyAdapter vs. BeanAdapter vs. PresentationModel
BeanAdapter
. The BeanAdapter
registers only a single PropertyChangeListener with the bean,
where multiple PropertyAdapters would register multiple listeners.
If you adapt bean properties for an editor, you will typically use the
PresentationModel
. The PresentationModel is
more powerful than the BeanAdapter. It adds support for buffered models,
and provides an extensible mechanism for observing the change state
of the bean and related objects.Basic Examples:
// Direct access, ignores changes Address address = new Address() PropertyAdapter adapter = new PropertyAdapter(address, "street"); adapter.setValue("Broadway"); System.out.println(address.getStreet()); // Prints "Broadway" address.setStreet("Franz-Josef-Strasse"); System.out.println(adapter.getValue()); // Prints "Franz-Josef-Strasse" //Direct access, observes changes PropertyAdapter adapter = new PropertyAdapter(address, "street", true); // Indirect access, ignores changes ValueHolder addressHolder = new ValueHolder(address1); PropertyAdapter adapter = new PropertyAdapter(addressHolder, "street"); adapter.setValue("Broadway"); // Sets the street in address1 System.out.println(address1.getValue()); // Prints "Broadway" adapter.setBean(address2); adapter.setValue("Robert-Koch-Strasse"); // Sets the street in address2 System.out.println(address2.getValue()); // Prints "Robert-Koch-Strasse" // Indirect access, observes changes ValueHolder addressHolder = new ValueHolder(); PropertyAdapter adapter = new PropertyAdapter(addressHolder, "street", true); addressHolder.setValue(address1); address1.setStreet("Broadway"); System.out.println(adapter.getValue()); // Prints "Broadway"Adapter Chain Example:
Country country = new Country(); country.setName("Germany"); country.setEuMember(true); JTextField nameField = new JTextField(); nameField.setDocument(new DocumentAdapter( new PropertyAdapter(country, "name", true))); JCheckBox euMemberBox = new JCheckBox("Is EU Member"); euMemberBox.setModel(new ToggleButtonAdapter( new PropertyAdapter(country, "euMember", true))); // Using factory methods JTextField nameField = Factory.createTextField(country, "name"); JCheckBox euMemberBox = Factory.createCheckBox (country, "euMember"); euMemberBox.setText("Is EU Member");
TODO: Consider adding a feature to ensure that update notifications are performed in the event dispatch thread. In case the adapted bean is changed in a thread other than the event dispatch thread, such a feature would help complying with Swing's single thread rule. The feature could be implemented by an extended PropertyChangeSupport.
TODO: I plan to improve the support for adapting beans that do not fire PropertyChangeEvents. This affects the classes PropertyAdapter, BeanAdapter, and PresentationModel. Basically the PropertyAdapter and the BeanAdapter's internal SimplePropertyAdapter's shall be able to optionally self-fire a PropertyChangeEvent in case the bean does not. There are several downsides with self-firing events compared to bound bean properties. See Issue 49 for more information about the downsides.
The observeChanges constructor parameter shall be replaced by a more fine-grained choice to not observe (former observeChanges=false), to observe bound properties (former observeChanges=true), and a new setting for self-firing PropertyChangeEvents if a value is set. The latter case may be further splitted up to specify how the self-fired PropertyChangeEvent is created:
BeanAdapter
,
ValueModel
,
ValueModel.getValue()
,
ValueModel.setValue(Object)
,
PropertyChangeEvent
,
PropertyChangeListener
,
Introspector
,
BeanInfo
,
PropertyDescriptor
Modifier and Type | Field and Description |
---|---|
static java.lang.String |
PROPERTYNAME_AFTER_BEAN
The property name used in the PropertyChangeEvent that is fired
after the bean property fires its PropertyChangeEvent.
|
static java.lang.String |
PROPERTYNAME_BEAN
The name of the read-write bound property that holds the target bean.
|
static java.lang.String |
PROPERTYNAME_BEFORE_BEAN
The property name used in the PropertyChangeEvent that is fired
before the bean property fires its PropertyChangeEvent.
|
static java.lang.String |
PROPERTYNAME_CHANGED
The name of the read-only bound bean property that
indicates whether one of the observed properties has changed.
|
PROPERTYNAME_VALUE
Constructor and Description |
---|
PropertyAdapter(B bean,
java.lang.String propertyName)
Constructs a
PropertyAdapter for the given
bean and property name; does not observe changes. |
PropertyAdapter(B bean,
java.lang.String propertyName,
boolean observeChanges)
Constructs a
PropertyAdapter for the given
bean and property name; observes changes if specified. |
PropertyAdapter(B bean,
java.lang.String propertyName,
java.lang.String getterName,
java.lang.String setterName)
Constructs a
PropertyAdapter for the given bean,
property name, getter and setter name; does not observe changes. |
PropertyAdapter(B bean,
java.lang.String propertyName,
java.lang.String getterName,
java.lang.String setterName,
boolean observeChanges)
Constructs a
PropertyAdapter for the given bean,
property name, getter and setter name; observes changes if specified. |
PropertyAdapter(ValueModel beanChannel,
java.lang.String propertyName)
Constructs a
PropertyAdapter for the given
bean channel and property name; does not observe changes. |
PropertyAdapter(ValueModel beanChannel,
java.lang.String propertyName,
boolean observeChanges)
Constructs a
PropertyAdapter for the given
bean channel and property name; observes changes if specified. |
PropertyAdapter(ValueModel beanChannel,
java.lang.String propertyName,
java.lang.String getterName,
java.lang.String setterName)
Constructs a
PropertyAdapter for the given bean channel,
property name, getter and setter name; does not observe changes. |
PropertyAdapter(ValueModel beanChannel,
java.lang.String propertyName,
java.lang.String getterName,
java.lang.String setterName,
boolean observeChanges)
Constructs a
PropertyAdapter for the given bean channel,
property name, getter and setter name; observes changes if specified. |
Modifier and Type | Method and Description |
---|---|
B |
getBean()
Returns the Java Bean that holds the adapted property.
|
boolean |
getObserveChanges()
Answers whether this adapter observes changes in the
adapted Bean property.
|
java.lang.String |
getPropertyName()
Returns the name of the adapted Java Bean property.
|
java.lang.Object |
getValue()
Returns the value of the bean's adapted property,
null
if the current bean is null . |
boolean |
isChanged()
Answers whether a bean property has changed since the changed state
has been reset.
|
protected java.lang.String |
paramString()
Returns a string representing the state of this model.
|
void |
release()
Removes the PropertyChangeHandler from the observed bean, if the bean
is not
null and if property changes are observed. |
void |
resetChanged()
Resets this tracker's changed state to
false . |
void |
setBean(B newBean)
Sets a new Java Bean as holder of the adapted property.
|
void |
setValue(java.lang.Object newValue)
Sets the given object as new value of the adapted bean property.
|
void |
setVetoableValue(java.lang.Object newValue)
Sets the given object as new value of the adapted bean property.
|
addValueChangeListener, booleanValue, doubleValue, fireValueChange, fireValueChange, fireValueChange, fireValueChange, fireValueChange, fireValueChange, fireValueChange, floatValue, getString, intValue, longValue, removeValueChangeListener, setValue, setValue, setValue, setValue, setValue, toString, valueString
createPropertyChangeSupport, firePropertyChange
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
addPropertyChangeListener, removePropertyChangeListener
public static final java.lang.String PROPERTYNAME_BEFORE_BEAN
public static final java.lang.String PROPERTYNAME_BEAN
getBean()
,
setBean(Object)
,
Constant Field Valuespublic static final java.lang.String PROPERTYNAME_AFTER_BEAN
public static final java.lang.String PROPERTYNAME_CHANGED
isChanged()
,
Constant Field Valuespublic PropertyAdapter(B bean, java.lang.String propertyName)
PropertyAdapter
for the given
bean and property name; does not observe changes.bean
- the bean that owns the propertypropertyName
- the name of the adapted propertyjava.lang.NullPointerException
- if propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptypublic PropertyAdapter(B bean, java.lang.String propertyName, boolean observeChanges)
PropertyAdapter
for the given
bean and property name; observes changes if specified.bean
- the bean that owns the propertypropertyName
- the name of the adapted propertyobserveChanges
- true
to observe changes of bound
or constrained properties, false
to ignore changesjava.lang.NullPointerException
- if propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptyPropertyUnboundException
- if observeChanges
is true but the property is unbound, i. e. the bean
does not provide a pair of methods to register a multicast
PropertyChangeListenerpublic PropertyAdapter(B bean, java.lang.String propertyName, java.lang.String getterName, java.lang.String setterName)
PropertyAdapter
for the given bean,
property name, getter and setter name; does not observe changes.bean
- the bean that owns the propertypropertyName
- the name of the adapted propertygetterName
- the optional name of the property readersetterName
- the optional name of the property writerjava.lang.NullPointerException
- if propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptypublic PropertyAdapter(B bean, java.lang.String propertyName, java.lang.String getterName, java.lang.String setterName, boolean observeChanges)
PropertyAdapter
for the given bean,
property name, getter and setter name; observes changes if specified.bean
- the bean that owns the propertypropertyName
- the name of the adapted propertygetterName
- the optional name of the property readersetterName
- the optional name of the property writerobserveChanges
- true
to observe changes of bound
or constrained properties, false
to ignore changesjava.lang.NullPointerException
- if propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptyPropertyUnboundException
- if observeChanges
is true but the property is unbound, i. e. the bean
does not provide a pair of methods to register a multicast
PropertyChangeListenerpublic PropertyAdapter(ValueModel beanChannel, java.lang.String propertyName)
PropertyAdapter
for the given
bean channel and property name; does not observe changes.beanChannel
- the ValueModel
that holds the beanpropertyName
- the name of the adapted propertyjava.lang.NullPointerException
- if beanChannel
or
propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptypublic PropertyAdapter(ValueModel beanChannel, java.lang.String propertyName, boolean observeChanges)
PropertyAdapter
for the given
bean channel and property name; observes changes if specified.beanChannel
- the ValueModel
that holds the beanpropertyName
- the name of the adapted propertyobserveChanges
- true
to observe changes of bound
or constrained properties, false
to ignore changesjava.lang.NullPointerException
- if beanChannel
or
propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptyPropertyUnboundException
- if observeChanges
is true but the property is unbound, i. e. the bean
does not provide a pair of methods to register a multicast
PropertyChangeListenerPropertyAccessException
- if the beanChannel
's value
does not provide a property descriptor for propertyName
public PropertyAdapter(ValueModel beanChannel, java.lang.String propertyName, java.lang.String getterName, java.lang.String setterName)
PropertyAdapter
for the given bean channel,
property name, getter and setter name; does not observe changes.beanChannel
- the ValueModel
that holds the beanpropertyName
- the name of the adapted propertygetterName
- the optional name of the property readersetterName
- the optional name of the property writerjava.lang.NullPointerException
- if beanChannel
or
propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptypublic PropertyAdapter(ValueModel beanChannel, java.lang.String propertyName, java.lang.String getterName, java.lang.String setterName, boolean observeChanges)
PropertyAdapter
for the given bean channel,
property name, getter and setter name; observes changes if specified.beanChannel
- the ValueModel
that holds the beanpropertyName
- the name of the adapted propertygetterName
- the optional name of the property readersetterName
- the optional name of the property writerobserveChanges
- true
to observe changes of bound
or constrained properties, false
to ignore changesjava.lang.NullPointerException
- if propertyName
is null
java.lang.IllegalArgumentException
- if propertyName
is emptyjava.lang.IllegalArgumentException
- if the bean channel is a ValueHolder
that has the identityCheck feature disabledPropertyUnboundException
- if observeChanges
is true but the property is unbound, i. e. the bean
does not provide a pair of methods to register a multicast
PropertyChangeListenerPropertyAccessException
- if the beanChannel
's value
does not provide a property descriptor for propertyName
public B getBean()
setBean(Object)
public void setBean(B newBean)
newBean
- the new holder of the propertygetBean()
public java.lang.String getPropertyName()
public boolean getObserveChanges()
public java.lang.Object getValue()
null
if the current bean is null
.If the adapted bean property is write-only, this adapter is write-only too, and this operation is not supported and throws an exception.
java.lang.UnsupportedOperationException
- if the property is write-onlyPropertyNotFoundException
- if the property could not be foundPropertyAccessException
- if the value could not be readpublic void setValue(java.lang.Object newValue)
null
. If the bean setter
throws a PropertyVetoException, it is silently ignored.
This write operation is supported only for writable bean properties.Notifies any registered value listeners if the bean reports a property change. Note that a bean may suppress PropertyChangeEvents if the old and new value are the same, or if the old and new value are equal.
newValue
- the value to setjava.lang.UnsupportedOperationException
- if the property is read-onlyPropertyNotFoundException
- if the property could not be foundPropertyAccessException
- if the new value could not be setpublic void setVetoableValue(java.lang.Object newValue) throws java.beans.PropertyVetoException
null
. If the bean setter
throws a PropertyVetoExeption, this method throws the same exception.
This write operation is supported only for writable bean properties.Notifies any registered value listeners if the bean reports a property change. Note that a bean may suppress PropertyChangeEvents if the old and new value are the same, or if the old and new value are equal.
newValue
- the value to setjava.lang.UnsupportedOperationException
- if the property is read-onlyPropertyNotFoundException
- if the property could not be foundPropertyAccessException
- if the new value could not be setjava.beans.PropertyVetoException
- if the invoked bean setter
throws a PropertyVetoExceptionpublic boolean isChanged()
public void resetChanged()
false
.public void release()
null
and if property changes are observed.
PropertyAdapters that observe changes have a PropertyChangeListener
registered with the target bean. Hence, a bean has a reference to all
PropertyAdapters that observe it. To avoid memory leaks it is recommended
to remove this listener if the bean lives much longer than the
PropertyAdapter, enabling the garbage collector to remove the adapter.
To do so, you can call setBean(null)
or set the
bean channel's value to null.
As an alternative you can use event listener lists in your beans
that implement references with WeakReference
.
Setting the bean to null has side-effects, for example
this adapter fires a change event for the bound property bean
and other properties. And this adpter's value may change.
However, typically this is fine and setting the bean to null is
the first choice for removing the reference from the bean to the adapter.
Another way to clear the reference from the target bean is
to call #release
. It has no side-effects, but the adapter
must not be used anymore once #release has been called.
setBean(Object)
,
WeakReference
protected java.lang.String paramString()
AbstractValueModel
null
.paramString
in class AbstractValueModel
Copyright © 2002-2010 JGoodies Karsten Lentzsch. All Rights Reserved.