java - 是否可以从 AspectJ 编织中排除接口(interface)类

标签 java interface aspectj load-time-weaving

场景:

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

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 ...

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

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

我的方面目前看起来像:

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

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

在我的示例中匹配 DogCatAnimal

我之前尝试过:

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

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

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

很确定这无关紧要,但我正在使用 javaagent 的加载时编织。

最佳答案

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

解决方案如下所示:

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

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());
    }
}

顺便说一句,枚举无论如何都不会实现接口(interface),即使你不排除它们。但是随后您会收到编译器错误“无法使用声明父项来使枚举类型 com.mycompany.data.Gender 实现接口(interface)”。

验证ITD效果的司机申请:

应用程序遍历所有相关类、枚举、接口(interface)并检查它们是否确实实现了Secure 接口(interface)。由于 !is(InterfaceType) && !is(EnumType) 子句,我们希望枚举 Gender 和接口(interface) Animal 免于 ITD。如果确实实现了接口(interface),将通过反射调用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 release notes (搜索“Type category type patterns”)因为该功能在其他方面没有记录,即使它是 AspectJ 语言的官方部分。

关于java - 是否可以从 AspectJ 编织中排除接口(interface)类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19573968/

相关文章:

java - 当标记 android studio 触发时,如何获取我保存在 firebase 中的数据 latlng

c++ - 一个类的多个接口(interface)

java - @Around (AspectJ) 内部未捕获异常

java - 是否有适用于所有类(而非接口(interface))的 AspectJ TypePattern?

java - "Fast"Java中的整数幂

java - 在android中使用HttpURLConnection时如何提取分块数据

java - 使用 EPL 跟踪事件序列

c# - 是否可以消除由于接口(interface)引起的 DLL 依赖?

java - 如何在 Java 编译后保留接口(interface)的参数名称?

java - 关于Springaspectj加载时织入执行顺序