Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a list of annotated functions in Kotlin using reflection

I am new to Kotlin and I want to do the following:

  1. Annotate some functions with an annotation e.g "Executable"

  2. At runtime, get all the functions with this annotation

  3. Inspect a property on the annotation and if it matches a condition, invoke the function

I have the following code

annotation class Executable(val name : String)

@Executable("doSomething")
fun stepDoSomething (param1 : String) {
    println("I am a step that does something! I print $param1")
}

However, I am unclear on how to retrieve all functions with the Executable annotation at runtime and inspect them.

Thank you for your help!

like image 836
user12276369 Avatar asked Oct 24 '25 02:10

user12276369


2 Answers

To accomplish this, you will need to use a classpath scanner, such as ClassGraph. Classpath scanners offer APIs to find classes based on various criteria, such as what package they’re in, what interface they implement, or what annotations they have. In the case of ClassGraph, the ScanResult has a getClassesWithMethodAnnotation(String name) method. Once you have all of those classes, you can use ordinary reflection to find which method(s) in those classes have the specific annotation you’re looking for and inspect the properties of the annotations. Here is a good overview of how to create an annotation and inspect it using reflection.

like image 137
Matthew Pope Avatar answered Oct 26 '25 22:10

Matthew Pope


Here is my implementation based on (very helpful) Matthew Pope's answer:

import io.github.classgraph.ClassGraph
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.jvm.kotlinFunction

@Image(filename = "image-1.svg")
fun foo() {
    println("in foo")
}

@Image(filename = "image-2.svg")
fun bar() {
    println("in bar")
}

@Throws(Exception::class)
fun getAllAnnotatedWith(annotation: KClass<out Annotation>): List<KFunction<*>> {
    val `package` = annotation.java.`package`.name
    val annotationName = annotation.java.canonicalName

    return ClassGraph()
        .enableAllInfo()
        .acceptPackages(`package`)
        .scan().use { scanResult ->
            scanResult.getClassesWithMethodAnnotation(annotationName).flatMap { routeClassInfo ->
                routeClassInfo.methodInfo.filter{ function ->
                     function.hasAnnotation(annotation.java) }.mapNotNull { method ->
                        method.loadClassAndGetMethod().kotlinFunction
                        // if parameter needed:
                        // method.getAnnotationInfo(routeAnnotation).parameterValues.map { it.value }
                    }
            }
        }
}

fun main(args: Array<String>) {
    getAllAnnotatedWith(Image::class)
        .forEach { function ->
            function.call()
        }
}
like image 30
Dimitry Ernot Avatar answered Oct 26 '25 21:10

Dimitry Ernot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!