确定哪个方法触发了一个方面

时间:2011-04-14 21:13:36

标签: java aspectj

我想知道在触发这个方面时是否还有确定哪种方法是活跃的。我找到了JointPoint.getSourceLocation()方法,它返回源代码行。我意识到我可以尝试解析该源文件并尝试从中确定方法......但似乎应该有更好的方法。

基本上,如果有以下代码:

 class Monkey{
      public void feed( Banana b ){
           b.eat()
      }
 }
 class Banana{
    private static int bananaIdGen;
    public final int bananaId = ++bananaIdGen;
    private boolean eaten = false;

    public void eat(){
         if( eaten )
              throw IllegalStateException( "Already eaten." );
         else
              eaten = true;
    }
 }

我希望有像

这样的方面
 @After("call(void Banana.eat()) && target(bbb)") 
 public void whereEaten( Banana bbb ){
      ....
 }

在身体里我可以打印出类似“org.example.Monkey(org.example.Banana)吃过的香蕉47”。

原因是如果一个方法被一个没有特定注释的方法调用,我想抛出一个错误。为此,我需要有方法的方法。

1 个答案:

答案 0 :(得分:2)

我认为this question及其thisEnclosingJoinPointStaticPart可以帮助您。

但解决问题的最佳方法是使用withincodecall切入点构建正确的连接点,例如here(请参阅Contract Enforcement部分)。这样就可以防止来自带或不带某些注释的方法的调用。

切入点列表可用here

您的示例代码如何引入注释:

package com.riapriority.test;

public @interface CanEat {
}

我们的Banana班级:

package com.riapriority.test;

public class Banana {
    private static int bananaIdGen;
    private final int bananaId = ++bananaIdGen;
    private boolean eaten = false;

    public void eat() {
        if (eaten)
            throw new IllegalStateException("Already eaten.");
        else
            eaten = true;
    }

    public int getBananaId() {
        return bananaId;
    }
}

我们的Monkey类及其相应的注释:

package com.riapriority.test;

public class Monkey {
    @CanEat
    public void feed(Banana b) {
        b.eat();
    }
}

我们的Airplane课程当然不能吃,所以没有@CanEat注释:

package com.riapriority.test;

public class Airplane {
    public void feed(Banana b) {
        b.eat();
    }
}

我们用于测试的简单主类:

package com.riapriority.test;

public class WithincodeTest {
    public static void main(String[] args) {
        Banana monkeyBanana = new Banana();
        Monkey monkey = new Monkey();
        monkey.feed(monkeyBanana);
        try {
            monkey.feed(monkeyBanana);
        } catch (IllegalStateException e) {
            System.out.println(e.getMessage());
        }
        Banana airplaneBanana = new Banana();
        Airplane airplane = new Airplane();
        try {
            airplane.feed(airplaneBanana);
        } catch (IllegalStateException e) {
            System.out.println(e.getMessage());
        }
    }
}

所以我们需要避免飞机吃香蕉。并获得相应的方面:

package com.riapriority.test;

import java.text.MessageFormat;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class EatingAspect {
    @Pointcut("call(void Banana.eat()) && target(banana)")
    public void eatCall(Banana banana) {
    }

    @Pointcut("@withincode(CanEat)")
    public void canEat() {
    }

    @AfterReturning("eatCall(banana) && canEat()")
    public void whereEaten(Banana banana,
                           JoinPoint.EnclosingStaticPart thisEnclosingStaticPart) {
        System.out.println(MessageFormat.format("Banana {0} eaten by {1}", banana.getBananaId(),
                thisEnclosingStaticPart.getSignature()));
    }

    @Before("eatCall(banana) && !canEat()")
    public void forbidEating(Banana banana,
                             JoinPoint.EnclosingStaticPart thisEnclosingStaticPart) {
        throw new IllegalStateException(MessageFormat.format("Can''t eat {0} by {1}", banana.getBananaId(),
                thisEnclosingStaticPart.getSignature()));
    }
}

所以现在我们的测试主类产生正确的输出:

Banana 1 eaten by void com.riapriority.test.Monkey.feed(Banana)
Already eaten.
Can't eat 2 by void com.riapriority.test.Airplane.feed(Banana)

希望这能解决你的问题。