Reputation: 863
I'm using AspectJ to weave in a custom PropertyChangeSupport engine for any class tagged with @BindableClass. It looks for methods tagged with @BindableMethod and intercepts the 'set' calls to fire off a chain of propertyChangeListeners. That all works ok, but I only want to intercept methods where it has the value @BindableMethod(type=Type.SET) as I'm using this annotation for features outside of PCS. I'm struggling a little with the syntax of the pointcut and would appreciate if someone could help me out.
I can hack it in by checking the annotation's value at the time I hunt for the field name, but I would prefer to have the aspectJ lookup do this for me. I think the key is in the 'pointcut' declaration below.
Apologies if I'm describing it badly, it has been a few years since I played with AspectJ. I found some answers around Annotation lookups, but not around the annotation values.
My Annotation:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindableMethod {
String fieldName();
Type type() default Type.SET;
public static enum Type {
GET, SET;
}
}
My Aspect:
public aspect PropertySupportAspect {
/**
* Weave any class which is tagged with @BindableClass with NestedPropertyChangeSupport
*/
declare parents: @BindableClass * implements PropertySupport, IBindable;
NestedPropertyChangeSupport PropertySupport.support = new NestedPropertyChangeSupport(this);
public interface PropertySupport {
public void addPropertyChangeListener(PropertyChangeListener listener);
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);
public void removePropertyChangeListener(PropertyChangeListener listener);
public boolean hasListeners(String propertyName);
public void firePropertyChange(Object b, String property, Object oldval, Object newval);
}
public PropertyChangeSupport PropertySupport.changeSupport() {
return support;
}
public void PropertySupport.addPropertyChangeListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
public void PropertySupport.addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
public void PropertySupport.removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.removePropertyChangeListener(propertyName, listener);
}
public void PropertySupport.removePropertyChangeListener(PropertyChangeListener listener) {
support.removePropertyChangeListener(listener);
}
public boolean PropertySupport.hasListeners(String propertyName) {
return support.hasListeners(propertyName);
}
pointcut callSetter(PropertySupport b) :
call( @BindableMethod * *(..) )
&& target( b );
void around(PropertySupport b) : callSetter( b )
{
Field propertyField = getField(thisJoinPointStaticPart.getSignature());
try {
propertyField.setAccessible(true);
Object oldValue = propertyField.get(b);
proceed(b);
Object newValue = propertyField.get(b);
((PropertySupport) b).firePropertyChange(b, propertyField.getName(), oldValue, newValue);
} catch (Exception e) {
e.printStackTrace();
}
}
private Field getField(Signature signature) {
Field field = null;
try {
MethodSignature ms = (MethodSignature) signature;
Method m = ms.getMethod();
BindableMethod annotation = m.getAnnotation(BindableMethod.class);
field = signature.getDeclaringType().getDeclaredField(annotation.fieldName());
} catch (NoSuchFieldException nsfe) {
nsfe.printStackTrace();
}
return field;
}
public void PropertySupport.firePropertyChange(Object b, String property, Object oldval, Object newval) {
support.firePropertyChange(property, oldval, newval);
}
}
My Test Class:
@BindableClass
private class Child {
public static final String FLD_NAME = "name";
private String name;
@BindableMethod(fieldName = FLD_NAME)
public void setName(String name) {
this.name = name;
}
@BindableMethod(fieldName = FLD_NAME, type = Type.GET)
public String getName() {
return name;
}
}
Upvotes: 2
Views: 848
Reputation: 530
pointcut callSetter(PropertySupport b, BindableMethod bm) :
call(@BindableMethod * *(..))
&& target(b)
&& @annotation(bm);
void around(PropertySupport b,BindableMethod bm) : callSetter( b,bm ){
bm.type();
}
Upvotes: 1
Reputation: 67317
At the moment this is not possible, but there has been talk going on on the aspectj-users mailing list:
You may want to catch up on the discussion and see when a core developer actually has time to extend AspectJ syntax appropriately.
Upvotes: 1