您可以将抽象类替换为AspectJ

时间:2018-11-01 06:25:55

标签: java abstract-class aspectj

给出java.util.Timer,您可以执行以下操作:

// where TimerMock extends Timer
Timer around(): call (Timer.new()) {
    return new TimerMock();
}

这可能与抽象类有关吗?以java.util.TimerTask为例,它是一个具有以下签名的abstract类:

public abstract class TimerTask implements Runnable {
    (...)
    public abstract void run();
}

是否可以返回扩展TimerTask的类?

如何?

1 个答案:

答案 0 :(得分:1)

您将很难正确匹配连接点。

让我用您的初始示例来解释问题:

public aspect InterceptTimer
{
    // where TimerMock extends Timer
    Timer around(): call(Timer.new())
    {
         return new TimerMock();
    }
}

public class Test {

    public void method() 
    {
        Timer a = new Timer();
        System.out.println(a.toString());
    }
}

编织后,AspectJ将Timer a = new Timer();替换为语义上等效于Timer a = new TimerMock();的东西,

但是,对于抽象类,事情并不是那么顺利。在这种情况下,您想用具体的类替换抽象类的具体实现。这样做的一个方面可能是类似的(假设TimerMock扩展了TimerTask):

public aspect InterceptTimer
{
    // where TimerMock extends Timer
    TimerTask around(): call(TimerTask+.new()) && !within(InterceptTimer)
    {
        return new TimerMock();
    }  
}

"TimerTask+"确保您拦截所有扩展TimerTask的类,并且"!within(InterceptTimer)"确保切入点不会拦截连接点"new TimerMock();",这将导致无限递归

现在让我们假设您有一个具体的类,如下:

public class MyTimer extends TimerTask {

    @Override
    public void run() 
    {
       // ...
    }
}  

如果要拦截以下创建:

public void method() {
    MyTimer a = new MyTimer();
    a.run();
} 

您立即得到错误: ” 不兼容的返回类型应用于构造函数调用(无效  test.MyTimer。()) “

这是因为连接点“ new MyTimer()”在词汇上与“ TimerTask”不同。如果可以通过“ new TimerTask()”来更改“ new MyTimer()”连接点,那么它将起作用,但是,由于TimerTask是抽象类,因此您不能这样做。

如果您尝试变得聪明,请将“建议”更改为:Object around(): call(MyTask+.new()) && !within(InterceptTimer){...}

您不会得到编译错误,而是运行时错误:

"java.lang.ClassCastException: test.TimerMock cannot be cast to test.MyTimer"

那是因为在编织期间AspectJ将执行以下操作:MyTimer a = (MyTimer) new TimerMock();

我认为不可能做到自己想做的事情,至少不能采用这种方法,也许有一种方法可以利用“执行”和“调用”连接点之间的差异。