luca
luca

Reputation: 3318

Spring AOP and annotation to check parameter before method execution

I have to throw an exception if a method parameter is a particular value. The aim is to lock all the method that work with the specific value so I thought to use Spring AOP but I am new with it. My problem is retrieve the value of method parameter, I create this sample:

Annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAOPAnnotation {
}

AOP class

@Component
@Aspect
public class TestAOP {

    @Before("@annotation(TestAOPAnnotation)")
    public void logAOP(){
        //Make some operations with database and throw exception in a specific case 
        throw new RuntimeException();
    }
}

The method where I use the annotation

@Override
@TestAOPAnnotation
public List<Animals> findByName(String name) throws QueryException {
    try{
        return animalsRepository.findByName(name);
    }catch(Exception e){
        throw new QueryException(e);
    }
}

and where I catch the exception

@Override
@RequestMapping(value="/test/{name}", method = RequestMethod.GET)
public @ResponseBody List<Animals> findByName(@PathVariable String name){
    try{
        return databaseAnimalsServices.findByName(name);
    }catch(QueryException e){
        return null;
    }catch(Exception e){
        //CATCH AOP EXCEPTION
        List<Animals> list = new ArrayList<Animals>();
        list.add(new Animals("AOP", "exception", "test"));
        return list;
    }
}

How can I get the name parameter? I may use another annotation on parameter (or only this annotation) but I don't know how. Can you help me?

EDIT To catch parameter annotation I may use:

@Before("execution(* *(@Param (*),..))")

but it works only if I know the parameters order instead I need only the annotated parameter. Otherwise , until now, the best solution is

@Before("@annotation(TestAOPAnnotation) && args(name,..)")
public void logAOP(String name){
    System.out.println(name);
    throw new RuntimeException("error");
}

but the parameter must be the fist in the signature

Upvotes: 0

Views: 5730

Answers (2)

Essex Boy
Essex Boy

Reputation: 7950

You can get the calling arguments from the joinPoint:

@Around(.....)
public Object check(ProceedingJoinPoint joinPoint) {
    for (Object object : joinPoint.getArgs()) {
           .... add your checks here.
    }
    return joinPoint.proceed();

}

Note you can not easily get the name of the parameter from the joinPoint (like you can in .NET) but you could check on type and value.

See https://blog.espenberntsen.net/2010/03/20/aspectj-cheat-sheet/ for valid execution patterns.

Upvotes: 0

Roman Puchkovskiy
Roman Puchkovskiy

Reputation: 11835

You could use an @Around advice which has access to the invocation data.

@Around("@annotation(TestAOPAnnotation)")
public Object logAOP(ProceedingJoinPoint aPoint) throws Throwable {
    // First, implement your checking logic
    // aPoint.getArgs() may be inspected here ...
    if (...) {
        throw new RuntimeException(...);
    }

    // now, actually proceed with the method call
    return aPoint.proceed();
}

getArgs() gives you access to the real arguments passed to the method.

Upvotes: 1

Related Questions