0

Is it possible to use Spring AOP (AspectJ) with Kotlin properties? Specifically due to how Kotlin compiles properties to Java:

  • a getter method, with the name calculated by prepending the get prefix
  • a setter method, with the name calculated by prepending the set prefix (only for var properties)
  • a private field, with the same name as the property name (only for properties with backing fields)

Consider the following minimal reproducible example:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION)
annotation class TestAnnotation

...

@Aspect
class TestAspect {
    @Around("@annotation(annotation)")
    fun throwingAround(joinPoint: ProceedingJoinPoint, annotation: TestAnnotation): Any? {
        throw RuntimeException()
    }
}

...

internal class MinimalReproducibleExample {

    open class TestProperties {
        @TestAnnotation
        val sampleProperty: String = "sample property"

        @TestAnnotation
        fun sampleFunction(): String = "sample function"
    }

    private lateinit var testProperties: TestProperties

    @BeforeEach
    fun setUp() {
        val aspectJProxyFactory = AspectJProxyFactory(TestProperties())
        aspectJProxyFactory.addAspect(TestAspect())
        val aopProxyFactory = DefaultAopProxyFactory()
        val aopProxy = aopProxyFactory.createAopProxy(aspectJProxyFactory)
        testProperties = aopProxy.proxy as TestProperties
    }

    @Test
    fun test() {
        println(testProperties.sampleProperty)
        println(testProperties.sampleFunction())
    }
}

Running the test yields:

null
sample function

When debugging I can see that the generated proxy is a cglib-backed proxy, which should be able to proxy to a concrete class, but it does not seem to invoke the configured aspect. Is there something wrong with my @Around definition, or is this a limitation of Kotlin properties and/or proxying concrete classes?

Bennett Lynch
  • 554
  • 4
  • 11

1 Answers1

0

Was able to trigger the aspect above with the following changes:

  1. Use a "site target" for the getter: @get:TestAnnotation
  2. Make the property/function both open
Bennett Lynch
  • 554
  • 4
  • 11
  • I do not speak Kotlin at all, but you seem to talk about [annotation use-site targets](https://kotlinlang.org/docs/annotations.html#annotation-use-site-targets). Quite interesting. Yes, like this an `@annotation()` pointcut would work. With Aspectj you can, however, also intercept direct field access and match field annotations directly. I just want to mention it, because Java users might also find this answer, and they do not have this Kotlin syntactic sugar at their disposal. – kriegaex Dec 16 '22 at 14:06