I am trying to combining multiple pointcuts of getter and setter to create an advice that will be executed if both pointcuts are executed. I have tried in normal AspectJ class and annotation #Aspect class but still it gives me warning adviceDidNotMatch and eventually the advice is not executed. Strangely if I change && (AND) with || (OR) it works, but why && doesn't work at all?
Here is the advice declared in normal AspectJ class.
package testMaven;
pointcut getter() : execution(* testMaven.testing.getDd(..));
before() : getter(){
System.out.println("test get");
}
pointcut setter() : execution(* testMaven.testing.setDd(..));
before() : setter(){
System.out.println("test set");
}
pointcut combine(): getter() && setter();
before(): combine(){
System.out.println("testing combine");
}
}
Here is the advice declared in annotation #Aspect class
package testMaven;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
#Aspect
public class aspecter {
#Pointcut("call (* testMaven.testing.getDd(..))")
public void getter(){
}
#Pointcut("call (* testMaven.testing.setDd(..))")
public void setter(){}
#Pointcut("execution (* testMaven.tester.setZ(..))")
public void setterZ(){}
#Before("setterZ()")
public void settingZ(){
System.out.println("before set Z");
}
#Pointcut("getter() && setter()")
public void getterSetter(){}
#After("getterSetter()")
public void testerd(){
System.out.println("works");
}
#Pointcut("getter() && setterZ()")
public void getterSetter2(){}
#After("getterSetter2()")
public void testinger(){
System.out.println("ok");
}
}
Here is the testing class that I want to be advised:
package testMaven;
public class testing {
public int dd;
public int getDd() {
return dd;
}
public void setDd(int dd) {
this.dd = dd;
}
}
package testMaven;
public class testing {
public int dd;
public int getDd() {
return dd;
}
public void setDd(int dd) {
this.dd = dd;
}
public void aa(int a){
System.out.println(a);
}
}
And here is the main class:
package testMaven;
public class MainApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
testing test = new testing();
test.aa(2);
test.setDd(3);
tester et = new tester();
et.setZ(3);
et.printNo(1000);
System.out.println(test.getDd());
}
}
Is there something wrong with my code? Any help is appreciated.
Thanks
You asked if there is something wrong with your code. The answer is yes. The two pointcuts setter() and getter() are mutually exclusive. Thus combining them with && - i.e. creating an intersection of two mutually disjunct sets of joinpoints - logically leads to an empty result set. Ergo your combined pointcut does not match. You should use || as uniknow suggested in his/her comment.
If you want to achieve something else, please explain it in a comprehensible way, if necessary by giving examples, in a comment or by updating your question. I really did not get what you really want.
Related
I'm developing an Advice and I want to make it advise only on field sets in specific methods.
I tried cflow(pointcutForSpecificMethod()) && set(* *) pointcut expression but it picks field sets in other methods under control flow of specific methods.
Any idea?
This is not possible directly with an exact pointcut expression, but you can use if() pointcuts to dynamically determine from the stack trace or - like in this case - from the enclosing join point static part exposed by AspectJ - what the executing method is. Here is a little example and an aspect in two variants: native syntax (my preference, more elegant and less boilerplate) and annotation-style syntax:
package de.scrum_master.app;
public class Application {
private int field = 0;
public static void main(String[] args) {
Application app = new Application();
app.foo(11);
app.bar(22);
}
public void foo(int i) {
field = i;
bar(2 * i);
}
void bar(int i) {
field = i;
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
public aspect MyAspectNative {
pointcut pointcutForSpecificMethod() : execution(* foo(*));
public static boolean executingMethodMatches(JoinPoint.StaticPart staticPart) {
return staticPart.getSignature().toLongString().contains("de.scrum_master.app.Application.foo(int)");
}
before() :
cflow(pointcutForSpecificMethod()) && set(* *) &&
if(executingMethodMatches(thisEnclosingJoinPointStaticPart))
{
System.out.println(thisEnclosingJoinPointStaticPart);
System.out.println(thisJoinPoint);
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class MyAspect {
#Pointcut("execution(* foo(*))")
private static void pointcutForSpecificMethod() {}
#Pointcut("if()")
public static boolean executingMethodMatches(JoinPoint.EnclosingStaticPart staticPart) {
return staticPart.getSignature().toLongString().contains("de.scrum_master.app.Application.foo(int)");
}
#Before(
"cflow(pointcutForSpecificMethod()) && set(* *) && " +
"executingMethodMatches(thisEnclosingJoinPointStaticPart)"
)
public void beforeAdvice(JoinPoint thisJoinPoint, JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart)
{
System.out.println(thisEnclosingJoinPointStaticPart);
System.out.println(thisJoinPoint);
}
}
I tried to keep the two aspects as similar as possible structurally. No matter which aspect syntax variant you choose, the output will be:
execution(void de.scrum_master.app.Application.foo(int))
set(int de.scrum_master.app.Application.field)
I am new to AspectJ and reflections What I want to achieve is something like In the below example:
A test class :
public class Sample {
Home home = new Home();
Account account = new Account();
AccountAuthentication accountAuthentication = new AccountAuthentication();
#Test
public void loginInvalidCredentials(){
home.clickOnAccount();
account.login("Admin", "secret");
accountAuthentication.waitForPage();
Assert.assertTrue(true);
}
}
I want to log Output something like this :
packageName.Sample.loginInvalidCredentials
packageName.Home.clickOnAccount();
packageName.Account.login(userName = "Admin", Password ="secret");
packageName.AccountAuthentication.waitForPage();
packageName.Assert.assertTrue(value= true);
I have accessed the name of function packageName.Sample.loginInvalidCredentials with AspectJ
#Aspect
public class AspectClass {
#Around("execution(* *(..)) && #annotation(org.testng.annotations.Test)")
public void around(ProceedingJoinPoint point) throws Throwable {
Method method = MethodSignature.class.cast(point.getSignature()).getMethod();
String methodName = method.getName();
System.out.println("Aspect called for method "+ point.getSignature().getDeclaringType().name +"."+methodName);
try {
//TODO intercept each function call inside the method without any custom anotation and get the value of parameters as well
joinPoint.proceed();
}
}
}
Thanks in advance.
I am assuming that
you use full AspectJ and not something like Spring AOP (because then the answer would not apply),
you do not want to record method calls recursively but just the ones directly called from your #Test methods. For example, if Account.login(..) would internally call Account.checkPassword(..), it should not be recorded. That would also be possible, but then the solution would look differently.
all you want to do is log test execution and not do anything else, so an #Around advice is not necessary, #Before is enough.
Dummy application classes:
package de.scrum_master.app;
public class Account {
public void login(String user, String password) {
checkPassword(password);
}
public void checkPassword(String password) {}
}
package de.scrum_master.app;
public class AccountAuthentication {
public void waitForPage() {}
}
package de.scrum_master.app;
public class Home {
public void clickOnAccount() {
doSomethingElse();
}
public void doSomethingElse() {}
}
Marker annotation:
I created this one myself because I was too lazy to set up a project with TestNG which I normally do not use.
package org.testng.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface Test {}
Sample application:
package de.scrum_master.app;
import org.testng.annotations.Test;
public class Sample {
Home home = new Home();
Account account = new Account();
AccountAuthentication accountAuthentication = new AccountAuthentication();
#Test
public void loginInvalidCredentials() {
home.clickOnAccount();
account.login("Admin", "secret");
accountAuthentication.waitForPage();
}
public static void main(String[] args) {
new Sample().loginInvalidCredentials();
}
}
Aspect:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class TestExecutionLogger {
#Before("execution(* *(..)) && #annotation(org.testng.annotations.Test)")
public void logTest(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
#Before("call(* *(..)) && withincode(#org.testng.annotations.Test * *(..))")
public void logTestActions(JoinPoint joinPoint) {
System.out.println(" " + joinPoint);
}
}
Console log:
execution(void de.scrum_master.app.Sample.loginInvalidCredentials())
call(void de.scrum_master.app.Home.clickOnAccount())
call(void de.scrum_master.app.Account.login(String, String))
call(void de.scrum_master.app.AccountAuthentication.waitForPage())
Of course you can refine your aspect if you really think you need to strip the plain method names from the informative AspectJ log output:
#Before("execution(* *(..)) && #annotation(org.testng.annotations.Test)")
public void logTest(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature());
}
#Before("call(* *(..)) && withincode(#org.testng.annotations.Test * *(..))")
public void logTestActions(JoinPoint joinPoint) {
System.out.println(" " + joinPoint.getSignature());
}
void de.scrum_master.app.Sample.loginInvalidCredentials()
void de.scrum_master.app.Home.clickOnAccount()
void de.scrum_master.app.Account.login(String, String)
void de.scrum_master.app.AccountAuthentication.waitForPage()
You can further refine it if you deliberately want to remove the method's return type or include the actual parameter values like in your example, which is easily possible via JoinPoint.getArgs(), but I leave that up to you. Your question was about pointcuts, not about how to extract which information from joinpoints.
Guys I need a point cut that filter me the called function by a specific class.
public aspect intLogin {
private capture c = new capture();
pointcut login() : execution(public * login(..))
before ():login(){
c.print();
}
}
This is my aspect, I want to know which class call login function. Can you help me?
Helper class called by all the others:
package de.scrum_master.app;
public class Other {
public void doOther() {}
}
Driver application with all kinds of inner classes:
Here we have
non-static inner class,
static inner class,
local inner class,
anonymous class
and of course the normal class.
package de.scrum_master.app;
public class Application {
public String foo(int number) {
new Other().doOther();
return "foo";
}
public class MyInner {
public void doSomething() {
new Other().doOther();
}
}
public static class MyStaticInner {
public void doSomethingElse() {
new Other().doOther();
}
}
public static void main(String[] args) {
new Application().foo(11);
new Application().new MyInner().doSomething();
new Application.MyStaticInner().doSomethingElse();
class LocalInner {
public void doWhatever() {
new Other().doOther();
}
}
new LocalInner().doWhatever();
new Runnable() {
#Override public void run() {
new Other().doOther();
}
}.run();
}
}
Aspect logging caller class names:
package de.scrum_master.aspect;
public aspect CallingClassLogger {
before(Object caller) : !within(CallingClassLogger) && call(* *(..)) && this(caller) {
System.out.println(caller.getClass().getName());
}
}
Console log:
de.scrum_master.app.Application
de.scrum_master.app.Application$MyInner
de.scrum_master.app.Application$MyStaticInner
de.scrum_master.app.Application$1LocalInner
de.scrum_master.app.Application$1
Your aspect would have printed something like
Application.java:5
Application.java:11
Application.java:17
Application.java:28
Application.java:35
which is not so helpful IMO if you are interested in class names.
I solved the problem using thisJoinPoint.getSourceLocation().
The code is:
public aspect intLogin {
private capture c = new capture();
pointcut login(Object a) : call(public * login(..)) && (target(a)) && this(capture);
before (Object x):login( spring.aop.so_52992365.intLogin) {
String xString = x.toString();
System.out.println("The class that is calling the function is:" + thisJoinPoint.getSourceLocation());
c.print();
}
}
I have a problem with the mockito.
Code to my program
public boolean bajaContribuyente(String dni){
Contribuyente c = em.find(Contribuyente.class, dni);
if(c!=null){
em.remove(c);
return true;
}
return false;
}
And the test:
#BeforeClass
public static void setUpBeforeClass()throws Exception{
contribuyenteDAO.setEm(em);;
when(contribuyenteD.getDni()).thenReturn("4");
when(em.find(Contribuyente.class, "4")).thenReturn(contribuyenteD);
}
#Test
public void testBajaContribuyente(){
contribuyenteDAO.bajaContribuyente("4");
verify(em).find(Contribuyente.class, "4");
verify(em).remove(contribuyenteD);
}
JUnit say that missing method call for verify(mock), but i dont know why
You likely need to add a static import of Mockito's methods (e.g. verify), like the following:
import static org.mockito.Mockito.*;
I was wondering if there is anyway of determining what method was active when this aspect was triggered. I found the method JointPoint.getSourceLocation() which returns the source code line. I realised I could try to parse that source file and try to determine the method from that... but there seems like there ought to be a better way.
Basically, if has the following code:
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;
}
}
I'd like to have an aspect like
#After("call(void Banana.eat()) && target(bbb)")
public void whereEaten( Banana bbb ){
....
}
Where in the body I could print out something like `"Banana 47 eaten by org.example.Monkey(org.example.Banana)".
The reason is that that I would like to throw an error if a method has been called by a method without a certain annotation on it. For that I'd need to have the Method of the method.
I suppose this question with its thisEnclosingJoinPointStaticPart can help you.
But the best way to solve your problem is to construct the right join point using withincode and call pointcuts as in example here (see Contract Enforcement section). This way you prevent calls from methods with or without certain annotation.
The list of pointcuts is available here.
What about your sample code lets introduce annotation:
package com.riapriority.test;
public #interface CanEat {
}
Our Banana class:
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;
}
}
Our Monkey class with corresponding annotation:
package com.riapriority.test;
public class Monkey {
#CanEat
public void feed(Banana b) {
b.eat();
}
}
Our Airplane class which, of course, can't eat and so hasn't #CanEat annotation:
package com.riapriority.test;
public class Airplane {
public void feed(Banana b) {
b.eat();
}
}
Our simple main class for testing:
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());
}
}
}
So we need to avoid eating bananas by Airplane. And the corresponding aspect to obtain this:
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()));
}
}
So now our test main class produces the right output:
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)
Hope this solves your problem.