Logo Search packages:      
Sourcecode: libjgoodies-binding-java version File versions

com::jgoodies::binding::beans::BeanAdapter Class Reference

Inheritance diagram for com::jgoodies::binding::beans::BeanAdapter:

com::jgoodies::binding::beans::Model com::jgoodies::binding::beans::Observable

List of all members.


Detailed Description

Converts multiple Java Bean properties into ValueModels. The bean properties must be single valued properties as described by the Java Bean Specification. See below for a comparison with the more frequently used PresentationModel class and the rarely used PropertyAdapter.

ValueModels can be created for a property name using getValueModel(String) or for a triple of (property name, getter name, setter name) using getValueModel(String, String, String). 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 method that accepts 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. Note: For each property name subsequent calls to these methods must use the same getter and setter names. Attempts to violate this constraint are rejected with an IllegalArgumentException.

Property values for a given property name can be read using getValue(String). To set a value for a for a property name invoke setValue(String, Object).

Optionally the BeanAdapter can observe changes in bound properties as described in section 7.4 of the Bean specification. The bean then must provide support for listening on properties as described in section 7.4 of this specification. You can enable this feature by setting the constructor parameter observeChanges to true. If the adapter observes changes, the ValueModels returned by getValueModel 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.

In addition you can observe the bean's bound properties by registering PropertyChangeListeners with the bean using addBeanPropertyChangeListener. These listeners will be removed from the old bean before the bean changes and will be re-added after the new bean has been set. Therefore these listeners will be notified about changes only if the current bean changes a property. They won't be notified if the bean changes - and in turn the property value. If you want to observes property changes caused by bean changes too, register with the adapting ValueModel as returned by getValueModel(String).

The BeanAdapter 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 properties.

If the adapted bean is null the BeanAdapter 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:

  1. this adapter's bean channel fires a value change,
  2. this adapter fires a beforeBean change,
  3. this adapter fires the bean change,
  4. this adapter fires an afterBean change.

Note: BeanAdapters that observe changes have a PropertyChangeListener registered with the target bean. Hence, a bean has a reference to any BeanAdapter that observes it. To avoid memory leaks it is recommended to remove this listener if the bean lives much longer than the BeanAdapter, 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 value of ValueModel's vended by this adapter 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
Basically the BeanAdapter does for multiple properties what the com.jgoodies.binding.beans.PropertyAdapter does for a single bean property. If you adapt multiple properties of the same bean, you better use the BeanAdapter. It registers 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 com.jgoodies.binding.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()
 BeanAdapter adapter = new BeanAdapter(address);
 adapter.setValue("street", "Broadway");
 System.out.println(address.getStreet());        // Prints "Broadway"
 address.setStreet("Franz-Josef-Str.");
 System.out.println(adapter.getValue("street")); // Prints "Franz-Josef-Str."

 //Direct access, observes changes
 BeanAdapter adapter = new BeanAdapter(address, true);

 // Indirect access, ignores changes
 ValueHolder addressHolder = new ValueHolder(address1);
 BeanAdapter adapter = new BeanAdapter(addressHolder);
 adapter.setValue("street", "Broadway");         // Sets the street in address1
 System.out.println(address1.getStreet());       // Prints "Broadway"
 adapter.setBean(address2);
 adapter.setValue("street", "Robert-Koch-Str."); // Sets the street in address2
 System.out.println(address2.getStreet());       // Prints "Robert-Koch-Str."

 // Indirect access, observes changes
 ValueHolder addressHolder = new ValueHolder();
 BeanAdapter adapter = new BeanAdapter(addressHolder, true);
 addressHolder.setValue(address1);
 address1.setStreet("Broadway");
 System.out.println(adapter.getValue("street")); // Prints "Broadway"

 // Access through ValueModels
 Address address = new Address();
 BeanAdapter adapter = new BeanAdapter(address);
 ValueModel streetModel = adapter.getValueModel("street");
 ValueModel cityModel   = adapter.getValueModel("city");
 streetModel.setValue("Broadway");
 System.out.println(address.getStreet());        // Prints "Broadway"
 address.setCity("Hamburg");
 System.out.println(cityModel.getValue());       // Prints "Hamburg"
 

Adapter Chain Example:
Builds an adapter chain from a domain model to the presentation layer.

 Country country = new Country();
 country.setName("Germany");
 country.setEuMember(true);

 BeanAdapter countryAdapter = new BeanAdapter(country, true);

 JTextField nameField = new JTextField();
 nameField.setDocument(new DocumentAdapter(
     countryAdapter.getValueModel("name")));

 JCheckBox euMemberBox = new JCheckBox("Is EU Member");
 euMemberBox.setModel(new ToggleButtonAdapter(
      countryAdapter.getValueModel("euMember")));

 // Using factory methods
 JTextField nameField   = Factory.createTextField(country, "name");
 JCheckBox  euMemberBox = Factory.createCheckBox (country, "euMember");
 euMemberBox.setText("Is EU Member");
 

As of version 1.3 this class is no longer marked as final, but lacks the documentation for subclass constraints. I plan to introduce an interface that shall describe the semantics required by the PresentationModel class. Until then, this BeanAdapter implementation describes the semantics and all constraints.

TODO: Improve the class comment and focus on the main features.

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:

  1. oldValue=null, newValue=null
  2. oldValue=null, newValue=the value set
  3. oldValue=value read before the set, newValue=the value set
  4. oldValue=value read before the set, newValue=value read after the set

Author:
Karsten Lentzsch
Version:
Revision
1.20

See also:
com.jgoodies.binding.beans.PropertyAdapter

