5

设想:

我在一个包中混合了类、接口和枚举的源文件,如下所示:

package com.mycompany.data;
class Dog {
    // implementation
}

package com.mycompany.data;
class Cat {
    // implementation
}

package com.mycompany.data;
enum Gender {
    // gender options
}

package com.mycompany.data;
interface Animal {
    // methods
}

// ... plus a lot more concrete classes and a few more interfaces ...

目标:让所有类实现一个新接口和一个新方法。

问题:我可以成功地将接口编织到类中,并排除枚举,但我不知道如何防止新接口也被添加到包中的接口中。

我的方面目前看起来像:

public aspect SecureAspect {
    declare parents: com.mycompany.data.* && !java.lang.Enum+ implements Secure;

    // add method from secure interface to everything implementing Secure
}

在我的示例中,匹配Dog,Cat和。Animal

我之前尝试过:

declare parents: com.mycompany.data.* && java.lang.Object+ && !java.lang.Enum+ implements Secure;

因为Animal.class.getSuperclass() == null,相对于 Object,但无济于事。

我知道我可以通过将接口移出包来解决这个问题(如果事实证明这是不可能的,我很乐意这样做),但我很好奇是否有办法像我一样排除接口枚举。

很确定没关系,但我正在使用 javaagent 的加载时编织。

4

1 回答 1

3

这个问题很老,但我发现它很有趣并做了一些研究。

解决方案如下所示:

从 ITD 中排除枚举和接口的方面:

package com.mycompany.aspect;

import com.mycompany.data.Secure;

public aspect SecureAspect {
    declare parents :
        !is(InterfaceType) && !is(EnumType) && com.mycompany.data.*
        implements Secure;

    public void Secure.doSomething() {
        System.out.println("I am a secure " + this.getClass().getSimpleName());
    }
}

顺便说一句,即使您不排除枚举,枚举也不会实现该接口。但是你会得到编译器错误“不能使用声明父母来使枚举类型 com.mycompany.data.Gender 实现一个接口”。

验证 ITD 效果的驱动应用程序:

应用程序遍历所有相关的类、枚举、接口并检查它们是否确实实现了Secure接口。由于该条款,我们希望枚举Gender和接口Animal免于 ITD 。!is(InterfaceType) && !is(EnumType)如果确实实现了接口,doSomething则会通过反射调用该方法,以再次检查 ITD 效果。

package com.mycompany.data;

public class Application {
    public static void main(String[] args) throws Exception {
        for (Class<?> clazz : new Class[] { Application.class, Cat.class, Dog.class, Gender.class, Animal.class }) {
            String implementsYesNo = " does not implement";
            for (Class<?> iface : clazz.getInterfaces()) {
                if (iface == Secure.class) {
                    implementsYesNo = " implements";
                    Object instance = clazz.newInstance();
                    clazz.getMethod("doSomething").invoke(instance);
                    break;
                }
            }
            System.out.println(clazz.getSimpleName() + implementsYesNo + " interface Secure\n");
        }
    }
}

控制台输出:

I am a secure Application
Application implements interface Secure

I am a secure Cat
Cat implements interface Secure

I am a secure Dog
Dog implements interface Secure

Gender does not implement interface Secure

Animal does not implement interface Secure

特别感谢AspectJ 维护者Andy Clement,他向我指出了AspectJ 1.6.9 发行说明(搜索“Type category type patterns”),因为该功能在其他方面没有记录,即使它是 AspectJ 语言的官方部分。

于 2014-08-28T08:09:36.407 回答