/**
  * A property in the observed bean has changed. First checks, if this listener should handle the
  * event, because the event's property name is the one to be observed or the event indicates
  * that any property may have changed. In case the event provides no new value, it is read from
  * the source bean.
  *
  * @param evt the property change event to be handled
  */
 public void propertyChange(PropertyChangeEvent evt) {
   String sourcePropertyName = sourcePropertyDescriptor.getName();
   if ((evt.getPropertyName() == null) || (evt.getPropertyName().equals(sourcePropertyName))) {
     Object newValue = evt.getNewValue();
     if (newValue == null) {
       newValue = BeanUtils.getValue(sourceBean, sourcePropertyDescriptor);
     }
     setValueSilently(
         sourceBean, sourcePropertyDescriptor, targetBean, targetPropertyDescriptor, newValue);
   }
 }
 private void setValueSilently(
     Object sourceBean,
     PropertyDescriptor sourcePropertyDescriptor,
     Object targetBean,
     PropertyDescriptor targetPropertyDescriptor,
     Object newValue) {
   if (property1ChangeHandler != null) {
     removePropertyChangeHandler(bean1, bean1Class, property1ChangeHandler);
   }
   if (property2ChangeHandler != null) {
     removePropertyChangeHandler(bean2, bean2Class, property2ChangeHandler);
   }
   try {
     // Set the new value in the target bean.
     BeanUtils.setValue(targetBean, targetPropertyDescriptor, newValue);
   } catch (PropertyVetoException e) {
     // Silently ignore this situation here, will be handled below.
   }
   // The target bean setter may have modified the new value.
   // Read the value set in the target bean.
   Object value = BeanUtils.getValue(targetBean, targetPropertyDescriptor);
   // If the new value and the value read differ,
   // update the source bean's value.
   // This ignores that the source bean setter may modify the value again.
   // But we won't end in a loop.
   if (!BindingUtils.equals(value, newValue)) {
     boolean sourcePropertyWritable = sourcePropertyDescriptor.getWriteMethod() != null;
     if (sourcePropertyWritable) {
       try {
         BeanUtils.setValue(sourceBean, sourcePropertyDescriptor, value);
       } catch (PropertyVetoException e) {
         // Ignore. The value set is a modified variant
         // of a value that had been accepted before.
       }
     }
   }
   if (property1ChangeHandler != null) {
     addPropertyChangeHandler(bean1, bean1Class, property1ChangeHandler);
   }
   if (property2ChangeHandler != null) {
     addPropertyChangeHandler(bean2, bean2Class, property2ChangeHandler);
   }
 }
 /**
  * Reads the value of the first bean property and sets it as new value of the second bean
  * property.
  *
  * @see #updateProperty1()
  */
 public void updateProperty2() {
   Object property1Value = BeanUtils.getValue(bean1, property1Descriptor);
   setValueSilently(bean1, property1Descriptor, bean2, property2Descriptor, property1Value);
 }