summaryrefslogtreecommitdiff
path: root/java/beans
diff options
context:
space:
mode:
Diffstat (limited to 'java/beans')
-rw-r--r--java/beans/DefaultPersistenceDelegate.java17
-rw-r--r--java/beans/Encoder.java45
-rw-r--r--java/beans/EventSetDescriptor.java1109
-rw-r--r--java/beans/PersistenceDelegate.java5
-rw-r--r--java/beans/PropertyChangeSupport.java25
-rw-r--r--java/beans/XMLDecoder.java6
-rw-r--r--java/beans/XMLEncoder.java2
7 files changed, 761 insertions, 448 deletions
diff --git a/java/beans/DefaultPersistenceDelegate.java b/java/beans/DefaultPersistenceDelegate.java
index 9dd1ae564..ca1041fef 100644
--- a/java/beans/DefaultPersistenceDelegate.java
+++ b/java/beans/DefaultPersistenceDelegate.java
@@ -157,6 +157,23 @@ public class DefaultPersistenceDelegate extends PersistenceDelegate
protected void initialize(Class type, Object oldInstance, Object newInstance,
Encoder out)
{
+ // Calling the supertype's implementation of initialize makes it
+ // possible that descendants of classes like AbstractHashMap
+ // or Hashtable are serialized correctly. This mechanism grounds on
+ // two other facts:
+ // * Each class which has not registered a special purpose
+ // PersistenceDelegate is handled by a DefaultPersistenceDelegate
+ // instance.
+ // * PersistenceDelegate.initialize() is implemented in a way that it
+ // calls the initialize method of the superclass' persistence delegate.
+ super.initialize(type, oldInstance, newInstance, out);
+
+ // Suppresses the writing of property setting statements when this delegate
+ // is not used for the exact instance type. By doing so the following code
+ // is called only once per object.
+ if (type != oldInstance.getClass())
+ return;
+
try
{
PropertyDescriptor[] propertyDescs = Introspector.getBeanInfo(
diff --git a/java/beans/Encoder.java b/java/beans/Encoder.java
index e7b53d786..cde1735f4 100644
--- a/java/beans/Encoder.java
+++ b/java/beans/Encoder.java
@@ -1,5 +1,5 @@
/* Encoder.java
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,21 +38,16 @@
package java.beans;
+import gnu.java.beans.DefaultExceptionListener;
import gnu.java.beans.encoder.ArrayPersistenceDelegate;
import gnu.java.beans.encoder.ClassPersistenceDelegate;
import gnu.java.beans.encoder.CollectionPersistenceDelegate;
import gnu.java.beans.encoder.MapPersistenceDelegate;
import gnu.java.beans.encoder.PrimitivePersistenceDelegate;
-import java.util.ArrayList;
+import java.util.AbstractCollection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.IdentityHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
/**
* @author Robert Schuster (robertschuster@fsfe.org)
@@ -123,31 +118,11 @@ public class Encoder
delegates.put(Object[].class, new ArrayPersistenceDelegate());
pd = new CollectionPersistenceDelegate();
- delegates.put(ArrayList.class, pd);
- delegates.put(LinkedList.class, pd);
- delegates.put(Vector.class, pd);
- delegates.put(HashSet.class, pd);
- delegates.put(LinkedHashSet.class, pd);
- delegates.put(TreeSet.class, pd);
+ delegates.put(AbstractCollection.class, pd);
pd = new MapPersistenceDelegate();
- delegates.put(HashMap.class, pd);
- delegates.put(TreeMap.class, pd);
+ delegates.put(java.util.AbstractMap.class, pd);
delegates.put(java.util.Hashtable.class, pd);
- delegates.put(java.util.IdentityHashMap.class, pd);
-
- delegates.put(java.util.LinkedHashMap.class, pd);
- delegates.put(java.util.Properties.class, pd);
-
- delegates.put(java.awt.RenderingHints.class, pd);
- delegates.put(java.util.WeakHashMap.class, pd);
- delegates.put(javax.swing.UIDefaults.class, pd);
-
- // TODO: These classes need to be implemented first
- //delegates.put(java.security.AuthProvider.class, pd);
- //delegates.put(java.util.concurrent.ConcurrentHashMap.class, pd);
- //delegates.put(java.util.EnumMap.class, pd);
- //delegates.put(javax.management.openmbean.TabularDataSupport.class, pd);
defaultPersistenceDelegate = new DefaultPersistenceDelegate();
delegates.put(Object.class, defaultPersistenceDelegate);
@@ -194,14 +169,8 @@ public class Encoder
*/
public void setExceptionListener(ExceptionListener listener)
{
- exceptionListener = (listener != null) ? listener : new ExceptionListener()
- {
- public void exceptionThrown(Exception e)
- {
- System.err.println("exception thrown: " + e);
- e.printStackTrace();
- }
- };
+ exceptionListener = (listener != null)
+ ? listener : DefaultExceptionListener.INSTANCE;
}
/**
diff --git a/java/beans/EventSetDescriptor.java b/java/beans/EventSetDescriptor.java
index e687b8a30..381a45303 100644
--- a/java/beans/EventSetDescriptor.java
+++ b/java/beans/EventSetDescriptor.java
@@ -45,398 +45,719 @@ import java.lang.reflect.Modifier;
import java.util.Vector;
/**
- ** EventSetDescriptor describes the hookup between an event source
- ** class and an event listener class.
- **
- ** EventSets have several attributes: the listener class, the events
- ** that can be fired to the listener (methods in the listener class), and
- ** an add and remove listener method from the event firer's class.<P>
- **
- ** The methods have these constraints on them:<P>
- ** <UL>
- ** <LI>event firing methods: must have <CODE>void</CODE> return value. Any
- ** parameters and exceptions are allowed. May be public, protected or
- ** package-protected. (Don't ask me why that is, I'm just following the spec.
- ** The only place it is even mentioned is in the Java Beans white paper, and
- ** there it is only implied.)</LI>
- ** <LI>add listener method: must have <CODE>void</CODE> return value. Must
- ** take exactly one argument, of the listener class's type. May fire either
- ** zero exceptions, or one exception of type <CODE>java.util.TooManyListenersException</CODE>.
- ** Must be public.</LI>
- ** <LI>remove listener method: must have <CODE>void</CODE> return value.
- ** Must take exactly one argument, of the listener class's type. May not
- ** fire any exceptions. Must be public.</LI>
- ** </UL>
- **
- ** A final constraint is that event listener classes must extend from EventListener.<P>
- **
- ** There are also various design patterns associated with some of the methods
- ** of construction. Those are explained in more detail in the appropriate
- ** constructors.<P>
- **
- ** <STRONG>Documentation Convention:</STRONG> for proper
- ** Internalization of Beans inside an RAD tool, sometimes there
- ** are two names for a property or method: a programmatic, or
- ** locale-independent name, which can be used anywhere, and a
- ** localized, display name, for ease of use. In the
- ** documentation I will specify different String values as
- ** either <EM>programmatic</EM> or <EM>localized</EM> to
- ** make this distinction clear.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.1.0, 31 May 1998
- **/
-
-public class EventSetDescriptor extends FeatureDescriptor {
- private Method addListenerMethod;
- private Method removeListenerMethod;
- private Class<?> listenerType;
- private MethodDescriptor[] listenerMethodDescriptors;
- private Method[] listenerMethods;
-
- private boolean unicast;
- private boolean inDefaultEventSet = true;
-
- /** Create a new EventSetDescriptor.
- ** This version of the constructor enforces the rules imposed on the methods
- ** described at the top of this class, as well as searching for:<P>
- ** <OL>
- ** <LI>The event-firing method must be non-private with signature
- ** <CODE>void &lt;listenerMethodName&gt;(&lt;eventSetName&gt;Event)</CODE>
- ** (where <CODE>&lt;eventSetName&gt;</CODE> has its first character capitalized
- ** by the constructor and the Event is a descendant of
- ** <CODE>java.util.EventObject</CODE>) in class <CODE>listenerType</CODE>
- ** (any exceptions may be thrown).
- ** <B>Implementation note:</B> Note that there could conceivably be multiple
- ** methods with this type of signature (example: java.util.MouseEvent vs.
- ** my.very.own.MouseEvent). In this implementation, all methods fitting the
- ** description will be put into the <CODE>EventSetDescriptor</CODE>, even
- ** though the spec says only one should be chosen (they probably weren't thinking as
- ** pathologically as I was). I don't like arbitrarily choosing things.
- ** If your class has only one such signature, as most do, you'll have no problems.</LI>
- ** <LI>The add and remove methods must be public and named
- ** <CODE>void add&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</CODE> and
- ** <CODE>void remove&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</CODE> in
- ** in class <CODE>eventSourceClass</CODE>, where
- ** <CODE>&lt;eventSetName&gt;</CODE> will have its first letter capitalized.
- ** Standard exception rules (see class description) apply.</LI>
- ** </OL>
- ** @param eventSourceClass the class containing the add/remove listener methods.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu). This will be used
- ** to generate the name of the event object as well as the names of the add and
- ** remove methods.
- ** @param listenerType the class containing the event firing method.
- ** @param listenerMethodName the name of the event firing method.
- ** @exception IntrospectionException if listenerType is not an EventListener,
- ** or if methods are not found or are invalid.
- **/
- public EventSetDescriptor(Class<?> eventSourceClass,
- String eventSetName,
- Class<?> listenerType,
- String listenerMethodName) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- String[] names = new String[1];
- names[0] = listenerMethodName;
-
- try {
- eventSetName = Character.toUpperCase(eventSetName.charAt(0)) + eventSetName.substring(1);
- } catch(StringIndexOutOfBoundsException e) {
- eventSetName = "";
- }
-
- findMethods(eventSourceClass,listenerType,names,"add"+eventSetName+"Listener","remove"+eventSetName+"Listener",eventSetName+"Event");
- this.listenerType = listenerType;
- checkAddListenerUnicast();
- if(this.removeListenerMethod.getExceptionTypes().length > 0) {
- throw new IntrospectionException("Listener remove method throws exceptions.");
- }
- }
-
- /** Create a new EventSetDescriptor.
- ** This form of the constructor allows you to specify the names of the methods and adds
- ** no new constraints on top of the rules already described at the top of the class.<P>
- **
- ** @param eventSourceClass the class containing the add and remove listener methods.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu).
- ** @param listenerType the class containing the event firing methods.
- ** @param listenerMethodNames the names of the even firing methods.
- ** @param addListenerMethodName the name of the add listener method.
- ** @param removeListenerMethodName the name of the remove listener method.
- ** @exception IntrospectionException if listenerType is not an EventListener
- ** or if methods are not found or are invalid.
- **/
- public EventSetDescriptor(Class<?> eventSourceClass,
- String eventSetName,
- Class<?> listenerType,
- String[] listenerMethodNames,
- String addListenerMethodName,
- String removeListenerMethodName) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- findMethods(eventSourceClass,listenerType,listenerMethodNames,addListenerMethodName,removeListenerMethodName,null);
- this.listenerType = listenerType;
- checkAddListenerUnicast();
- if(this.removeListenerMethod.getExceptionTypes().length > 0) {
- throw new IntrospectionException("Listener remove method throws exceptions.");
- }
- }
-
- /** Create a new EventSetDescriptor.
- ** This form of constructor allows you to explicitly say which methods do what, and
- ** no reflection is done by the EventSetDescriptor. The methods are, however,
- ** checked to ensure that they follow the rules set forth at the top of the class.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu).
- ** @param listenerType the class containing the listenerMethods.
- ** @param listenerMethods the event firing methods.
- ** @param addListenerMethod the add listener method.
- ** @param removeListenerMethod the remove listener method.
- ** @exception IntrospectionException if the listenerType is not an EventListener,
- ** or any of the methods are invalid.
- **/
- public EventSetDescriptor(String eventSetName,
- Class<?> listenerType,
- Method[] listenerMethods,
- Method addListenerMethod,
- Method removeListenerMethod) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- this.listenerMethods = listenerMethods;
- this.addListenerMethod = addListenerMethod;
- this.removeListenerMethod = removeListenerMethod;
- this.listenerType = listenerType;
- checkMethods();
- checkAddListenerUnicast();
- if(this.removeListenerMethod.getExceptionTypes().length > 0) {
- throw new IntrospectionException("Listener remove method throws exceptions.");
- }
- }
-
- /** Create a new EventSetDescriptor.
- ** This form of constructor allows you to explicitly say which methods do what, and
- ** no reflection is done by the EventSetDescriptor. The methods are, however,
- ** checked to ensure that they follow the rules set forth at the top of the class.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu).
- ** @param listenerType the class containing the listenerMethods.
- ** @param listenerMethodDescriptors the event firing methods.
- ** @param addListenerMethod the add listener method.
- ** @param removeListenerMethod the remove listener method.
- ** @exception IntrospectionException if the listenerType is not an EventListener,
- ** or any of the methods are invalid.
- **/
- public EventSetDescriptor(String eventSetName,
- Class<?> listenerType,
- MethodDescriptor[] listenerMethodDescriptors,
- Method addListenerMethod,
- Method removeListenerMethod) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- this.listenerMethodDescriptors = listenerMethodDescriptors;
- this.listenerMethods = new Method[listenerMethodDescriptors.length];
- for(int i=0;i<this.listenerMethodDescriptors.length;i++) {
- this.listenerMethods[i] = this.listenerMethodDescriptors[i].getMethod();
- }
-
- this.addListenerMethod = addListenerMethod;
- this.removeListenerMethod = removeListenerMethod;
- this.listenerType = listenerType;
- checkMethods();
- checkAddListenerUnicast();
- if(this.removeListenerMethod.getExceptionTypes().length > 0) {
- throw new IntrospectionException("Listener remove method throws exceptions.");
- }
- }
-
- /** Get the class that contains the event firing methods. **/
- public Class<?> getListenerType() {
- return listenerType;
- }
-
- /** Get the event firing methods. **/
- public Method[] getListenerMethods() {
- return listenerMethods;
- }
-
- /** Get the event firing methods as MethodDescriptors. **/
- public MethodDescriptor[] getListenerMethodDescriptors() {
- if(listenerMethodDescriptors == null) {
- listenerMethodDescriptors = new MethodDescriptor[listenerMethods.length];
- for(int i=0;i<listenerMethods.length;i++) {
- listenerMethodDescriptors[i] = new MethodDescriptor(listenerMethods[i]);
- }
- }
- return listenerMethodDescriptors;
- }
-
- /** Get the add listener method. **/
- public Method getAddListenerMethod() {
- return addListenerMethod;
- }
-
- /** Get the remove listener method. **/
- public Method getRemoveListenerMethod() {
- return removeListenerMethod;
- }
-
- /** Set whether or not multiple listeners may be added.
- ** @param unicast whether or not multiple listeners may be added.
- **/
- public void setUnicast(boolean unicast) {
- this.unicast = unicast;
- }
-
- /** Get whether or not multiple listeners may be added. (Defaults to false.) **/
- public boolean isUnicast() {
- return unicast;
- }
-
- /** Set whether or not this is in the default event set.
- ** @param inDefaultEventSet whether this is in the default event set.
- **/
- public void setInDefaultEventSet(boolean inDefaultEventSet) {
- this.inDefaultEventSet = inDefaultEventSet;
- }
-
- /** Get whether or not this is in the default event set. (Defaults to true.)**/
- public boolean isInDefaultEventSet() {
- return inDefaultEventSet;
- }
-
- private void checkAddListenerUnicast() throws IntrospectionException {
- Class[] addListenerExceptions = this.addListenerMethod.getExceptionTypes();
- if(addListenerExceptions.length > 1) {
- throw new IntrospectionException("Listener add method throws too many exceptions.");
- } else if(addListenerExceptions.length == 1
- && !java.util.TooManyListenersException.class.isAssignableFrom(addListenerExceptions[0])) {
- throw new IntrospectionException("Listener add method throws too many exceptions.");
- }
- }
-
- private void checkMethods() throws IntrospectionException {
- if(!addListenerMethod.getDeclaringClass().isAssignableFrom(removeListenerMethod.getDeclaringClass())
- && !removeListenerMethod.getDeclaringClass().isAssignableFrom(addListenerMethod.getDeclaringClass())) {
- throw new IntrospectionException("add and remove listener methods do not come from the same class. This is bad.");
- }
- if(!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
- || addListenerMethod.getParameterTypes().length != 1
- || !listenerType.equals(addListenerMethod.getParameterTypes()[0])
- || !Modifier.isPublic(addListenerMethod.getModifiers())) {
- throw new IntrospectionException("Add Listener Method invalid.");
- }
- if(!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
- || removeListenerMethod.getParameterTypes().length != 1
- || !listenerType.equals(removeListenerMethod.getParameterTypes()[0])
- || removeListenerMethod.getExceptionTypes().length > 0
- || !Modifier.isPublic(removeListenerMethod.getModifiers())) {
- throw new IntrospectionException("Remove Listener Method invalid.");
- }
-
- for(int i=0;i<listenerMethods.length;i++) {
- if(!listenerMethods[i].getReturnType().equals(java.lang.Void.TYPE)
- || Modifier.isPrivate(listenerMethods[i].getModifiers())) {
- throw new IntrospectionException("Event Method " + listenerMethods[i].getName() + " non-void or private.");
- }
- if(!listenerMethods[i].getDeclaringClass().isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Event Method " + listenerMethods[i].getName() + " not from class " + listenerType.getName());
- }
- }
- }
-
- private void findMethods(Class eventSourceClass,
- Class listenerType,
- String listenerMethodNames[],
- String addListenerMethodName,
- String removeListenerMethodName,
- String absurdEventClassCheckName) throws IntrospectionException {
-
- /* Find add listener method and remove listener method. */
- Class[] listenerArgList = new Class[1];
- listenerArgList[0] = listenerType;
- try {
- this.addListenerMethod = eventSourceClass.getMethod(addListenerMethodName,listenerArgList);
- } catch(SecurityException E) {
- throw new IntrospectionException("SecurityException trying to access method " + addListenerMethodName + ".");
- } catch(NoSuchMethodException E) {
- throw new IntrospectionException("Could not find method " + addListenerMethodName + ".");
- }
-
- if(this.addListenerMethod == null || !this.addListenerMethod.getReturnType().equals(java.lang.Void.TYPE)) {
- throw new IntrospectionException("Add listener method does not exist, is not public, or is not void.");
- }
-
- try {
- this.removeListenerMethod = eventSourceClass.getMethod(removeListenerMethodName,listenerArgList);
- } catch(SecurityException E) {
- throw new IntrospectionException("SecurityException trying to access method " + removeListenerMethodName + ".");
- } catch(NoSuchMethodException E) {
- throw new IntrospectionException("Could not find method " + removeListenerMethodName + ".");
- }
- if(this.removeListenerMethod == null || !this.removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE)) {
- throw new IntrospectionException("Remove listener method does not exist, is not public, or is not void.");
- }
-
- /* Find the listener methods. */
- Method[] methods;
- try {
- methods = ClassHelper.getAllMethods(listenerType);
- } catch(SecurityException E) {
- throw new IntrospectionException("Security: You cannot access fields in this class.");
- }
-
- Vector chosenMethods = new Vector();
- boolean[] listenerMethodFound = new boolean[listenerMethodNames.length];
- for(int i=0;i<methods.length;i++) {
- if(Modifier.isPrivate(methods[i].getModifiers())) {
- continue;
- }
- Method currentMethod = methods[i];
- Class retval = currentMethod.getReturnType();
- if(retval.equals(java.lang.Void.TYPE)) {
- for(int j=0;j<listenerMethodNames.length;j++) {
- if(currentMethod.getName().equals(listenerMethodNames[j])
- && (absurdEventClassCheckName == null
- || (currentMethod.getParameterTypes().length == 1
- && ((currentMethod.getParameterTypes()[0]).getName().equals(absurdEventClassCheckName)
- || (currentMethod.getParameterTypes()[0]).getName().endsWith("."+absurdEventClassCheckName)
- )
- )
- )
- ) {
- chosenMethods.addElement(currentMethod);
- listenerMethodFound[j] = true;
- }
- }
- }
- }
-
- /* Make sure we found all the methods we were looking for. */
- for(int i=0;i<listenerMethodFound.length;i++) {
- if(!listenerMethodFound[i]) {
- throw new IntrospectionException("Could not find event method " + listenerMethodNames[i]);
- }
- }
-
- /* Now that we've chosen the listener methods we want, store them. */
- this.listenerMethods = new Method[chosenMethods.size()];
- for(int i=0;i<chosenMethods.size();i++) {
- this.listenerMethods[i] = (Method)chosenMethods.elementAt(i);
- }
- }
+ * EventSetDescriptor describes the hookup between an event source class and
+ * an event listener class.
+ *
+ * <p>EventSets have several attributes: the listener class,
+ * the events that can be fired to the listener (methods in the listener
+ * class), and an add and remove listener method from the event firer's
+ * class.
+ * </p>
+ *
+ * <p>
+ * The methods have these constraints on them:
+ * <ul>
+ * <li>event firing methods: must have <code>void</code> return value. Any
+ * parameters and exceptions are allowed. May be public, protected or
+ * package-protected. (Don't ask me why that is, I'm just following the spec.
+ * The only place it is even mentioned is in the Java Beans white paper, and
+ * there it is only implied.)</li>
+ *
+ * <li>add listener method: must have <code>void</code> return value. Must
+ * take exactly one argument, of the listener class's type. May fire either
+ * zero exceptions, or one exception of type
+ * <code>java.util.TooManyListenersException</code>.
+ * Must be public.</li>
+ *
+ * <li>remove listener method: must have <code>void</code> return value. Must
+ * take exactly one argument, of the listener class's type. May not fire any
+ * exceptions. Must be public.</li>
+ * </ul>
+ *
+ * <p>
+ * A final constraint is that event listener classes must extend from
+ * EventListener.
+ * </p>
+ *
+ * <p>
+ * There are also various design patterns associated with some of the methods
+ * of construction. Those are explained in more detail in the appropriate
+ * constructors.
+ * </p>
+ *
+ * <p>
+ * <strong>Documentation Convention:</strong> for proper Internalization of
+ * Beans inside an RAD tool, sometimes there are two names for a property or
+ * method: a programmatic, or locale-independent name, which can be used
+ * anywhere, and a localized, display name, for ease of use. In the
+ * documentation I will specify different String values as either
+ * <em>programmatic</em> or <em>localized</em> to make this distinction clear.
+ *
+ * @author John Keiser
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.1
+ */
+
+public class EventSetDescriptor extends FeatureDescriptor
+{
+ private Method addListenerMethod;
+
+ private Method removeListenerMethod;
+
+ private Class listenerType;
+
+ private MethodDescriptor[] listenerMethodDescriptors;
+
+ private Method[] listenerMethods;
+
+ private Method getListenerMethod;
+
+ private boolean unicast;
+
+ private boolean inDefaultEventSet = true;
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code<.
+ *
+ * <p>
+ * This version of the constructor enforces the rules imposed on the methods
+ * described at the top of this class, as well as searching for:
+ * </p>
+ *
+ * <ol>
+ * <li>
+ * The event-firing method must be non-private with signature <code>void
+ * &lt;listenerMethodName&gt;(&lt;eventSetName&gt;Event)</code> (where
+ * <code>&lt;eventSetName&gt;</code> has its first character capitalized
+ * by the constructor and the Event is a descendant of
+ * {@link java.util.EventObject}) in class <code>listenerType</code>
+ * (any exceptions may be thrown). <b>Implementation note:</b> Note that
+ * there could conceivably be multiple methods with this type of signature
+ * (example: <code>java.util.MouseEvent</code> vs.
+ * <code>my.very.own.MouseEvent</code>). In this implementation, all
+ * methods fitting the description will be put into the
+ * <code>EventSetDescriptor</code>, even though the spec says only one
+ * should be chosen (they probably weren't thinking as pathologically as I
+ * was). I don't like arbitrarily choosing things. If your class has only one
+ * such signature, as most do, you'll have no problems.</li>
+ *
+ * <li>The add and remove methods must be public and named <code>void
+ * add&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</code> and
+ * <code>void remove&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</code>
+ * in in class <code>eventSourceClass</code>, where
+ * <code>&lt;eventSetName&gt;</code> will have its first letter capitalized.
+ * Standard exception rules (see class description) apply.</li>
+ * </ol>
+ *
+ * @param eventSourceClass
+ * the class containing the add/remove listener methods.
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu). This will
+ * be used to generate the name of the event object as well as the
+ * names of the add and remove methods.
+ * @param listenerType
+ * the class containing the event firing method.
+ * @param listenerMethodName
+ * the name of the event firing method.
+ * @exception IntrospectionException
+ * if listenerType is not an EventListener, or if methods are not
+ * found or are invalid.
+ */
+ public EventSetDescriptor(Class eventSourceClass, String eventSetName,
+ Class listenerType, String listenerMethodName)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ String[] names = new String[1];
+ names[0] = listenerMethodName;
+
+ try
+ {
+ eventSetName = Character.toUpperCase(eventSetName.charAt(0))
+ + eventSetName.substring(1);
+ }
+ catch (StringIndexOutOfBoundsException e)
+ {
+ eventSetName = "";
+ }
+
+ findMethods(eventSourceClass, listenerType, names,
+ "add" + eventSetName + "Listener",
+ "remove" + eventSetName + "Listener", eventSetName + "Event");
+ this.listenerType = listenerType;
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>This form of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ * </p>
+ *
+ * @param eventSourceClass
+ * the class containing the add and remove listener methods.
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the event firing methods.
+ * @param listenerMethodNames
+ * the names of the even firing methods.
+ * @param addListenerMethodName
+ * the name of the add listener method.
+ * @param removeListenerMethodName
+ * the name of the remove listener method.
+ * @exception IntrospectionException
+ * if listenerType is not an EventListener or if methods are not
+ * found or are invalid.
+ */
+ public EventSetDescriptor(Class eventSourceClass, String eventSetName,
+ Class listenerType, String[] listenerMethodNames,
+ String addListenerMethodName,
+ String removeListenerMethodName)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ findMethods(eventSourceClass, listenerType, listenerMethodNames,
+ addListenerMethodName, removeListenerMethodName, null);
+ this.listenerType = listenerType;
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>
+ * This variant of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ * </p>
+ * <p>
+ * A valid GetListener method is public, flags no exceptions and has one
+ * argument which is of type <code>Class</code>
+ * {@link java.awt.Component#getListeners(Class)} is such a method.
+ * </p>
+ * <p>
+ * Note: The validity of the return value of the GetListener method is not
+ * checked.
+ * </p>
+ *
+ * @param eventSourceClass
+ * the class containing the add and remove listener methods.
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the event firing methods.
+ * @param listenerMethodNames
+ * the names of the even firing methods.
+ * @param addListenerMethodName
+ * the name of the add listener method.
+ * @param removeListenerMethodName
+ * the name of the remove listener method.
+ * @param getListenerMethodName
+ * Name of a method which returns the array of listeners.
+ * @exception IntrospectionException
+ * if listenerType is not an EventListener or if methods are not
+ * found or are invalid.
+ * @since 1.4
+ */
+ public EventSetDescriptor(Class eventSourceClass, String eventSetName,
+ Class listenerType, String[] listenerMethodNames,
+ String addListenerMethodName,
+ String removeListenerMethodName,
+ String getListenerMethodName)
+ throws IntrospectionException
+ {
+ this(eventSourceClass, eventSetName, listenerType, listenerMethodNames,
+ addListenerMethodName, removeListenerMethodName);
+
+ Method newGetListenerMethod = null;
+
+ try
+ {
+ newGetListenerMethod
+ = eventSourceClass.getMethod(getListenerMethodName,
+ new Class[] { Class.class });
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ throw (IntrospectionException)
+ new IntrospectionException("No method named " + getListenerMethodName
+ + " in class " + listenerType
+ + " which can be used as"
+ + " getListenerMethod.").initCause(nsme);
+ }
+
+ // Note: This does not check the return value (which
+ // should be EventListener[]) but the JDK does not either.
+
+ getListenerMethod = newGetListenerMethod;
+
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor.</code>
+ *
+ * <p>
+ * This variant of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ * </p>
+ * <p>
+ * A valid GetListener method is public, flags no exceptions and has one
+ * argument which is of type <code>Class</code>
+ * {@link java.awt.Component#getListeners(Class)} is such a method.
+ * </p>
+ * <p>
+ * Note: The validity of the return value of the GetListener method is not
+ * checked.
+ * </p>
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethods
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @param getListenerMethod
+ * The method which returns an array of the listeners.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ * @since 1.4
+ */
+ public EventSetDescriptor(String eventSetName, Class listenerType,
+ Method[] listenerMethods, Method addListenerMethod,
+ Method removeListenerMethod,
+ Method getListenerMethod)
+ throws IntrospectionException
+ {
+ this(eventSetName, listenerType, listenerMethods, addListenerMethod,
+ removeListenerMethod);
+
+ // Do no checks if the getListenerMethod is null.
+ if (getListenerMethod.getParameterTypes().length != 1
+ || getListenerMethod.getParameterTypes()[0] != Class.class
+ || getListenerMethod.getExceptionTypes().length > 0
+ || !Modifier.isPublic(getListenerMethod.getModifiers()))
+ throw new IntrospectionException("GetListener method is invalid.");
+
+ // Note: This does not check the return value (which
+ // should be EventListener[]) but the JDK does not either.
+
+ this.getListenerMethod = getListenerMethod;
+ }
+
+ /**
+ * Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>This form of constructor allows you to explicitly say which methods
+ * do what, and no reflection is done by the <code>EventSetDescriptor</code>.
+ * The methods are, however, checked to ensure that they follow the rules
+ * set forth at the top of the class.
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethods
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ */
+ public EventSetDescriptor(String eventSetName, Class listenerType,
+ Method[] listenerMethods, Method addListenerMethod,
+ Method removeListenerMethod)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ this.listenerMethods = listenerMethods;
+ this.addListenerMethod = addListenerMethod;
+ this.removeListenerMethod = removeListenerMethod;
+ this.listenerType = listenerType;
+ checkMethods();
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /** Creates a new <code>EventSetDescriptor</code>.
+ *
+ * <p>This form of constructor allows you to explicitly say which methods do
+ * what, and no reflection is done by the <code>EventSetDescriptor</code>.
+ * The methods are, however, checked to ensure that they follow the rules
+ * set forth at the top of the class.
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethodDescriptors
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ */
+ public EventSetDescriptor(String eventSetName, Class listenerType,
+ MethodDescriptor[] listenerMethodDescriptors,
+ Method addListenerMethod,
+ Method removeListenerMethod)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ this.listenerMethodDescriptors = listenerMethodDescriptors;
+ this.listenerMethods = new Method[listenerMethodDescriptors.length];
+ for (int i = 0; i < this.listenerMethodDescriptors.length; i++)
+ {
+ this.listenerMethods[i]
+ = this.listenerMethodDescriptors[i].getMethod();
+ }
+
+ this.addListenerMethod = addListenerMethod;
+ this.removeListenerMethod = removeListenerMethod;
+ this.listenerType = listenerType;
+ checkMethods();
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /** Returns the class that contains the event firing methods.
+ */
+ public Class getListenerType()
+ {
+ return listenerType;
+ }
+
+ /** Returns the event firing methods.
+ */
+ public Method[] getListenerMethods()
+ {
+ return listenerMethods;
+ }
+
+ /** Returns the event firing methods as {@link MethodDescriptor}.
+ */
+ public MethodDescriptor[] getListenerMethodDescriptors()
+ {
+ if (listenerMethodDescriptors == null)
+ {
+ listenerMethodDescriptors
+ = new MethodDescriptor[listenerMethods.length];
+
+ for (int i = 0; i < listenerMethods.length; i++)
+ {
+ listenerMethodDescriptors[i]
+ = new MethodDescriptor(listenerMethods[i]);
+ }
+ }
+
+ return listenerMethodDescriptors;
+ }
+
+ /** Returns the add listener method.
+ */
+ public Method getAddListenerMethod()
+ {
+ return addListenerMethod;
+ }
+
+ /* Returns the remove listener method.
+ */
+ public Method getRemoveListenerMethod()
+ {
+ return removeListenerMethod;
+ }
+
+ /**
+ * Returns the method that retrieves the listeners or <code>null</code> if
+ * it does not exist.
+ */
+ public Method getGetListenerMethod()
+ {
+ return getListenerMethod;
+ }
+
+ /** Sets whether or not multiple listeners may be added.
+ *
+ * @param unicast
+ * whether or not multiple listeners may be added.
+ */
+ public void setUnicast(boolean unicast)
+ {
+ this.unicast = unicast;
+ }
+
+ /** Returns whether or not multiple listeners may be added.
+ * (Defaults to false.)
+ */
+ public boolean isUnicast()
+ {
+ return unicast;
+ }
+
+ /** Sets whether or not this is in the default event set.
+ *
+ * @param inDefaultEventSet
+ * whether this is in the default event set.
+ */
+ public void setInDefaultEventSet(boolean inDefaultEventSet)
+ {
+ this.inDefaultEventSet = inDefaultEventSet;
+ }
+
+ /** Returns whether or not this is in the default event set.
+ * (Defaults to true.)
+ */
+ public boolean isInDefaultEventSet()
+ {
+ return inDefaultEventSet;
+ }
+
+ private void checkAddListenerUnicast() throws IntrospectionException
+ {
+ Class[] addListenerExceptions = this.addListenerMethod.getExceptionTypes();
+ if (addListenerExceptions.length > 1)
+ {
+ throw new IntrospectionException(
+ "Listener add method throws too many exceptions.");
+ }
+ else if (addListenerExceptions.length == 1
+ && !java.util.TooManyListenersException.class
+ .isAssignableFrom(addListenerExceptions[0]))
+ {
+ throw new IntrospectionException(
+ "Listener add method throws too many exceptions.");
+ }
+ }
+
+ private void checkMethods() throws IntrospectionException
+ {
+ if (!addListenerMethod.getDeclaringClass()
+ .isAssignableFrom(removeListenerMethod.getDeclaringClass())
+ && !removeListenerMethod.getDeclaringClass()
+ .isAssignableFrom(addListenerMethod.getDeclaringClass()))
+ {
+ throw new IntrospectionException(
+ "add and remove listener methods do not come from the"
+ + " same class. This is bad.");
+ }
+ if (!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
+ || addListenerMethod.getParameterTypes().length != 1
+ || !listenerType.equals(addListenerMethod.getParameterTypes()[0])
+ || !Modifier.isPublic(addListenerMethod.getModifiers()))
+ {
+ throw new IntrospectionException("Add Listener Method invalid.");
+ }
+ if (!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
+ || removeListenerMethod.getParameterTypes().length != 1
+ || !listenerType.equals(removeListenerMethod.getParameterTypes()[0])
+ || removeListenerMethod.getExceptionTypes().length > 0
+ || !Modifier.isPublic(removeListenerMethod.getModifiers()))
+ {
+ throw new IntrospectionException("Remove Listener Method invalid.");
+ }
+
+ for (int i = 0; i < listenerMethods.length; i++)
+ {
+ if (!listenerMethods[i].getReturnType().equals(java.lang.Void.TYPE)
+ || Modifier.isPrivate(listenerMethods[i].getModifiers()))
+ {
+ throw new IntrospectionException("Event Method "
+ + listenerMethods[i].getName()
+ + " non-void or private.");
+ }
+ if (!listenerMethods[i].getDeclaringClass()
+ .isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException("Event Method "
+ + listenerMethods[i].getName()
+ + " not from class "
+ + listenerType.getName());
+ }
+ }
+ }
+
+ private void findMethods(Class eventSourceClass, Class listenerType,
+ String listenerMethodNames[],
+ String addListenerMethodName,
+ String removeListenerMethodName,
+ String absurdEventClassCheckName)
+ throws IntrospectionException
+ {
+
+ /* Find add listener method and remove listener method. */
+ Class[] listenerArgList = new Class[1];
+ listenerArgList[0] = listenerType;
+ try
+ {
+ this.addListenerMethod
+ = eventSourceClass.getMethod(addListenerMethodName,
+ listenerArgList);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "SecurityException trying to access method "
+ + addListenerMethodName + ".");
+ }
+ catch (NoSuchMethodException E)
+ {
+ throw new IntrospectionException("Could not find method "
+ + addListenerMethodName + ".");
+ }
+
+ if (this.addListenerMethod == null
+ || !this.addListenerMethod.getReturnType().equals(java.lang.Void.TYPE))
+ {
+ throw new IntrospectionException(
+ "Add listener method does not exist, is not public,"
+ + " or is not void.");
+ }
+
+ try
+ {
+ this.removeListenerMethod
+ = eventSourceClass.getMethod(removeListenerMethodName,
+ listenerArgList);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "SecurityException trying to access method "
+ + removeListenerMethodName + ".");
+ }
+ catch (NoSuchMethodException E)
+ {
+ throw new IntrospectionException("Could not find method "
+ + removeListenerMethodName + ".");
+ }
+ if (this.removeListenerMethod == null
+ || !this.removeListenerMethod.getReturnType()
+ .equals(java.lang.Void.TYPE))
+ {
+ throw new IntrospectionException(
+ "Remove listener method does not exist, is not public,"
+ + " or is not void.");
+ }
+
+ /* Find the listener methods. */
+ Method[] methods;
+ try
+ {
+ methods = ClassHelper.getAllMethods(listenerType);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "Security: You cannot access fields in this class.");
+ }
+
+ Vector chosenMethods = new Vector();
+ boolean[] listenerMethodFound = new boolean[listenerMethodNames.length];
+ for (int i = 0; i < methods.length; i++)
+ {
+ if (Modifier.isPrivate(methods[i].getModifiers()))
+ {
+ continue;
+ }
+ Method currentMethod = methods[i];
+ Class retval = currentMethod.getReturnType();
+ if (retval.equals(java.lang.Void.TYPE))
+ {
+ for (int j = 0; j < listenerMethodNames.length; j++)
+ {
+ if (currentMethod.getName().equals(listenerMethodNames[j])
+ && (absurdEventClassCheckName == null
+ || (currentMethod.getParameterTypes().length == 1
+ && ((currentMethod.getParameterTypes()[0])
+ .getName().equals(absurdEventClassCheckName)
+ || (currentMethod.getParameterTypes()[0])
+ .getName().endsWith("." + absurdEventClassCheckName)))))
+ {
+ chosenMethods.addElement(currentMethod);
+ listenerMethodFound[j] = true;
+ }
+ }
+ }
+ }
+
+ /* Make sure we found all the methods we were looking for. */
+ for (int i = 0; i < listenerMethodFound.length; i++)
+ {
+ if (!listenerMethodFound[i])
+ {
+ throw new IntrospectionException("Could not find event method "
+ + listenerMethodNames[i]);
+ }
+ }
+
+ /* Now that we've chosen the listener methods we want, store them. */
+ this.listenerMethods = new Method[chosenMethods.size()];
+ for (int i = 0; i < chosenMethods.size(); i++)
+ {
+ this.listenerMethods[i] = (Method) chosenMethods.elementAt(i);
+ }
+ }
+
}
diff --git a/java/beans/PersistenceDelegate.java b/java/beans/PersistenceDelegate.java
index 91c02d2b8..a6f715763 100644
--- a/java/beans/PersistenceDelegate.java
+++ b/java/beans/PersistenceDelegate.java
@@ -59,9 +59,8 @@ public abstract class PersistenceDelegate
{
type = type.getSuperclass();
- PersistenceDelegate pd = out.getPersistenceDelegate(
- oldInstance.getClass().getSuperclass());
-
+ PersistenceDelegate pd = out.getPersistenceDelegate(type);
+
pd.initialize(type, oldInstance, newInstance, out);
}
}
diff --git a/java/beans/PropertyChangeSupport.java b/java/beans/PropertyChangeSupport.java
index 991390b56..e944e1512 100644
--- a/java/beans/PropertyChangeSupport.java
+++ b/java/beans/PropertyChangeSupport.java
@@ -1,5 +1,6 @@
/* PropertyChangeSupport.java -- support to manage property change listeners
- Copyright (C) 1998, 1999, 2000, 2002, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2002, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -120,14 +121,17 @@ public class PropertyChangeSupport implements Serializable
* property change events will be sent to this listener. The listener add
* is not unique: that is, <em>n</em> adds with the same listener will
* result in <em>n</em> events being sent to that listener for every
- * property change. Adding a null listener may cause a NullPointerException
- * down the road. This method will unwrap a PropertyChangeListenerProxy,
+ * property change. Adding a null listener is silently ignored.
+ * This method will unwrap a PropertyChangeListenerProxy,
* registering the underlying delegate to the named property list.
*
* @param l the listener to add
*/
public synchronized void addPropertyChangeListener(PropertyChangeListener l)
{
+ if (l == null)
+ return;
+
if (l instanceof PropertyChangeListenerProxy)
{
PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
@@ -216,8 +220,8 @@ public class PropertyChangeSupport implements Serializable
* cumulative, too; if you are registered to listen to receive events on
* all property changes, and then you register on a particular property,
* you will receive change events for that property twice. Adding a null
- * listener may cause a NullPointerException down the road. This method
- * will unwrap a PropertyChangeListenerProxy, registering the underlying
+ * listener is silently ignored. This method will unwrap a
+ * PropertyChangeListenerProxy, registering the underlying
* delegate to the named property list if the names match, and discarding
* it otherwise.
*
@@ -228,6 +232,9 @@ public class PropertyChangeSupport implements Serializable
public synchronized void addPropertyChangeListener(String propertyName,
PropertyChangeListener l)
{
+ if (l == null)
+ return;
+
while (l instanceof PropertyChangeListenerProxy)
{
PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
@@ -290,17 +297,16 @@ public class PropertyChangeSupport implements Serializable
/**
* Returns an array of all property change listeners registered under the
- * given property name. If there are no registered listeners, this returns
- * an empty array.
+ * given property name. If there are no registered listeners, or
+ * propertyName is null, this returns an empty array.
*
* @return the array of registered listeners
- * @throws NullPointerException if propertyName is null
* @since 1.4
*/
public synchronized PropertyChangeListener[]
getPropertyChangeListeners(String propertyName)
{
- if (children == null)
+ if (children == null || propertyName == null)
return new PropertyChangeListener[0];
PropertyChangeSupport s
= (PropertyChangeSupport) children.get(propertyName);
@@ -455,7 +461,6 @@ public class PropertyChangeSupport implements Serializable
*
* @param propertyName the property that may be listened on
* @return whether the property is being listened on
- * @throws NullPointerException if propertyName is null
*/
public synchronized boolean hasListeners(String propertyName)
{
diff --git a/java/beans/XMLDecoder.java b/java/beans/XMLDecoder.java
index 238fd6bed..7618bb8cb 100644
--- a/java/beans/XMLDecoder.java
+++ b/java/beans/XMLDecoder.java
@@ -1,5 +1,5 @@
/* java.beans.XMLDecoder --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,7 +38,7 @@ exception statement from your version. */
package java.beans;
-import gnu.java.beans.decoder.DefaultExceptionListener;
+import gnu.java.beans.DefaultExceptionListener;
import gnu.java.beans.decoder.PersistenceParser;
import java.io.IOException;
@@ -289,7 +289,7 @@ public class XMLDecoder
// uses a default implementation when null
if (listener == null)
{
- listener = new DefaultExceptionListener();
+ listener = DefaultExceptionListener.INSTANCE;
}
exceptionListener = listener;
}
diff --git a/java/beans/XMLEncoder.java b/java/beans/XMLEncoder.java
index f9cbe6396..feff68bd3 100644
--- a/java/beans/XMLEncoder.java
+++ b/java/beans/XMLEncoder.java
@@ -168,6 +168,8 @@ public class XMLEncoder extends Encoder
// an erroneous state to the ScanEngine without behaving different
// to the JDK.
scanEngine.revoke();
+
+ return;
}
writeObject(value);