This Tech Tip reprinted with permission by java.sun.com

In J2SE 5.0, a number of features were added to the JavaBeans component API. One of these was support for IndexedPropertyChangeEvent. The JavaBeans component API provided a way to report changes to a regular property of a JavaBeans component (also called a JavaBean or just a "bean"). The support for IndexedPropertyChangeEvent added the ability to report additional information about changes to an indexed property of a bean.

Most people are familiar with JavaBean component properties. Simply add set and get methods to your class and you have a read-write property defined by whatever the name is after set and get. In other words, if your class has methods named setName() and getName(), your class has a JavaBean component property named name.

There are two types of component properties: regular and indexed. Indexed properties are distinguished from regular properties in that they have multiple values, where each value is accessed by an index. The set and get methods for a regular property such as name would look like this:

Regular property:

  • public void setName(String name)
  • public String getName()

If name is an indexed property, the methods look like this:

Indexed property:

  • public void setName(int index, String name)
  • public String getName(int index)
  • public void setName(String[] names)
  • public String[] getName()

Beans can be designed to notify you of their property changes. You can register a PropertyChangeListener object with the bean through the addPropertyChangeListener() method. The listener is then notified of changes through PropertyChangeEvent objects or IndexedPropertyChangeEvent objects. A property that generates a PropertyChangeEvent when its value changes is called a bound property.

The PropertyChangeListener class has one method:

   public void propertyChange(PropertyChangeEvent pce)

 

If the argument to propertyChange() is of type PropertyChangeEvent, how do you get notified with an IndexedPropertyChangeEvent? The answer derives from the fact that the IndexedPropertyChangeEvent class is a subclass of PropertyChangeEvent. So, inside your propertyChange() you need an instanceof check to see what type of argument you get:

  public void propertyChange(PropertyChangeEvent pce) {
     String name = pce.getPropertyName();
     if (pce instanceof IndexedPropertyChangeEvent) {
       IndexedPropertyChangeEvent ipce =
         (IndexedPropertyChangeEvent) pce;
       int index = ipce.getIndex();
       System.out.println("Property: " + name + "; index: " 
       + index);
     } else {
       System.out.println("Property: " + name);
     }
     System.out.println("; value: " + pce.getNewValue());
   }

 

Before viewing an example program that uses IndexedPropertyChangeEvent, let's focus on how to report a change to a bound indexed property. The following code reports the update of the name indexed property shown previously:

 private PropertyChangeSupport changeSupport;

   public ClassConstructor() {
     changeSupport = new PropertyChangeSupport(this);
   }

   public void setName(int index, String name) {
     String oldName = this.name;
     this.name = name;
     changeSupport.fireIndexedPropertyChange("name", index,
       oldName, name);
   }

 

The PropertyChangeSupport class is a support class found in the java.beans package (the package for the JavaBeans component API). The fireIndexedPropertyChange() method reports a change to the bound indexed property (in this case, name) to any listeners that were registered through the addPropertyChangeListener() method.

Here's what the full example looks like:

  import java.beans.*;
   import java.util.*;
   
   public class IndexedSampleBean {
   
     private PropertyChangeSupport changeSupport;
   
     private Map<Integer, String> names;
   
     private String title;
   
     public IndexedSampleBean() {
       changeSupport = new PropertyChangeSupport(this);
       names = new HashMap<Integer, String>();
     }
   
     public void setTitle(String title) {
       String oldTitle = this.title;
       this.title = title;
       changeSupport.firePropertyChange("title", oldTitle, title);
     }
   
     public String getTitle() {
       return title;
     }
   
     public void setName(int index, String name) {
         String oldName = names.get(index);
         names.put(index, name);
         changeSupport.fireIndexedPropertyChange("name", index,
                   oldName, name);
     }
   
     public String getName(int index) {
       return names.get(index);
     }
   
     public void addPropertyChangeListener(
      PropertyChangeListener l) {
         changeSupport.addPropertyChangeListener(l);
     }

     public void removePropertyChangeListener(
      PropertyChangeListener l) {
         changeSupport.removePropertyChangeListener(l);
     }
   
     public static void main(String[] args) throws Exception {
       IndexedSampleBean bean = new IndexedSampleBean();
       PropertyChangeListener listener = 
         new PropertyChangeListener() {
           public void propertyChange(PropertyChangeEvent pce) {
             String name = pce.getPropertyName();
             if (pce instanceof IndexedPropertyChangeEvent) {
               IndexedPropertyChangeEvent ipce =
                 (IndexedPropertyChangeEvent) pce;
               int index = ipce.getIndex();
               System.out.print("Property: " + name +
                 "; index: " + index);
             } else {
               System.out.print("Property: " + name);
             }
             System.out.println("; value: " + pce.getNewValue());
           }
       };
       bean.addPropertyChangeListener(listener);
       bean.setName(1, "John");
       bean.setName(2, "Ed");
       bean.setName(3, "Mary");
       bean.setName(4, "Joan");
       bean.setTitle("Captain");
       System.out.println("Name at 3 is: " + bean.getName(3));
       System.out.println("Title is: " + bean.getTitle());
     }
   }

 

 

The class defines an indexed property named name and sets the name at four positions. In addition, a regular bound property named title is also present and set. The listener is notified for each call to set the name or title and then print the property name, index (if appropriate), and value. The class then gets the name at one specific position and prints it, before printing the single title.

Running the program produces the following results:

 >java IndexedSample

    Property: name index: 1 value: John
    Property: name index: 2 value: Ed
    Property: name index: 3 value: Mary
    Property: name index: 4 value: Joan
    Property: title; value: Captain
    Name at 3 is: Mary
    Title is: Captain

For more information about the support for IndexedPropertyChangeEvent in the JavaBeans component API, see API Enhancements to the JavaBeans Component API in J2SE 5.0. Also see the JavaBeans Trail in the Java Tutorial.

Copyright (c) 2004-2005 Sun Microsystems, Inc.
All Rights Reserved.