繁体   English   中英

建议中未识别 AspectJ 类型间字段

[英]AspectJ inter-type field not recognized in advice

我实际上是在尝试跟踪账户 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/发布/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;
        }
}

但是,如上面代码中所述,这些字段不被识别为存在于方面内的 class 上。 我究竟做错了什么?

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

Account class 中发生了一些事情,很遗憾您没有在这里分享。 请了解MCVE是什么,以及为什么始终提供 MCVE 如此有价值。 特别是在 AOP 的上下文中,它甚至更重要,因为如果没有目标 class,方面就没有多大意义。 我无法调试一个没有另一个,这就是为什么我必须发明自己的虚拟 class。 那实际上是你的工作。

可能您正在尝试直接从Account class 中使用声明的私有成员。 由于我还不明白的原因,这不起作用,因为它使用The method getTransferCount() from the type Account is not visible或类似的错误消息抛出 AspectJ 编译器。 这一定是 AspectJ 中的限制或错误,我会询问维护者并稍后在这里报告。

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

应用 class:

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

方面:

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

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

  • 在检查s.getTransferCount() == 0之前增加transferCount ,因此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 中,我在应用程序 class 中看到编译错误,并且由于编译失败导致方面本身的后续问题。 只要您注释掉main方法的最后一行,它就可以工作。 (也许您必须重新保存方面或重新编译项目才能使波浪线消失。)

实际上,最简单的做法是让getTransferCount()公开而不是私有。 Getter 通常是公共的,然后您也可以再次使用main方法中的方法,程序 output 将变为:

50% markup
2

顺便说一句,在这方面您不需要使用getTransferCount() 就像上面的行一样,您可以直接访问该字段。


更新:我答应你回答为什么目标 class 不能访问通过 ITD 声明为private的字段和方法:因为它们相对于方面本身是私有的,这个答案来自 AspectJ 维护者本人,请阅读完整答案在这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM