Overview | Package | Class | Use | Tree | Deprecated | Index | Help
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

## com.jgoodies.binding.beans
Class PropertyAdapter

    java.lang.Object
      com.jgoodies.binding.beans.Model
          com.jgoodies.binding.value.AbstractValueModel
              com.jgoodies.binding.beans.PropertyAdapter

All Implemented Interfaces:
  Observable, ValueModel, Serializable

    public final class PropertyAdapter

extends AbstractValueModel

Converts a single Java Bean property into the generic ValueModel interface. The bean property must be a single value as described by the Java Bean Specification. See below for a comparison with the more frequently used BeanAdapter and PresentationModel classes.

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:

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: 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
If you adapt multiple properties of the same bean, you better use a `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:
Builds an adapter chain from a domain model to the presentation layer.

     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:

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

Version:
  $Revision: 1.7 $
Author:
  Karsten Lentzsch
See Also:
  `BeanAdapter`, `ValueModel`, `ValueModel.getValue()`, `ValueModel.setValue(Object)`, `PropertyChangeEvent`, `PropertyChangeListener`, `Introspector`, `BeanInfo`, `PropertyDescriptor`, Serialized Form

Field Summary
`static String` | `PROPERTYNAME_AFTER_BEAN` The property name used in the PropertyChangeEvent that is fired after the bean property fires its PropertyChangeEvent.
`static String` | `PROPERTYNAME_BEAN` The name of the read-write bound property that holds the target bean.
`static String` | `PROPERTYNAME_BEFORE_BEAN` The property name used in the PropertyChangeEvent that is fired before the bean property fires its PropertyChangeEvent.
`static String` | `PROPERTYNAME_CHANGED` The name of the read-only bound bean property that indicates whether one of the observed properties has changed.

Fields inherited from class com.jgoodies.binding.value.AbstractValueModel
`PROPERTYNAME_VALUE`

Constructor Summary
`PropertyAdapter(Object bean, String propertyName)` Constructs a `PropertyAdapter` for the given bean and property name; does not observe changes.
`PropertyAdapter(Object bean, String propertyName, boolean observeChanges)` Constructs a `PropertyAdapter` for the given bean and property name; observes changes if specified.
`PropertyAdapter(Object bean, String propertyName, String getterName, String setterName)` Constructs a `PropertyAdapter` for the given bean, property name, getter and setter name; does not observe changes.
`PropertyAdapter(Object bean, String propertyName, String getterName, String setterName, boolean observeChanges)` Constructs a `PropertyAdapter` for the given bean, property name, getter and setter name; observes changes if specified.
`PropertyAdapter(ValueModel beanChannel, String propertyName)` Constructs a `PropertyAdapter` for the given bean channel and property name; does not observe changes.
`PropertyAdapter(ValueModel beanChannel, String propertyName, boolean observeChanges)` Constructs a `PropertyAdapter` for the given bean channel and property name; observes changes if specified.
`PropertyAdapter(ValueModel beanChannel, String propertyName, String getterName, String setterName)` Constructs a `PropertyAdapter` for the given bean channel, property name, getter and setter name; does not observe changes.
`PropertyAdapter(ValueModel beanChannel, String propertyName, String getterName, String setterName, boolean observeChanges)` Constructs a `PropertyAdapter` for the given bean channel, property name, getter and setter name; observes changes if specified.

Method Summary
`Object` | `getBean()` Returns the Java Bean that holds the adapted property.
`boolean` | `getObserveChanges()` Answers whether this adapter observes changes in the adapted Bean property.
`String` | `getPropertyName()` Returns the name of the adapted Java Bean property.
`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.
`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(Object newBean)` Sets a new Java Bean as holder of the adapted property.
`void` | `setValue(Object newValue)` Sets the given object as new value of the adapted bean property.
`void` | `setVetoableValue(Object newValue)` Sets the given object as new value of the adapted bean property.

Methods inherited from class com.jgoodies.binding.value.AbstractValueModel
`addValueChangeListener, booleanValue, doubleValue, fireValueChange, fireValueChange, fireValueChange, fireValueChange, fireValueChange, fireValueChange, fireValueChange, floatValue, getString, intValue, longValue, removeValueChangeListener, setValue, setValue, setValue, setValue, setValue, toString`

Methods inherited from class com.jgoodies.binding.beans.Model
`addPropertyChangeListener, addPropertyChangeListener, addVetoableChangeListener, addVetoableChangeListener, equals, fireMulticastPropertyChange, fireMultiplePropertiesChanged, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, fireVetoableChange, fireVetoableChange, fireVetoableChange, fireVetoableChange, fireVetoableChange, fireVetoableChange, getPropertyChangeListeners, getPropertyChangeListeners, getVetoableChangeListeners, getVetoableChangeListeners, removePropertyChangeListener, removePropertyChangeListener, removeVetoableChangeListener, removeVetoableChangeListener`

