jvmMain.ch.softappeal.yass2.InterceptorReflection.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yass2-jvm Show documentation
Show all versions of yass2-jvm Show documentation
Yet Another Service Solution
package ch.softappeal.yass2
import java.lang.reflect.*
import java.lang.reflect.Proxy.*
import kotlin.coroutines.*
import kotlin.reflect.*
import kotlin.reflect.full.*
import kotlin.reflect.jvm.*
internal fun KClass<*>.serviceFunctions() = memberFunctions
.filter { it.javaMethod!!.declaringClass != Object::class.java }
.sortedBy { it.name }
internal fun KClass<*>.checkService() {
val sf = serviceFunctions()
sf.forEach { require(it.isSuspend) { "'$it' is not a suspend function" } }
require(sf.map { it.name }.toSet().size == sf.size) { "'$this' has overloaded functions" }
}
private interface SuspendFunction {
suspend fun invoke(): Any?
}
private val SuspendMethod = SuspendFunction::class.java.methods[0]
internal fun invokeSuspendFunction(continuation: Continuation<*>, suspendFunction: suspend () -> Any?) = try {
SuspendMethod.invoke(
object : SuspendFunction {
override suspend fun invoke() = suspendFunction()
},
continuation
)
} catch (e: InvocationTargetException) {
throw e.cause!!
}
object ReflectionProxyFactory : ProxyFactory {
override fun create(service: KClass, implementation: S, interceptor: Interceptor): S {
service.checkService()
@Suppress("UNCHECKED_CAST")
return newProxyInstance(service.java.classLoader, arrayOf(service.java)) { _, method, args ->
val parameters = args.copyOf(args.size - 1)
val continuation = args.last() as Continuation<*>
invokeSuspendFunction(continuation) {
interceptor(method.name, parameters) {
try {
method.invoke(implementation, *parameters, continuation)
} catch (e: InvocationTargetException) {
throw e.cause!!
}
}
}
} as S
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy