PeXXeR
PeXXeR

Reputation: 101

Invoke annotated aspect on all methods with a specific annotation

I have an application based on MVC and I want to log inputs/outputs from all my controllers.
Also, each of my controller methods is annotated with some specific annotation (eg: @MyControllerMethod).
I wrote an Annotated Aspect which works fine when I use the annotation (eg: LogRequestReply) from the aspect on my controller methods.

@Around("@annotation(com.xyz.LogRequestReply)")
public Object logRequestResponse(ProceedingJoinPoint pjp) throws Throwable {
@MyControllerMethod
@LogRequestReply /* It invokes my logRequestResponse method */
public ResponseEntity controllerMethodA(...) {}

However, I have a lot of controller methods and each with annotation MyControllerMethod.
Is there a way I can make my aspect annotation make work on all controller methods by default, such that each of the methods automatically calls my aspect logger and I can log the inputs/outputs?

Note: I also looked into writing an interceptor extending from HandlerInterceptorAdapter. But it has its own complexity of being able to log request/response where the stream can only be read once.

Please suggest.

Upvotes: 1

Views: 1110

Answers (2)

adoalonso
adoalonso

Reputation: 325

Perhaps you should include the AOP in your controller-config

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:oxm="http://www.springframework.org/schema/oxm"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">

    <mvc:default-servlet-handler />

    <context:component-scan base-package="com.xyz.controller" />

    <aop:aspectj-autoproxy proxy-target-class="true" />

    <bean id="whatever" class="com.xyz.controller.MyRestController"/>

</bean>

and in your Aspect you can also include the within combined with annotation:

@Around(value = "@within(com.xyz.server.annotation.MyAnnotationForController) || @annotation(com.xyz.server.annotation.MyAnnotationForController)")
public Object ownersTimeZone(ProceedingJoinPoint joinPoint) throws Throwable {
    //whatever you need before
    Object obj = joinPoint.proceed();
    //whatever you need after
    return obj;
}

Upvotes: 0

Ezequiel
Ezequiel

Reputation: 136

One option is to let the @Around definition less restrictive, add a restriction by package or something like that. Internally you can check if this is a Controller by this check bellow and then print the request/response:

@Pointcut("within(com.mypackage.controller..*)")
private void inControllerPackage() {
}

@Around("inControllerPackage()")
public Object logRequestResponse(ProceedingJoinPoint pjp) throws Throwable {
    if (pjp.getSignature().getDeclaringType().isAnnotationPresent(RestController.class)) {
       ...
    } 

Upvotes: 1

Related Questions