AspectJ互类型字段未在通知中识别

问题描述 投票:0回答:1

我本质上是试图跟踪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

这些告诉我,我应该能够做这样的事情:

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;
        }
}

但是,如上面的代码中所述,在方面中,这些字段未被识别为存在于类中。我在做什么错?

我得到的错误是:transferCount cannot be resolved or is not a field

java aop aspectj aspect
1个回答
0
投票

Account类中发生了某些事情,很遗憾您没有在这里分享。请了解什么是MCVE以及为什么总是提供它是如此有价值。尤其是在AOP的情况下,这一点尤为重要,因为如果没有目标类,一个方面就没有多大意义。我不能调试一个而没有另一个,这就是为什么我必须发明自己的虚拟类。那实际上是您的工作。

[您可能正在尝试直接从Account类中使用声明的私有成员。由于某种原因,我尚不了解,这不起作用,因为它以The method getTransferCount() from the type Account is not visible或类似的错误消息抛出了AspectJ编译器。这必须是AspectJ中的限制或错误,我将要求维护者并在以后报告。

但是首先让我们重现您的情况:

应用程序类:

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());
  }
}

方面:

首先让我提到,我修复了您的代码中的两个错误:

  • 仅当您正确绑定参数时,您的切入点才会匹配。 double amount是两个方法参数中的第二个,而不是唯一一个。因此,您必须编写args(*, amount)而不是args(amount)

  • 您递增transferCount 之前来检查s.getTransferCount() == 0,因此if条件将永远不匹配。您想要的是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方法的最后一行,它就会起作用。 (也许您必须重新保存方面或重新编译项目才能使弯曲的线条消失。)

实际上,最简单的方法是将getTransferCount()设为公开而非私有。吸气剂通常是公共的,然后您也可以再次使用main方法中的方法,程序输出将变为:

50% markup
2

BTW,在方面内,您无需使用getTransferCount()。就像上面的行一样,您可以直接访问该字段。


更新:我答应过一个答案,为什么目标类无法通过ITD访问声明为private的字段和方法:因为它们相对于方面而言是私有的]本身!此答案来自AspectJ维护人员本人,请阅读full answer here

© www.soinside.com 2019 - 2024. All rights reserved.