willcodejavaforfood decided not to publish any source code, so I will post it here for posterity.
To use it simply add <meta attribute="property-change-support">true</meta> under your <class>.
And to add fields that fire the event, simply add <meta attribute="bound">FIELD_PROPERTY</meta> under the needed <property>.
FIELD_PROPERTY should be the unique name given to this property, and it will be exposed as a static string.
Pojo.ftlCode:
${pojo.getPackageDeclaration()}
// Generated ${date} by Hibernate Tools ${version}
<#assign classbody>
<#include "PojoTypeDeclaration.ftl"/> {
<#if !pojo.isInterface()>
<#include "PojoFields.ftl"/>
<#include "PojoConstructors.ftl"/>
<#include "PojoPropertyAccessors.ftl"/>
<#include "PojoToString.ftl"/>
<#include "PojoEqualsHashcode.ftl"/>
<#else>
<#include "PojoInterfacePropertyAccessors.ftl"/>
</#if>
<#include "PojoExtraClassCode.ftl"/>
}
</#assign>
${pojo.generateImports()}
<#if pojo.hasMetaAttribute("property-change-support")>
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
</#if>
${classbody}
PojoFields.ftlCode:
<#-- // Fields -->
<#foreach field in pojo.getAllPropertiesIterator()><#if pojo.getMetaAttribAsBool(field, "gen-property", true)> <#if pojo.hasMetaAttribute(field, "field-description")> /**
${pojo.getFieldJavaDoc(field, 0)}
*/
</#if> ${pojo.getFieldModifiers(field)} ${pojo.getJavaTypeName(field, jdk5)} ${field.name}<#if pojo.hasFieldInitializor(field, jdk5)> = ${pojo.getFieldInitialization(field, jdk5)}</#if>;
</#if>
</#foreach>
<#if pojo.hasMetaAttribute("property-change-support")>
// Property Change support
<#foreach property in pojo.getAllPropertiesIterator()>
<#if pojo.hasMetaAttribute(property, "bound")>
public static final String ${c2j.getMetaAsString(property, "bound")} = "${property.name}";
</#if>
</#foreach>
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
</#if>
PojoPropertyAccessors.ftlCode:
<#-- // Property accessors -->
<#foreach property in pojo.getAllPropertiesIterator()>
<#if pojo.getMetaAttribAsBool(property, "gen-property", true)>
<#if pojo.hasFieldJavaDoc(property)>
/**
* ${pojo.getFieldJavaDoc(property, 4)}
*/
</#if>
<#include "GetPropertyAnnotation.ftl"/>
${pojo.getPropertyGetModifiers(property)} ${pojo.getJavaTypeName(property, jdk5)} ${pojo.getGetterSignature(property)}() {
return this.${property.name};
}
${pojo.getPropertySetModifiers(property)} void set${pojo.getPropertyName(property)}(${pojo.getJavaTypeName(property, jdk5)} ${property.name}) {
<#if pojo.hasMetaAttribute(property, "bound")>
<#assign oldVal = "this.${property.name}">
<#assign newVal = "this.${property.name} = ${property.name}">
<#if pojo.getJavaTypeName(property, jdk5) == "byte">
<#assign oldVal = "new Byte(this.${property.name})">
<#assign newVal = "new Byte(this.${property.name} = ${property.name})">
<#elseif pojo.getJavaTypeName(property, jdk5) == "short">
<#assign oldVal = "new Short(this.${property.name})">
<#assign newVal = "new Short(this.${property.name} = ${property.name})">
<#elseif pojo.getJavaTypeName(property, jdk5) == "int">
<#assign oldVal = "new Integer(this.${property.name})">
<#assign newVal = "new Integer(this.${property.name} = ${property.name})">
<#elseif pojo.getJavaTypeName(property, jdk5) == "long">
<#assign oldVal = "new Long(this.${property.name})">
<#assign newVal = "new Long(this.${property.name} = ${property.name})">
<#elseif pojo.getJavaTypeName(property, jdk5) == "float">
<#assign oldVal = "new Float(this.${property.name})">
<#assign newVal = "new Float(this.${property.name} = ${property.name})">
<#elseif pojo.getJavaTypeName(property, jdk5) == "double">
<#assign oldVal = "new Double(this.${property.name})">
<#assign newVal = "new Double(this.${property.name} = ${property.name})">
<#elseif pojo.getJavaTypeName(property, jdk5) == "char">
<#assign oldVal = "new Character(this.${property.name})">
<#assign newVal = "new Character(this.${property.name} = ${property.name})">
<#elseif pojo.getJavaTypeName(property, jdk5) == "boolean">
<#assign oldVal = "new Boolean(this.${property.name})">
<#assign newVal = "new Boolean(this.${property.name} = ${property.name})">
</#if>
propertyChangeSupport.firePropertyChange(${c2j.getMetaAsString(property, "bound")}, ${oldVal}, ${newVal});
<#else>
this.${property.name} = ${property.name};
</#if>
}
</#if>
</#foreach>