私は AspectJ を使用して、@BindableClass でタグ付けされたクラスのカスタム PropertyChangeSupport エンジンを織り込んでいます。@BindableMethod でタグ付けされたメソッドを探し、「set」呼び出しをインターセプトして、一連の propertyChangeListeners を起動します。それはすべて正常に機能しますが、PCS の外部の機能にこの注釈を使用しているため、値 @BindableMethod(type=Type.SET) を持つメソッドのみをインターセプトしたいと考えています。ポイントカットの構文に少し苦労しています。誰かが私を助けてくれれば幸いです。
フィールド名を探しているときに注釈の値をチェックすることでハッキングできますが、aspectJ ルックアップでこれを行うことをお勧めします。キーは、以下の「ポイントカット」宣言にあると思います。
AspectJ で遊んでから数年が経ちました。注釈のルックアップに関するいくつかの回答が見つかりましたが、注釈の値に関する回答は見つかりませんでした。
私の注釈:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindableMethod {
String fieldName();
Type type() default Type.SET;
public static enum Type {
GET, SET;
}
}
私の側面:
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);
}
}
私のテストクラス:
@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;
}
}