使用“方法注释”值来定位切入点

时间:2013-05-03 22:38:05

标签: java aop aspectj

我正在使用AspectJ在自定义PropertyChangeSupport引擎中编织任何使用@BindableClass标记的类。它查找用@BindableMethod标记的方法,并拦截'set'调用以触发propertyChangeListeners链。这一切都运行正常,但我只想拦截它具有值@BindableMethod(type = Type.SET)的方法,因为我在PCS之外使用此注释。我正在努力解决切入点的语法问题,如果有人可以帮助我,我会很感激。

我可以通过在我寻找字段名称时检查注释的值来破解它,但我更愿意让aspectJ查找为我做这个。我认为关键在于下面的'切入点'声明。

道歉,如果我描述得很严重,那么自从我使用AspectJ已经有几年了。我在Annotation查找周围找到了一些答案,但没有围绕注释值。

我的注释:

@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;
        }
    }

2 个答案:

答案 0 :(得分:1)

目前这是不可能的,但 aspectj-users 邮件列表上已经有人谈论:

  • 有人描述了相同的要求here
  • 并且还讨论了there的可能语法。

您可能想要了解讨论,看看核心开发人员何时真正有时间适当地扩展AspectJ语法。

答案 1 :(得分:1)

pointcut callSetter(PropertySupport b, BindableMethod bm) : 
    call(@BindableMethod * *(..)) 
    && target(b)
    && @annotation(bm);

void around(PropertySupport b,BindableMethod bm) : callSetter( b,bm ){
    bm.type();
}