你能用 AspectJ 替换抽象 class 吗
Can you replace an abstract class with AspectJ
给定 java.util.Timer
你可以这样做:
// where TimerMock extends Timer
Timer around(): call (Timer.new()) {
return new TimerMock();
}
这可能与抽象 classes 有关吗?以 java.util.TimerTask
为例,它是具有以下签名的 abstract
class:
public abstract class TimerTask implements Runnable {
(...)
public abstract void run();
}
是否可以 return 扩展 TimerTask 的 class?
如何?
您将很难正确匹配连接点。
让我用你最初的例子来解释问题:
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();
的东西。
然而,有了摘要class,事情就没那么顺利了。在这种情况下,您想用具体 class 替换抽象 class 的具体实现。这样做的一个方面可能类似于(假设现在 TimerMock 扩展了 TimerTask):
public aspect InterceptTimer
{
// where TimerMock extends Timer
TimerTask around(): call(TimerTask+.new()) && !within(InterceptTimer)
{
return new TimerMock();
}
}
"TimerTask+"
确保拦截所有扩展 TimerTask
的 class,"!within(InterceptTimer)"
确保切入点不拦截连接点 "new TimerMock();"
这将导致无限递归。
现在假设您有一个具体的 class 这样:
public class MyTimer extends TimerTask {
@Override
public void run()
{
// ...
}
}
如果要拦截以下创建:
public void method() {
MyTimer a = new MyTimer();
a.run();
}
您会立即收到错误消息:
“
不兼容 return 类型应用于构造函数调用(void
test.MyTimer.())
“
那是因为连接点 "new MyTimer()" 在词法上与 "TimerTask" 不同。如果您可以通过 "new TimerTask()" 更改 "new MyTimer()" 连接点,它会起作用,但是,您不能这样做,因为 TimerTask 是抽象的 class.
如果你想变聪明,把"advice"改成:Object around(): call(MyTask+.new()) && !within(InterceptTimer){...}
您不会得到编译错误,而是运行时错误:
"java.lang.ClassCastException: test.TimerMock cannot be cast to test.MyTimer"
这是因为在编织过程中 AspectJ 将执行以下操作:MyTimer a = (MyTimer) new TimerMock();
我认为不可能做你想做的事,至少不能用那种方法,也许有一种方法可以利用 "execution" 和 "call" 连接点之间的差异来做到这一点.
给定 java.util.Timer
你可以这样做:
// where TimerMock extends Timer
Timer around(): call (Timer.new()) {
return new TimerMock();
}
这可能与抽象 classes 有关吗?以 java.util.TimerTask
为例,它是具有以下签名的 abstract
class:
public abstract class TimerTask implements Runnable {
(...)
public abstract void run();
}
是否可以 return 扩展 TimerTask 的 class?
如何?
您将很难正确匹配连接点。
让我用你最初的例子来解释问题:
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();
的东西。
然而,有了摘要class,事情就没那么顺利了。在这种情况下,您想用具体 class 替换抽象 class 的具体实现。这样做的一个方面可能类似于(假设现在 TimerMock 扩展了 TimerTask):
public aspect InterceptTimer
{
// where TimerMock extends Timer
TimerTask around(): call(TimerTask+.new()) && !within(InterceptTimer)
{
return new TimerMock();
}
}
"TimerTask+"
确保拦截所有扩展 TimerTask
的 class,"!within(InterceptTimer)"
确保切入点不拦截连接点 "new TimerMock();"
这将导致无限递归。
现在假设您有一个具体的 class 这样:
public class MyTimer extends TimerTask {
@Override
public void run()
{
// ...
}
}
如果要拦截以下创建:
public void method() {
MyTimer a = new MyTimer();
a.run();
}
您会立即收到错误消息: “ 不兼容 return 类型应用于构造函数调用(void test.MyTimer.()) “
那是因为连接点 "new MyTimer()" 在词法上与 "TimerTask" 不同。如果您可以通过 "new TimerTask()" 更改 "new MyTimer()" 连接点,它会起作用,但是,您不能这样做,因为 TimerTask 是抽象的 class.
如果你想变聪明,把"advice"改成:Object around(): call(MyTask+.new()) && !within(InterceptTimer){...}
您不会得到编译错误,而是运行时错误:
"java.lang.ClassCastException: test.TimerMock cannot be cast to test.MyTimer"
这是因为在编织过程中 AspectJ 将执行以下操作:MyTimer a = (MyTimer) new TimerMock();
我认为不可能做你想做的事,至少不能用那种方法,也许有一种方法可以利用 "execution" 和 "call" 连接点之间的差异来做到这一点.