sun.com/products/javabeans/docs/spec.html">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:
- this adapter's bean channel fires a value change,
- this adapter fires a beforeBean change,
- this adapter fires the bean change,
- this adapter fires an afterBean change.
Unused PropertyAdapters that observe changes have a PropertyChangeListener registered with the target bean if the bean is not null. It is recommended to remove this listener by invoking #release
if the observed bean lives much longer than the adapter. After #release has been called you cannot use the PropertyAdapter instance any longer. As an alternative you can use event listener lists that implement references with WeakReference
.
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 {@link net.helipilot50.stocktrade.displayproject.binding.beans.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 {@link net.helipilot50.stocktrade.displayproject.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() 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");
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:
- oldValue=null, newValue=null
- oldValue=null, newValue=the value set
- oldValue=value read before the set, newValue=the value set
- oldValue=value read before the set, newValue=value read after the set
@author Karsten Lentzsch
@version $Revision: 1.23 $
@see net.helipilot50.stocktrade.displayproject.binding.beans.BeanAdapter
@see ValueModel
@see ValueModel#getValue()
@see ValueModel#setValue(Object)
@see PropertyChangeEvent
@see PropertyChangeListener
@see java.beans.Introspector
@see java.beans.BeanInfo
@see PropertyDescriptor Copyright (c) 2002-2005 JGoodies Karsten Lentzsch. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: o Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. o Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. o Neither the name of JGoodies Karsten Lentzsch nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.