BaseBO

package enhancement.bo;

public class BaseBO {
   private static int counter = 0;
   
   private int id;
   
   public BaseBO() {
      id = counter++;
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }
}

BOPropertyChangeSupportAspect

package enhancement.bo;

import java.beans.PropertyChangeListener;

import com.jgoodies.binding.beans.ExtendedPropertyChangeSupport;

public aspect BOPropertyChangeSupportAspect {

//   declare parents: BaseBO implements IFPropertyChangeSupport;
   
   pointcut setAttribute(Object o) : target(o) && call (public * BaseBO+.set*(*));
   
   after(Object o): setAttribute(o)  {
      Object[] args = thisJoinPoint.getArgs();
      String s = thisJoinPoint.getStaticPart().getSignature().getName().substring(3);
      String attribute = Character.toLowerCase(s.charAt(0)) + s.substring(1);
      
//      System.out.println("Attribut [" + attribute + "] wurde gesetzt auf: " + args[0]);
//      System.out.println("target: ["+ thisJoinPoint.getTarget() + "] o: [" + o + "]");
      ((BaseBO)thisJoinPoint.getTarget()).changeSupport.firePropertyChange(attribute, null, args[0]);
   }
   
   private ExtendedPropertyChangeSupport BaseBO.changeSupport = new ExtendedPropertyChangeSupport(this);
   
   public void BaseBO.addPropertyChangeListener(PropertyChangeListener x) {
      changeSupport.addPropertyChangeListener(x);
   }

   public void BaseBO.removePropertyChangeListener(PropertyChangeListener x) {
      changeSupport.removePropertyChangeListener(x);
   }

}

IFPropertyChangeSupport

package enhancement.bo;

import java.beans.PropertyChangeListener;

public interface IFPropertyChangeSupport {

   public void addPropertyChangeListener(PropertyChangeListener x);
   public void removePropertyChangeListener(PropertyChangeListener x);

}

MyBO

package enhancement.bo;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MyBO extends BaseBO {
   private String  name;
   private Date    dob;
   private Boolean alive;

   public MyBO() {
      this.name = "unset";
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public Date getDob() {
      return dob;
   }

   public void setDob(Date dob) {
      this.dob = dob;
   }

   public Boolean getAlive() {
      return alive;
   }

   public void setAlive(Boolean alive) {
      this.alive = alive;
   }
   
   public String toString() {
      return name + " (" + (new SimpleDateFormat()).format(dob) + ") is " + (alive.booleanValue() ? "" : "not ") + "alive";
   }
}

BindingTest

package enhancement.client;

import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.util.Date;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.text.DateFormatter;

import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.beans.BeanAdapter;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.factories.ButtonBarFactory;

import enhancement.bo.MyBO;

public class BindingTest {

   public static MyBO bean = new MyBO();
   
   public static void main(String[] args) {

      bean.setName("Annette Willmann");
      bean.setDob(new Date());
      bean.setAlive(Boolean.TRUE);
      
      (new Thread() {
         public void run() {
            while( true ) {
               try {
                  sleep(1000);
                  bean.setAlive(new Boolean(!bean.getAlive().booleanValue()));
               }
               catch(Exception ignored) {}
            }
         }
      }).start();
      

      // Bean adapter is an adapter that can create many value model objects for a single
      // bean. It is more efficient than the property adapter. The 'true' once again means
      // we want it to observe our bean for changes.
      BeanAdapter adapter = new BeanAdapter(bean, true);

      ValueModel stringModel  = adapter.getValueModel("name");
      ValueModel dateModel    = adapter.getValueModel("dob");
      ValueModel booleanModel = adapter.getValueModel("alive");

      JTextField name  = BasicComponentFactory.createTextField(stringModel);
      JTextField dob   = BasicComponentFactory.createFormattedTextField(dateModel, new DateFormatter());
      JCheckBox  alive = BasicComponentFactory.createCheckBox(booleanModel, "Boolean Value");
      
      JButton okButton = new JButton("OK");
      okButton.addActionListener(new ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent e) {
            System.out.println("bo: " + bean);
         }
      });
      JButton cancelButton = new JButton("Cancel");
      cancelButton.addActionListener(new ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent e) {
            System.exit(0);
         }
      });      

      JFrame frame = new JFrame();
      
      frame.getContentPane().setLayout(new GridLayout(4, 1));
      frame.getContentPane().add(name);
      frame.getContentPane().add(dob);
      frame.getContentPane().add(alive);
      // add the OK/Cancel buttons to the UI
      frame.getContentPane().add(ButtonBarFactory.buildOKCancelBar(okButton, cancelButton));      
      frame.pack();
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.setVisible(true);
   }
}

Main

package enhancement.client;

import enhancement.bo.MyBO;

public class Main {

   public static void main(String[] args) {
      MyBO bo1 = new MyBO();
      MyBO bo2 = new MyBO();
      
      bo1.setName("one");
      bo2.setName("two");
      System.out.println("bo1: " + bo1.getName());
      System.out.println("bo2: " + bo2.getName());
   }

}