0%
August 5, 2024

AOP in Kotlin

kotlin

springboot

Annotation on Methods

We start with a simple case:

package com.machingclee.payment.annotation

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class LogParam(
    val value: String = ""
)

From this we can annotate any method with @LogParam.

Here is a code example on what can be done:

import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.reflect.MethodSignature
import org.springframework.stereotype.Component

@Aspect
@Component
class LogAspect {
    @Around("@annotation(com.machingclee.payment.annotation.LogParam)")
    fun around(point: ProceedingJoinPoint): Any? {
        val name = point.signature.name
        println("function $name is called")

        val signature = point.signature as MethodSignature
        val method = signature.method
        val annotation = method.getAnnotation(LogParamType::class.java)
        val value = annotation.value
        val parameterTypes = method.parameterTypes[0].name
        println("annotation $value and parameterTypes $parameterTypes")
        return point.proceed()
    }
}

A helpful usecase is to validate user's access right before accessing a specific controller (method).

Annotation on Class

Sometimes we would like to have interceptor applied to all the methods of a class, we replace @Target(AnnotationTarget.FUNCTION) by @Target(AnnotationTarget.CLASS) and write:

@Aspect
@Component
class LogAspect {
    @Around("@within(com.machingclee.payment.annotation.LogParam)")
    fun around(point: ProceedingJoinPoint): Any? {
        try {
            val signature = point.signature as MethodSignature
            val method = signature.method
            val annotation = method.getAnnotation(LogParamType::class.java)
            println("parmeters: ${method.parameters[0]}")
            val annotation = method.getAnnotation(LogParamType::class.java)
            val value = annotation.value
            val parameterTypes = method.parameterTypes[0].name
            println("annotation $value and parameterTypes $parameterTypes")
            return point.proceed()
        } catch (e: Exception) {
            println(e.message)
            return null
        }
    }
}

Here @within will target to all methods of a class annotated by LogParam.

More References