通知中未识别 AspectJ 类型间字段 [英] AspectJ inter-type field not recognized in advice

查看:21
本文介绍了通知中未识别 AspectJ 类型间字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实际上是在尝试跟踪 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 write args(*, amount) instead of args(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