Getting Listeners from JavaBeansTM (轉)
An Amendment to the JavaBeans Specification
Hans Muller and Mark Davidson
<!-- @@@ print version @@@ -->Presently all of the state in an AWT component that can be written can also be read, e.g. there are no write-only properties in the component . Event listeners are a notable exception. AWT event listeners are managed according to the JavaBeans conventions with a pair of methods: addFooListener()
and removeFooListener()
for a listener that implements the FooListener
interface.
No access is provd to the listener lists themselves. The fields that contain the listener lists may be private, package private or protected and no methods are provided to return the contents of the listener lists. This has caused some problems for and other AWT clients:
- The Swing UI classes have to keep references to every listener they add, just to enable removing them if the UI is changed. Swing applications contain 1000's of references like this. In general, you can't clear any JavaBeans listener list unless you've kept a private copy.
- Archiving systems have to resort to implementation dependent sning to diver the contents of listener lists.
- Externalization isn't an option for classes derived from Component, like the Swing components, because the listeners are inaccessible.
To mitigate the problem in Java 2 Standard Edition () v 1.3 we added a getListeners(Class)
method to Component
and to the Swing classes that defined listener lists. The getListeners(Class)
method uses a Class
as its argument to specify a particular listener list. For example to get all of the listeners added with addFocusListener()
, one would write: getListeners(FocusListener.class)
.
This particular approach to exposing listener lists was taken to minimize the overall change to the AWT/Swing public API. It was not indented to be a pattern for all JavaBeans and it did not handle PropertyChangeListeners - which can be added to a single property, as in addPropertyChangeListener("myProperty", myListener)
.
The specific implementation of this work in the AWT and Swing is covered by bugParade/bugs/4290704.html">4290704.
Solution
The has been extended so that listener lists can optionally be read. Two extensions have been added:
- To the add/remove pattern for listeners: add an optional
get
method that returns an array of all of the listeners for a particular list.s() - Extend the
EventSetDescriptor
class to cover the newget
method. So that BeanInfreturned for classes by Introspection can recognize the new event pattern.s()
The rest of the document describes the changes to the JavaBeans Specification to support the new get
extension.
The additional methods and classes presented in this amendment have been implemented for Java 2 Standard Edition (J2SE) v 1.4. JavaBeans which have been written that extend Beans in the java.awt
or javax.swing
packages will automatically pick up the implementation of this amendment for existing listeners when J2SE 1.4 is used . If the extended Bean defines additional listeners, then the extended Bean should implement the appropriate get
methods.
Beans Specification Amendments
All additions or changes to the JavaBeans Specification are in red
6.5 Event Listener Registration
... public void add The add The get public abstract class Model { ... private List listeners = new ArrayList(0); public synchronized void ModelChangedListener[] getModelChangedListeners() { return (ModelChangedListener[])(listeners.toArray()); } ... } ... The PropertyChangeListener event listener interface is used to report updates to simple bound properties. If a bean supports bound properties then it should support the set of multi-cast event listener registration methods for PropertyChangeListeners: public void addPropertyChangeListener(PropertyChangeListener x); public void removePropertyChangeListener(PropertyChangeListener x); public PropertyChangeListener[] getPropertyChangeListeners(); ... The ... ... If a bean supports constrained properties then it should support a normal set of multi-cast event listener registration methods for VetoableChangeListeners: void addVetoableChangeListener(VetoableChangeListener x); void removeVetoableChangeListener(VetoableChangeListener x); VetoableChangeListener[] getVetoableChangeListeners(); The void addPropertyChangeListener(String propertyName, PropertyChangeListener listener); void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); PropertyChangeListener[] getPropertyChangeListeners(String propertyName); In this case, the bean should associate the given listener with the given property name, and only invoke it's propertyChange method when the given named property has been changed. Similarly, in addition to supporting the standard additional registration methods for adding and removing VetoableChangeListeners, beans may also support addition registration methods that are tied to a specific named property: void addVetoableChangeListener(String propertyName, VetoableChangeListener listener); void removeVetoableChangeListener(String propertyName, VetoableChangeListener listener); VetoableChangeListener[] getVetoableChangeListeners(String propertyName); When listeners for named properties are added to a bean, the zero argument retrieval method If the calling method is interested in distinguishing the listeners from the For example, if a import java.awt.*; import java.beans.*; public class JellyBean { ... public PropertyChangeListener[] getPropertyChangeListeners() { return changes.getPropertyChangeListeners(); } ... public VetoableChangeListener[] getVetoableChangeListeners() { return vetos.getVetoableChangeListeners(); } ... } package java.util; /** * An abstract wrapper class for an EventListener class which associates a set of * additional parameters with the listener. Subclasses must provide the storage and * accessor methods for the additional arguments or parameters. * * Subclasses of EventListenerProxy may be returned by getListeners() methods * as a way of associating named properties with their listeners. * * * @since 1.4 */ public class EventListenerProxy implements EventListener { private final EventListener listener; /** * @param listener The listener object * @param parameters List of parameters associated with the listener. */ public EventListenerProxy(EventListener listener) /** * @return The listener associated with this proxy. */ public EventListener getListener() } /** * A class which extends the EventListenerProxy specifically * for adding a named PropertyChangeListener. Instances of * this class can be added as PropertyChangeListener to * an object. * * If the object has a getPropertyChangeListeners() * method then the array returned could be a mixture of * PropertyChangeListener and PropertyChangeListenerProxy * objects. * * For example, a Bean which supports named properties would have a two argument * method signature for adding a PropertyChangeListener for a property: * * public void addPropertyChangeListener(String propertyName, * PropertyChangeListener listener); * * If the Bean also implemented the zero argument get listener method: * * public PropertyChangeListener[] getPropertyChangeListeners(); * * then the array may contain PropertyChangeListeners which are also * PropertyChangeListenerProxy objects. * * If the calling method is interested in retrieving the named property then it * would have to test the element to see if its a proxy class. * * @see java.util.EventListenerProxy * @since 1.4 */ public class PropertyChangeListenerProxy extends EventListenerProxy implements PropertyChangeListener { /** * Constructor which binds the PropertyChangeListener to a specific property. * * @param listener The listener object * @param propertyName The name of the property to listen on. // XXX - msd NOTE: I changed the order of the arguments so that it's similar to // PropertyChangeSupport.addPropertyChangeListener(String, PropertyChangeListener) */ public PropertyChangeListenerProxy(String propertyName, PropertyChangeListener listener) /** * @param listener The listener object * @param parameters List of parameters associated with the listener. */ public PropertyChangeListenerProxy(PropertyChangeListener listener, Object[] parameters) /** * Forwards the property change event to the listener delegate. * * @param evt the property change event */ public void propertyChange(PropertyChangeEvent evt) /** * Returns the name of the named property associated with the * listener. */ public String getPropertyName() } /** * A class which extends the EventListenerProxy specifically * for adding a named VetoableChangeListener. Instances of * this class can be added as VetoableChangeListener to * an object. * * If the object has a getVetoableChangeListeners() * method then the array returned could be a mixture of * VetoableChangeListener and VetoableChangeListenerProxy * objects. * * @see #EventListenerProxy * @since 1.4 */ public class VetoableChangeListenerProxy extends EventListenerProxy implements VetoableChangeListener { /** * @param propertyName The name of the property to listen on. * @param listener The listener object // XXX - msd NOTE: I changed the order of the arguments so that it's similar to // PropertyChangeSupport.addPropertyChangeListener(String, PropertyChangeListener) */ public VetoableChangeListenerProxy(String propertyName, VetoableChangeListener listener) /** * @param listener The listener object * @param parameters List of parameters associated with the listener. */ public VetoableChangeListenerProxy(VetoableChangeListener listener, Object[] parameters) /** * Forwards the property change event to the listener delegate. */ public void vetoableChange(PropertyChangeEvent evt) /** * Returns the name of the named property associated with the * listener. */ public String getPropertyName() } ... We look for a set of methods of the form: public void add where the first two methods take the same " ... The So for example: public void addFredListener(FredListener t); public void removeFredListener(FredListener t); public FredListener[] getFredListeners(); Defines a multi-cast event Implement the same changes as the multi-cast example /** * This constructor creates an EventSetDescriptor from scratch using * string names. * * @param sourceClass The class firing the event. * @param eventSetName The programmatic name of the event set. * Note that this should normally start with a lower-case character. * @param listenerType The Class of the target interface that events * will get delivered to. * @param listenerMethodNames The names of the methods that will get called * when the event gets delivered to its target listener interface. * @param addListenerMethodName The name of the method on the event source * that can be used to register an event listener object. * @param removeListenerMethodName The name of the method on the event source * that can be used to de-register an event listener object. * @param getListenerMethodName The name of the method on the event source * that can be used to access the array of event listener objects. * @exception IntrospectionException if an exception occurs during * introspection. * @since 1.4 */ public EventSetDescriptor(Class sourceClass, String eventSetName, Class listenerType, String listenerMethodNames[], String addListenerMethodName, String removeListenerMethodName, String getListenerMethodName) throws IntrospectionException /** * This constructor creates an EventSetDescriptor from scratch using * java.lang.reflect.Method and java.lang.Class objects. * * @param eventSetName The programmatic name of the event set. * @param listenerType The Class for the listener interface. * @param listenerMethods An array of Method objects describing each * of the event handling methods in the target listener. * @param addListenerMethod The method on the event source * that can be used to register an event listener object. * @param removeListenerMethod The method on the event source * that can be used to de-register an event listener object. * @param getListenerMethod The method on the event source * that can be used to access the array of event listener object. * @exception IntrospectionException if an exception occurs during * introspection. * @since 1.4 */ public EventSetDescriptor(String eventSetName, Class listenerType, Method listenerMethods[], Method addListenerMethod, Method removeListenerMethod, Method getListenerMethod) throws IntrospectionException /** * Gets the method used to access the event listeners. * * @return The method used to access the array of listeners at the * event source or null if it doesn't exist * @since 1.4 */ public Method getGetListenerMethod() The The For backwards compatibility, the PropertyChangeSupport has had the following methods added: public PropertyChangeListener[] getPropertyChangeListeners(); public PropertyChangeListener[] getPropertyChangeListeners(String propertyName); VetoableChangeSupport has had the following methods added: public VetoableChangeListener[] getVetoableChangeListeners(); public VetoableChangeListener[] getVetoableChangeListeners(String propertyName); 6.5.1 Event Registration Example
7.4.1 Bound properties
getPropertyChangeListeners
method is optional. It was added in the XX revision of this specification and as a consequence beans defined per earlier revisions don't support it. Also, the getPropertyChangeListeners
method may return a mixture of PropertyChangeListener
s and PropertyChangeListener
s (which implement PropertyChangeListener
) if the bean supports listening on named properties. See Section 7.4.5.1 (section number may change - msd) for details. 7.4.2 Constrained properties
getVetoableChangeListeners
method is optional. It was added in the XX revision of this specification and as a consequence beans defined per earlier revisions don't support it. Also, the getVetoableChangeListeners
method may return a mixture of VetoableChangeListener
s and VetoableChangeListenerProxy
objects (which implement VetoableChangeListener
) if the bean supports listening on named properties. See Section 7.4.5.1 (section number may change - msd) for details. 7.4.5 Optional support for listening on named properties
In addition to supporting the standard design pattern for adding, retrieving and removing PropertyChangeListeners shown in Section 7.4.1 above, a bean that fires PropertyChangeEvents may also support an additional set methods that allow a PropertyChangeListener to be added, retrieved and removed for a named property:
7.4.5.1 Retrieval of listeners for named properties
getPropertyChangeListener
s (or similarly, getVetoableChangeListener
s) will return all the listeners added to the bean. For beans which support named properties, the definition of getListeners()
has been extended to mean that it would return the real listener, or a subclass of an EventListenerProxy
for listeners added with additional parameters. Subclasses of EventListenerProxy
s may be used to identify the listeners associated with specific named properties. getXXXListeners()
method, then it must check each element to see if its an EventListenerProxy
or subclass, perfothe appropriate cast and extract the additional parameters.PropertyChangeListener
was added with a named property to a bean with the addPropertyChangeListener("propertyName", listener)
, then the no argument getPropertyChangeListeners()
method may return a set of PropertyChangeListener
s and PropertyChangeListenerProxy
s. If the calling method is interested in retrieving the name of the property, then it must test each element to see if its a PropertyChangeListenerProxy
. 7.4.7 A bound and constrained example
... We use instances of the PropertyChangeSupport and VetoableChangeSupport classes to help us keep track of the event listeners and to deliver the actual events.
Javadoc for EventListenerProxy
8.4 Design Patterns for Eventsget
method is optional. It was added in the XX revision of this specification and as a consequence beans defined per earlier revisions don't support it. Also, the get
method may return a mixture of EventListenerProxy
objects if the bean supports listening on named properties. See Section 7.4.5.1 (section number may change - msd) for details. 8.4.1 Unicast event sources
JavaDoc for EventSetDescriptor (additional contructors and accessor method)
Implementation Details
get
methods have been added in J2SE v 1.4 for all classes in the javax.swing
and java.awt
packages and sub packages which implement listener registration.Changes to java.beans.EventSetDescriptor
EventSetDescriptor
has been amended to support the get
method. This means that two new constructors and the accessor method have been added. EventSetDescriptor
will not fail if the getListener() methods do not exist. However, the getGetListenerMethod()
will return null if that method doesn't exist.Changes to java.beans.PropertyChangeSupport
Changes to java.beans.VetoableChangeSupport
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991231/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Getting oracle agent installation from oemOracle
- Camunda中的Execution listeners和Task listeners
- TECH: Getting a Stack Trace from a CORE file on Unix (Doc ID 1812.1)
- Getting Testing PKGBUILDs(轉)UI
- 對話#25:Getting to the Point (轉)
- Camunda User Task:Task Listeners
- Linux kernel 'getting buggier'[英文](轉)Linux
- Beaglebone - Getting Started
- appium 初始化安裝的時候報錯 Error getting strings.xml from apkAPPErrorXMLAPK
- [移動端新特性] Passive Event Listeners
- [轉]How to release space from databaseDatabase
- getting started with transformjsORMJS
- Windows HLK Getting StartedWindows
- Result Sets from Stored Procedures In Oracle (轉)Oracle
- $attrs 與 $listeners 進行「巢狀元件」通訊巢狀元件
- 關於 vue2.x 的 $attrs 和 $listenersVue
- Vue 父子元件資料傳遞( inheritAttrs + $attrs + $listeners)Vue元件
- Hive Getting Started補充Hive
- ElasticSearch 2 (1) - Getting StartElasticsearch
- Getting More Information about PartitionsORM
- Getting NOW() in your preferred time zone
- Module 1 Getting to know you
- 1、 Getting Stared with Database AdministrationDatabase
- Firebase Tutorial: Getting Started 教程翻譯
- Getting Approximate Row Count of a Huge FileAPP
- 1. Getting Stared with Database AdministrationDatabase
- 優雅地亂玩Redux: Getting StartedRedux
- 排查not eligible for getting processed by all BeanPostProcessorsBean
- Repca: Error -Sqlexception On Getting Sid And Systemname InformationPCAErrorSQLExceptionORM
- 【轉載】使用 BAPI_BUPA_CREATE_FROM_DATA 建立BPAPI
- 大資料CHENGDAYE中日期轉換FROM_大資料
- [轉]Updating Session Variables from Dashboards using Presentation VariablesSession
- 轉:SAP學習筆記(from 神話blog)筆記
- Getting going quickly with Python, MongoDB and Spatial dataUIPythonMongoDB
- web2.0創業寶典-Getting RealWeb創業
- [AlwaysOn2017] AlwaysOn的DMV和DMF - Sys.availability_group_listenersAI
- 在 Android 上使用協程(二):Getting startedAndroid
- 在 Android 上使用協程(一):Getting The BackgroundAndroid