ValueModel

ValueModel::getValue()

ValueModel::setValue(Object)

PropertyChangeEvent

PropertyChangeListener

java.beans.Introspector

java.beans.BeanInfo

PropertyDescriptor

Definition at line 282 of file BeanAdapter.java.


Public Member Functions

synchronized void addBeanPropertyChangeListener (String propertyName, PropertyChangeListener listener)
synchronized void addBeanPropertyChangeListener (PropertyChangeListener listener)
final synchronized void addPropertyChangeListener (String propertyName, PropertyChangeListener listener)
final synchronized void addPropertyChangeListener (PropertyChangeListener listener)
final synchronized void addVetoableChangeListener (String propertyName, VetoableChangeListener listener)
final synchronized void addVetoableChangeListener (VetoableChangeListener listener)
 BeanAdapter (ValueModel beanChannel, boolean observeChanges)
 BeanAdapter (ValueModel beanChannel)
 BeanAdapter (Object bean, boolean observeChanges)
 BeanAdapter (Object bean)
Object getBean ()
ValueModel getBeanChannel ()
synchronized
PropertyChangeListener[] 
getBeanPropertyChangeListeners (String propertyName)
synchronized
PropertyChangeListener[] 
getBeanPropertyChangeListeners ()
boolean getObserveChanges ()
final synchronized
PropertyChangeListener[] 
getPropertyChangeListeners (String propertyName)
final synchronized
PropertyChangeListener[] 
getPropertyChangeListeners ()
Object getValue (String propertyName)
SimplePropertyAdapter getValueModel (String propertyName, String getterName, String setterName)
SimplePropertyAdapter getValueModel (String propertyName)
final synchronized
VetoableChangeListener[] 
getVetoableChangeListeners (String propertyName)
final synchronized
VetoableChangeListener[] 
getVetoableChangeListeners ()
boolean isChanged ()
synchronized void release ()
synchronized void removeBeanPropertyChangeListener (String propertyName, PropertyChangeListener listener)
synchronized void removeBeanPropertyChangeListener (PropertyChangeListener listener)
final synchronized void removePropertyChangeListener (String propertyName, PropertyChangeListener listener)
final synchronized void removePropertyChangeListener (PropertyChangeListener listener)
final synchronized void removeVetoableChangeListener (String propertyName, VetoableChangeListener listener)
final synchronized void removeVetoableChangeListener (VetoableChangeListener listener)
void resetChanged ()
void setBean (Object newBean)
void setValue (String propertyName, Object newValue)
void setVetoableValue (String propertyName, Object newValue) throws PropertyVetoException

Static Public Attributes

static final String PROPERTYNAME_AFTER_BEAN = "afterBean"
static final String PROPERTYNAME_BEAN = "bean"
static final String PROPERTYNAME_BEFORE_BEAN = "beforeBean"
static final String PROPERTYNAME_CHANGED = "changed"

Protected Member Functions

SimplePropertyAdapter createPropertyAdapter (String propertyName, String getterName, String setterName)
final boolean equals (Object o1, Object o2)
final void fireMultiplePropertiesChanged ()
final void firePropertyChange (String propertyName, long oldValue, long newValue)
final void firePropertyChange (String propertyName, int oldValue, int newValue)
final void firePropertyChange (String propertyName, float oldValue, float newValue)
final void firePropertyChange (String propertyName, double oldValue, double newValue)
final void firePropertyChange (String propertyName, boolean oldValue, boolean newValue)
final void firePropertyChange (String propertyName, Object oldValue, Object newValue, boolean checkIdentity)
final void firePropertyChange (String propertyName, Object oldValue, Object newValue)
final void firePropertyChange (PropertyChangeEvent event)
final void fireVetoableChange (String propertyName, long oldValue, long newValue) throws PropertyVetoException
final void fireVetoableChange (String propertyName, float oldValue, float newValue) throws PropertyVetoException
final void fireVetoableChange (String propertyName, int oldValue, int newValue) throws PropertyVetoException
final void fireVetoableChange (String propertyName, double oldValue, double newValue) throws PropertyVetoException
final void fireVetoableChange (String propertyName, boolean oldValue, boolean newValue) throws PropertyVetoException
final void fireVetoableChange (String propertyName, Object oldValue, Object newValue) throws PropertyVetoException
final void fireVetoableChange (PropertyChangeEvent event) throws PropertyVetoException

Package Functions

SimplePropertyAdapter getPropertyAdapter (String propertyName)

Package Attributes

Object storedOldBean

Private Member Functions

void addChangeHandlerTo (Object bean)
void checkBeanChannelIdentityCheck (ValueModel valueModel) throws IllegalArgumentException
void forwardAllAdaptedValuesChanged ()
void forwardAllAdaptedValuesChanged (Object oldBean, Object newBean)
Class getBeanClass (Object bean)
Object getValue0 (Object bean, PropertyDescriptor propertyDescriptor)
void removeChangeHandlerFrom (Object bean)
void setBean0 (Object oldBean, Object newBean)
void setChanged (boolean newValue)
void setValue0 (Object bean, PropertyDescriptor propertyDescriptor, Object newValue) throws PropertyVetoException

Private Attributes

final ValueModel beanChannel
boolean changed = false
IndirectPropertyChangeSupport indirectChangeSupport
final boolean observeChanges
final Map propertyAdapters
PropertyChangeListener propertyChangeHandler

Classes

class  BeanChangeHandler
class  PropertyChangeHandler
class  SimplePropertyAdapter

The documentation for this class was generated from the following file:

Generated by  Doxygen 1.6.0   Back to index