Multiple Targets
AspectK supports many-to-many relationships between advice and target annotations.
One Advice, Multiple Targets
A single @Before method can target multiple annotation classes:
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class Logged
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class Traced
@Aspect
object ObservabilityAspect {
@Before(target = [Logged::class, Traced::class])
fun observe(joinPoint: JoinPoint) {
println("Intercepting: ${joinPoint.signature.methodName}")
}
}
Functions annotated with either @Logged or @Traced (or both) will trigger this advice.
Multiple Advice, One Target
Multiple @Before methods (from the same or different aspects) can all target the same annotation:
@Aspect
object LoggingAspect {
@Before(target = [Audited::class])
fun log(joinPoint: JoinPoint) {
println("LOG: ${joinPoint.signature.methodName}")
}
}
@Aspect
object AuditAspect {
@Before(target = [Audited::class])
fun audit(joinPoint: JoinPoint) {
auditService.record(joinPoint.signature.methodName, joinPoint.args)
}
}
@Audited
fun deleteAccount(userId: String) {
// Both log() and audit() run before this body
}
Combining Multiple Annotations on a Function
A function can carry multiple target annotations, triggering all matching advice:
@Logged @Traced @Metered
fun processCheckout(cart: Cart, userId: String) {
// All three aspects run their advice before this body
}
This is a natural composition — AspectK applies all matching advice in compiler-discovery order.
Identifying the Trigger Annotation
Inside advice, use JoinPoint.signature.annotations to determine which annotations are
present on the intercepted function:
@Aspect
object DispatchAspect {
@Before(target = [Logged::class, Traced::class])
fun dispatch(joinPoint: JoinPoint) {
val annotationNames = joinPoint.signature.annotations.map { it.typeName }
if ("com.example.Logged" in annotationNames) {
logger.info(joinPoint.signature.methodName)
}
if ("com.example.Traced" in annotationNames) {
tracer.start(joinPoint.signature.methodName)
}
}
}