Methods inherited from class java.lang.Object
`clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

Field Detail

### PROPERTYNAME_BEFORE_BEAN

    public static final String PROPERTYNAME_BEFORE_BEAN

  The property name used in the PropertyChangeEvent that is fired before the bean property fires its PropertyChangeEvent. Useful to perform an operation before listeners that handle the bean change are notified. See also the class comment.

  See Also:
    Constant Field Values

### PROPERTYNAME_BEAN

    public static final String PROPERTYNAME_BEAN

  The name of the read-write bound property that holds the target bean.

  See Also:
    `getBean()`, `setBean(Object)`, Constant Field Values

### PROPERTYNAME_AFTER_BEAN

    public static final String PROPERTYNAME_AFTER_BEAN

  The property name used in the PropertyChangeEvent that is fired after the bean property fires its PropertyChangeEvent. Useful to perform an operation after listeners that handle the bean change are notified. See also the class comment.

  See Also:
    Constant Field Values

### PROPERTYNAME_CHANGED

    public static final String PROPERTYNAME_CHANGED

  The name of the read-only bound bean property that indicates whether one of the observed properties has changed.

  See Also:
    `isChanged()`, Constant Field Values

Constructor Detail

### PropertyAdapter

    public PropertyAdapter(Object bean,
                           String propertyName)

  Constructs a `PropertyAdapter` for the given bean and property name; does not observe changes.

  Parameters:
    `bean` - the bean that owns the property
    `propertyName` - the name of the adapted property
  Throws:
    `NullPointerException` - if `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty

### PropertyAdapter

    public PropertyAdapter(Object bean,
                           String propertyName,
                           boolean observeChanges)

  Constructs a `PropertyAdapter` for the given bean and property name; observes changes if specified.

  Parameters:
    `bean` - the bean that owns the property
    `propertyName` - the name of the adapted property
    `observeChanges` - `true` to observe changes of bound or constrained properties, `false` to ignore changes
  Throws:
    `NullPointerException` - if `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty
    `PropertyUnboundException` - if `observeChanges` is true but the property is unbound, i. e. the `bean` does not provide a pair of methods to register a multicast PropertyChangeListener

### PropertyAdapter

    public PropertyAdapter(Object bean,
                           String propertyName,
                           String getterName,
                           String setterName)

  Constructs a `PropertyAdapter` for the given bean, property name, getter and setter name; does not observe changes.

  Parameters:
    `bean` - the bean that owns the property
    `propertyName` - the name of the adapted property
    `getterName` - the optional name of the property reader
    `setterName` - the optional name of the property writer
  Throws:
    `NullPointerException` - if `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty

### PropertyAdapter

    public PropertyAdapter(Object bean,
                           String propertyName,
                           String getterName,
                           String setterName,
                           boolean observeChanges)

  Constructs a `PropertyAdapter` for the given bean, property name, getter and setter name; observes changes if specified.

  Parameters:
    `bean` - the bean that owns the property
    `propertyName` - the name of the adapted property
    `getterName` - the optional name of the property reader
    `setterName` - the optional name of the property writer
    `observeChanges` - `true` to observe changes of bound or constrained properties, `false` to ignore changes
  Throws:
    `NullPointerException` - if `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty
    `PropertyUnboundException` - if `observeChanges` is true but the property is unbound, i. e. the `bean` does not provide a pair of methods to register a multicast PropertyChangeListener

### PropertyAdapter

    public PropertyAdapter(ValueModel beanChannel,
                           String propertyName)

  Constructs a `PropertyAdapter` for the given bean channel and property name; does not observe changes.

  Parameters:
    `beanChannel` - the `ValueModel` that holds the bean
    `propertyName` - the name of the adapted property
  Throws:
    `NullPointerException` - if `beanChannel` or `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty

