Skip to content

Inheritance

By default, AspectK only intercepts functions that are directly annotated with a target annotation. With inherits = true, advice also applies to functions that override an annotated function, even if the override itself is not annotated.

Default Behavior (inherits = false)

abstract class BaseRepository {
    @Cached
    abstract fun findById(id: String): Entity?
}

class SqlRepository : BaseRepository() {
    // No @Cached annotation here
    override fun findById(id: String): Entity? { ... }
}

@Aspect
object CacheAspect {
    @Before(target = [Cached::class])  // inherits = false by default
    fun cache(joinPoint: JoinPoint) { ... }
}

With default settings, cache() runs for BaseRepository.findById declarations but not for SqlRepository.findById calls (since the override is not annotated).

Enabling Inheritance

@Aspect
object CacheAspect {
    @Before(target = [Cached::class], inherits = true)
    fun cache(joinPoint: JoinPoint) { ... }
}

Now cache() runs for any override of a @Cached-annotated function, regardless of whether the override itself carries the annotation.

Use Cases

Interface Contracts

interface AuthService {
    @RequiresAdmin
    fun deleteUser(userId: String)

    @RequiresAdmin
    fun resetPassword(userId: String)
}

class AuthServiceImpl : AuthService {
    // Both overrides are protected automatically with inherits = true
    override fun deleteUser(userId: String) { ... }
    override fun resetPassword(userId: String) { ... }
}

@Aspect
object AdminAspect {
    @Before(target = [RequiresAdmin::class], inherits = true)
    fun verifyAdmin(jp: JoinPoint) {
        if (!currentUser.isAdmin) throw ForbiddenException()
    }
}

Abstract Base Classes

Use inherits = true when you annotate template methods in abstract classes and want all concrete implementations to be intercepted automatically.

How It Works

When inherits = true, AspectK's InheritableVisitor tracks all IR functions that override a function annotated with a target annotation. These overriding functions are added to the transform targets, even without the direct annotation.