AspectJ inter-type field not recognized in advice

心已入冬 提交于 2020-05-28 06:53:41

问题


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?

The error I get is: transferCount cannot be resolved or is not a field


回答1:


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.

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:

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

Aspect:

First let me mention that I fixed two errors in your code:

  • 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)

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

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.)

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

BTW, inside the aspect you do not need to use getTransferCount(). Just like in the line above, you can directly access the field.


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.



来源:https://stackoverflow.com/questions/61429008/aspectj-inter-type-field-not-recognized-in-advice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!