### PropertyAdapter

    public PropertyAdapter(ValueModel beanChannel,
                           String propertyName,
                           boolean observeChanges)

  Constructs a `PropertyAdapter` for the given bean channel and property name; observes changes if specified.

  Parameters:
    `beanChannel` - the `ValueModel` that holds the bean
    `propertyName` - the name of the adapted property
    `observeChanges` - `true` to observe changes of bound or constrained properties, `false` to ignore changes
  Throws:
    `NullPointerException` - if `beanChannel` or `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty
    `PropertyUnboundException` - if `observeChanges` is true but the property is unbound, i. e. the `bean` does not provide a pair of methods to register a multicast PropertyChangeListener
    `PropertyAccessException` - if the `beanChannel`'s value does not provide a property descriptor for `propertyName`

### PropertyAdapter

    public PropertyAdapter(ValueModel beanChannel,
                           String propertyName,
                           String getterName,
                           String setterName)

  Constructs a `PropertyAdapter` for the given bean channel, property name, getter and setter name; does not observe changes.

  Parameters:
    `beanChannel` - the `ValueModel` that holds the bean
    `propertyName` - the name of the adapted property
    `getterName` - the optional name of the property reader
    `setterName` - the optional name of the property writer
  Throws:
    `NullPointerException` - if `beanChannel` or `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty

### PropertyAdapter

    public PropertyAdapter(ValueModel beanChannel,
                           String propertyName,
                           String getterName,
                           String setterName,
                           boolean observeChanges)

  Constructs a `PropertyAdapter` for the given bean channel, property name, getter and setter name; observes changes if specified.

  Parameters:
    `beanChannel` - the `ValueModel` that holds the bean
    `propertyName` - the name of the adapted property
    `getterName` - the optional name of the property reader
    `setterName` - the optional name of the property writer
    `observeChanges` - `true` to observe changes of bound or constrained properties, `false` to ignore changes
  Throws:
    `NullPointerException` - if `propertyName` is `null`
    `IllegalArgumentException` - if `propertyName` is empty
    `IllegalArgumentException` - if the bean channel is a ValueHolder that has the identityCheck feature disabled
    `PropertyUnboundException` - if `observeChanges` is true but the property is unbound, i. e. the `bean` does not provide a pair of methods to register a multicast PropertyChangeListener
    `PropertyAccessException` - if the `beanChannel`'s value does not provide a property descriptor for `propertyName`

Method Detail

### getBean

    public Object getBean()

  Returns the Java Bean that holds the adapted property.

  Returns:
    the Bean that holds the adapted property
  See Also:
    `setBean(Object)`

### setBean

    public void setBean(Object newBean)

  Sets a new Java Bean as holder of the adapted property. Notifies any registered value listeners if the value has changed. Also notifies listeners that have been registered with this adapter to observe the bound property bean.

  Parameters:
    `newBean` - the new holder of the property
  See Also:
    `getBean()`

### getPropertyName

    public String getPropertyName()

  Returns the name of the adapted Java Bean property.

  Returns:
    the name of the adapted property

### getObserveChanges

    public boolean getObserveChanges()

  Answers whether this adapter observes changes in the adapted Bean property.

  Returns:
    true if this adapter observes changes, false if not

### getValue

    public Object getValue()

  Returns the value of the bean's adapted property, `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.

  Returns:
    the value of the adapted bean property, null if the bean is null
  Throws:
    `UnsupportedOperationException` - if the property is write-only
    `PropertyNotFoundException` - if the property could not be found
    `PropertyAccessException` - if the value could not be read

### setValue

    public void setValue(Object newValue)

  Sets the given object as new value of the adapted bean property. Does nothing if the bean is `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.

  Parameters:
    `newValue` - the value to set
  Throws:
    `UnsupportedOperationException` - if the property is read-only
    `PropertyNotFoundException` - if the property could not be found
    `PropertyAccessException` - if the new value could not be set

### setVetoableValue

    public void setVetoableValue(Object newValue)
                          throws PropertyVetoException

  Sets the given object as new value of the adapted bean property. Does nothing if the bean is `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.

  Parameters:
    `newValue` - the value to set
  Throws:
    `UnsupportedOperationException` - if the property is read-only
    `PropertyNotFoundException` - if the property could not be found
    `PropertyAccessException` - if the new value could not be set
    `PropertyVetoException` - if the invoked bean setter throws a PropertyVetoException
  Since:
    1.1

### isChanged

    public boolean isChanged()

  Answers whether a bean property has changed since the changed state has been reset. The changed state is implicitly reset everytime the target bean changes.

  Returns:
    true if a property of the current target bean has changed since the last reset

### resetChanged

    public void resetChanged()

  Resets this tracker's changed state to `false`.

### release

    public void release()

  Removes the PropertyChangeHandler from the observed bean, if the bean is not `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 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 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.

  See Also:
    `setBean(Object)`, `WeakReference`

Overview | Package | Class | Use | Tree | Deprecated | Index | Help
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

Copyright © 2002-2006 JGoodies Karsten Lentzsch. All Rights Reserved.