给出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的类?
如何?
答案 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();
我认为不可能做到自己想做的事情,至少不能采用这种方法,也许有一种方法可以利用“执行”和“调用”连接点之间的差异。