Search code examples
javaspringkotlinspring-webfluxspring-aop

Webflux-Aop:Get method request(Mono) in Aspect class


I am trying to write an aspect which is responsible to call some external systems, before calling service impl classes.

I have difficulty getting method request in aspect class.Any help would be appreciated. I tried to write as below ,but no luck getting Mono Object in aspect class.

Method

@someAnnotation
@PutMapping
fun getAccounts(
    @RequestParam(name = "someParam")
    someParam: String?,
    @ModelAttribute
    request: Mono<Request>,
): Mono<Response>{
        return response;
    }

Annotation

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class someAnnotation(
    val api: String,
)

Aspect:

@Aspect
@Component
@Order(0)
class SomeAspect{
    @Suppress("UNCHECKED_CAST")
    @Around("@annotation(someAnnotation)&&args(req,..)")
    @Throws(Throwable::class)
    fun <T> getResponse(joinPoint: ProceedingJoinPoint,apiReq : Mono<T>): Mono<T> {
        
        val target = joinPoint.target
        val methodSignature = joinPoint.signature as MethodSignature
        val method: Method = methodSignature.method

        val flux: Mono<T> = joinPoint.proceed() as Mono<T>
        val methodArgs = joinPoint.args

//How to get request: Mono<Request> here????
        
        return flux.flatMap { it ->
            val req = it as someObject
           //do something here........
        }
    }
}

Solution

  • Following modification to the aspect code would solve the issue. The OP want to advice a method with multiple arguments and the required argument to be made available to the advice body would be the last argument.

    Summarizing the resolution through comments here.

    @Aspect
    @Component
    @Order(0)
    class SomeAspect{
        @Suppress("UNCHECKED_CAST")
        @Around("@annotation(someAnnotation) && args(..,apiReq)")
        @Throws(Throwable::class)
        fun <T> getResponse(joinPoint: ProceedingJoinPoint,apiReq : Mono<T>): Mono<T> {
            
            val target = joinPoint.target
            val methodSignature = joinPoint.signature as MethodSignature
            val method: Method = methodSignature.method
    
            val flux: Mono<T> = joinPoint.proceed() as Mono<T>
            val methodArgs = joinPoint.args
    
    
            //.. apiReq will refer to the required argument
            return flux.flatMap { it ->
                val req = it as someObject
               //do something here........
            }
        }
    }