All Downloads are FREE. Search and download functionalities are using the official Maven repository.

run.smt.ktest.util.reflection.annotations.kt Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package run.smt.ktest.util.reflection

import java.lang.reflect.Method
import java.lang.reflect.Proxy
import kotlin.reflect.KClass
import java.lang.reflect.Array as ReflectArray

inline fun  a(valueArg: Any?): T = a(T::class, valueArg)
inline fun  a(args: Map): T = a(T::class, args)
inline fun  a(vararg args: Pair = emptyArray()): T = a(mapOf(*args))

fun  a(clazz: KClass, args: Map) = createAnnotationStub(
    clazz,
    { args.containsKey(it?.name) },
    { _, method, _ -> args[method?.name] }
)

fun  a(clazz: KClass, valueArg: Any?): T = createAnnotationStub(
    clazz,
    { it?.name == "value" },
    { _, _, _ -> valueArg }
)

@Suppress("UNCHECKED_CAST")
private inline fun  createAnnotationStub(
    clazz: KClass,
    crossinline handledCase: (Method?) -> Boolean,
    crossinline handler: (T, Method?, Array?) -> Any?
): T {
    return Proxy.newProxyInstance(clazz.java.classLoader, arrayOf(clazz.java)) { proxy, method, args: Array? ->
        val self = proxy as T
        handleCommonAnnotationMethods(clazz, self, method, args) ?:
            if (handledCase(method)) {
                val result = handler(self, method, args)
                val methodReturn = method?.returnType
                if (methodReturn?.isArray == true && result?.javaClass != methodReturn && result != null) {
                    val arrayResult = ReflectArray.newInstance(methodReturn.componentType, 1)
                    ReflectArray.set(arrayResult, 0, result)
                    arrayResult
                } else {
                    result
                }
            } else {
                extractDefaultsIfAny(method)
            }
    } as T
}

private fun extractDefaultsIfAny(method: Method): Any? {
    return when {
        method.defaultValue != null -> method.defaultValue
        method.returnType.isArray -> ReflectArray.newInstance(method.returnType.componentType, 0)
        else -> null
    }
}

private fun  handleCommonAnnotationMethods(clazz: KClass, instance: T, currentMethod: Method?, args: Array?)
    = when (currentMethod?.name) {
    "annotationType" -> clazz.java
    "equals" -> {
        val compareTo = args?.firstOrNull()
        compareTo != null && compareTo is Annotation && extractAnnotationValues(instance).toList() == extractAnnotationValues(compareTo).toList()
    }
    "toString" -> "@" + clazz.java.canonicalName + "(" + extractAnnotationValues(instance).map { it.first + "=" + it.second }.joinToString(", ") + ")"
    "hashCode" -> instance.toString().hashCode()
    else -> null
}

private fun extractAnnotationValues(annotation: Annotation): Sequence> {
    return annotation.annotationClass.java.declaredMethods.asSequence()
        .filter { it.name !in arrayOf("equals", "hashCode", "toString", "annotationType") }
        .filter { it.parameterTypes.isEmpty() }
        .map({ it.name to it.invoke(annotation) })
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy