通知中未识别 AspectJ 类型间字段 [英] AspectJ inter-type field not recognized in advice
问题描述
我实际上是在尝试跟踪 Account 类的转账次数.在这里阅读文档:https://www.eclipse.org/aspectj/doc/released/progguide/language-anatomy.html在第 48 和第 49 张幻灯片上:https://www.eclipse.org/aspectj/doc/released/progguide/language-anatomy.html
I'm essentially trying to track the number of transfers for an Account class. Reading the docs here: https://www.eclipse.org/aspectj/doc/released/progguide/language-anatomy.html And on slide 48 and 49 here: https://www.eclipse.org/aspectj/doc/released/progguide/language-anatomy.html
这些告诉我我应该能够做这样的事情:
These tell me I should be able to do something like this:
public aspect LoggingAspect {
private int Account.transferCount = 0;
private int Account.getTransferCount() {
return transferCount;
}
pointcut firstTransfer(Account s, double amount):
withincode(public void transfer (int, int, double))
&& call(public boolean withdraw(int,double))
&& target(s)
&& args(amount);
boolean around(Account s, double amount):
firstTransfer(s, amount){
s.transferCount++; // Not recognized
if (s.getTransferCount() == 0) { // Not recognized
System.out.println("50% markup");
return s.deposit(amount*.5);
}
return false;
}
}
然而,正如上面代码中所评论的,这些字段不被识别为存在于方面内的类中.我做错了什么?
However, as commented in the code above, the fields are not recognized as existing on the class within the aspect. What am I doing wrong?
我得到的错误是:transferCount 无法解析或不是字段
推荐答案
Account
类中发生了一些事情,很遗憾您没有在此处分享.请了解什么是 MCVE 以及为什么总是提供它如此有价值.尤其是在 AOP 的上下文中,这一点更为重要,因为如果没有目标类,方面就没有多大意义.如果没有另一个,我无法调试一个,这就是为什么我必须发明自己的虚拟类.那实际上是你的工作.
Something is happening in the Account
class which unfortunately you didn't share here. Please learn what an MCVE is and why it is so valuable to always provide one. Especially in the context of AOP it is even more important because an aspect does not make much sense without a target class. I cannot debug one without the other, which is why I had to invent my own dummy class. That would actually have been your job.
可能您正在尝试直接从 Account
类中使用声明的私有成员.由于我还不明白的原因,这不起作用,因为它使用 The method getTransferCount() from the type Account is not visible
或类似的错误消息抛出 AspectJ 编译器.这一定是 AspectJ 中的限制或错误,我会询问维护者并稍后在这里报告.
Probably you are trying to use the declared private members directly from within the Account
class. For a reason I do not understand yet, this does not work because it throws off the AspectJ compiler with a The method getTransferCount() from the type Account is not visible
or similar error message. This must be a limitation or a bug in AspectJ, I will ask the maintainer and report back here later.
但首先让我们重现您的情况:
But first let us reproduce your situation:
应用类:
package de.scrum_master.app;
public class Account {
public void transfer(int a, int b, double c) {
withdraw(a, c);
}
public boolean withdraw(int a, double c) {
return true;
}
public boolean deposit(double amount) {
return true;
}
public static void main(String[] args) {
Account account = new Account();
account.transfer(11, 22, 33.33);
account.withdraw(44, 55.55);
account.transfer(66, 77, 88.88);
account.withdraw(99, 11.11);
// [error] The method getTransferCount() from the type Account is not visible
System.out.println(account.getTransferCount());
}
}
方面:
首先让我提一下,我修复了您代码中的两个错误:
First let me mention that I fixed two errors in your code:
您的切入点只有在正确绑定参数时才会匹配.
double amount
是两个方法参数中的第二个,而不是唯一一个.因此你必须写args(*, amount)
而不是args(amount)
Your pointcut will only match if you bind the arguments correctly.
double amount
is the second of two method parameters, not the only one. Thus you have to writeargs(*, amount)
instead ofargs(amount)
你增加 transferCount
before 检查 s.getTransferCount() == 0
,所以 if代码> 条件永远不会匹配.你想要的是
s.getTransferCount() == 1
.
You increment transferCount
before checking for s.getTransferCount() == 0
, so the if
condition will never match. What you want is s.getTransferCount() == 1
.
package de.scrum_master.aspect;
import de.scrum_master.app.Account;
public aspect LoggingAspect {
private int Account.transferCount = 0;
private int Account.getTransferCount() {
return transferCount;
}
pointcut firstTransfer(Account s, double amount) :
withincode(public void transfer (int, int, double)) &&
call(public boolean withdraw(int, double)) &&
target(s) &&
args(*, amount);
boolean around(Account s, double amount) : firstTransfer(s, amount) {
s.transferCount++;
if (s.getTransferCount() == 1) {
System.out.println("50% markup");
return s.deposit(amount * .5);
}
return false;
}
}
现在在 Eclipse 中,我看到应用程序类中的编译错误,并且由于编译失败,方面本身出现了后续问题.只要您注释掉 main
方法的最后一行,它就会起作用.(也许您必须重新保存方面或重新编译项目才能使波浪线消失.)
Now in Eclipse I see the compile error in the application class and due to the failed compilation the subsequent problem in the aspect itself. As soon as you comment out the last line of the main
method, it works. (Maybe you have to re-save the aspect or recompile the project in order to make the squiggly lines disappear.)
实际上,最简单的方法是将 getTransferCount()
设为公开而不是私有.Getter 通常是公共的,然后您也可以再次使用 main
方法中的方法,程序输出将变为:
Actually the easiest thing to do is to make getTransferCount()
public instead of private. Getters are usually public and you then can also use the method from the main
method again and the program output would become:
50% markup
2
顺便说一句,在方面你不需要使用getTransferCount()
.就像上一行一样,您可以直接访问该字段.
BTW, inside the aspect you do not need to use getTransferCount()
. Just like in the line above, you can directly access the field.
更新:我向您保证了为什么目标类无法访问通过 ITD 声明为 private
的字段和方法的问题的答案:因为它们是关于方面的隐私本身!此答案来自 AspectJ 维护者本人,请阅读 此处的完整答案一>.
Update: I promised you an answer to the question why the target class cannot access fields and methods declared as private
via ITD: because they are private with respect to the aspect itself! This answer comes from the AspectJ maintainer himself, please read the full answer here.
这篇关于通知中未识别 AspectJ 类型间字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!