I am new to Kotlin and I want to do the following:
Annotate some functions with an annotation e.g "Executable"
At runtime, get all the functions with this annotation
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!
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.
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()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With