【问题标题】:AspectJ inter-type field not recognized in advice建议中未识别 AspectJ 类型间字段
【发布时间】:2020-04-25 16:36:18
【问题描述】:

我实际上是在尝试跟踪 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】:

    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)

    • 您在检查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 中,我在应用程序类中看到了编译错误,并且由于编译失败导致了方面本身的后续问题。只要您注释掉 main 方法的最后一行,它就会起作用。 (也许您必须重新保存方面或重新编译项目才能使波浪线消失。)

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

    50% markup
    2
    

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


    更新:我答应你回答为什么目标类不能通过 ITD 访问声明为 private 的字段和方法:因为它们是私有的方面本身!此答案来自 AspectJ 维护者本人,请阅读full answer here

    【讨论】:

    • 更新:我的回答现在解释了编译器错误,用于从目标类访问通过 ITD 声明的私有字段/方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-20
    • 2016-02-28
    • 1970-01-01
    相关资源
    最近更新 更多