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

commonMain.co.touchlab.skie.compilerinject.reflection.Reflector.kt Maven / Gradle / Ivy

There is a newer version: 0.9.0-RC.5
Show newest version
package co.touchlab.skie.compilerinject.reflection

import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty

abstract class Reflector {

    private val reflectedClass: Class<*>

    protected abstract val instance: Any

    constructor(reflectedClass: Class<*>) {
        this.reflectedClass = reflectedClass
    }

    constructor(reflectedClass: KClass<*>) : this(reflectedClass.java)

    constructor(fqName: String) {
        reflectedClass = this::class.java.classLoader.loadClass(fqName)
    }

    protected inline fun  declaredMethod0() =
        Provider { DeclaredMethod0(it, R::class.java) }

    protected inline fun  declaredMethod1() =
        Provider {
            DeclaredMethod1(it, P1::class.java, R::class.java)
        }

    protected inline fun  declaredMethod2() =
        Provider {
            DeclaredMethod2(it, P1::class.java, P2::class.java, R::class.java)
        }

    protected inline fun  declaredMethod3() =
        Provider {
            DeclaredMethod3(it, P1::class.java, P2::class.java, P3::class.java, R::class.java)
        }

    protected inline fun  reflectedDeclaredMethod1() =
        Provider {
            ReflectedMethod<(P1) -> Any, (P1) -> R>(DeclaredMethod1(it, P1::class.java, Any::class.java)) { invoke ->
                { param ->
                    invoke(param).reflectedBy()
                }
            }
        }

    protected inline fun  declaredProperty() =
        Provider { DeclaredProperty(it, T::class.java) }

    protected inline fun  declaredField(nameOverride: String? = null) =
        Provider { DeclaredField(nameOverride ?: it, T::class.java) }

    protected inline fun  extensionFunction0(extensionClassFqName: String) =
        Provider { ExtensionFunction0(it, extensionClassFqName, R::class.java) }

    protected inline fun  extensionFunction1(extensionClassFqName: String) =
        Provider { ExtensionFunction1(it, extensionClassFqName, P1::class.java, R::class.java) }

    protected inline fun  extensionFunction1(extensionClassFqName: String, functionName: String) =
        Provider { ExtensionFunction1(functionName, extensionClassFqName, P1::class.java, R::class.java) }

    protected inline fun  extensionProperty(extensionClassFqName: String) =
        Provider { ExtensionProperty(it, extensionClassFqName, T::class.java) }

    protected class Provider(private val factory: (String) -> T) : PropertyDelegateProvider {

        override fun provideDelegate(thisRef: Reflector, property: KProperty<*>): T = factory(property.name)
    }

    protected abstract inner class DeclaredMethod(
        name: String,
        private val returnType: Class,
        parameterTypes: Array>,
    ) : ReadOnlyProperty {

        private val method by lazy {
            reflectedClass.getDeclaredMethod(name, *parameterTypes).also { it.isAccessible = true }
        }

        protected fun invoke(arguments: Array): R =
            method.invoke(instance, *arguments).let { returnType.cast(it) }
    }

    protected inner class DeclaredMethod0(
        name: String,
        returnType: Class,
    ) : DeclaredMethod<() -> R, R>(name, returnType, emptyArray()) {

        override fun getValue(thisRef: Reflector, property: KProperty<*>): () -> R = {
            invoke(emptyArray())
        }
    }

    protected inner class DeclaredMethod1(
        name: String,
        param1: Class,
        returnType: Class,
    ) : DeclaredMethod<(P1) -> R, R>(name, returnType, arrayOf(param1)) {

        override fun getValue(thisRef: Reflector, property: KProperty<*>): (P1) -> R = {
            invoke(arrayOf(it))
        }
    }

    protected inner class DeclaredMethod2(
        name: String,
        param1: Class,
        param2: Class,
        returnType: Class,
    ) : DeclaredMethod<(P1, P2) -> R, R>(name, returnType, arrayOf(param1, param2)) {

        override fun getValue(thisRef: Reflector, property: KProperty<*>): (P1, P2) -> R = { p1, p2 ->
            invoke(arrayOf(p1, p2))
        }
    }

    protected inner class DeclaredMethod3(
        name: String,
        param1: Class,
        param2: Class,
        param3: Class,
        returnType: Class,
    ) : DeclaredMethod<(P1, P2, P3) -> R, R>(name, returnType, arrayOf(param1, param2, param3)) {

        override fun getValue(thisRef: Reflector, property: KProperty<*>): (P1, P2, P3) -> R = { p1, p2, p3 ->
            invoke(arrayOf(p1, p2, p3))
        }
    }

    protected inner class ReflectedMethod(
        private val method: DeclaredMethod,
        private val reflectorFactory: (invoke: WRAPPED) -> T,
    ) : ReadOnlyProperty {

        override fun getValue(thisRef: Reflector, property: KProperty<*>): T {
            return method.getValue(thisRef, property).let(reflectorFactory)
        }
    }

    protected inner class DeclaredProperty(name: String, type: Class) : ReadWriteProperty {

        private val getter by lazy {
            DeclaredMethod0("get" + name.replaceFirstChar { it.uppercase() }, type)
        }
        private val setter by lazy {
            DeclaredMethod1("set" + name.replaceFirstChar { it.uppercase() }, type, Unit::class.java)
        }

        override fun getValue(thisRef: Reflector, property: KProperty<*>): T =
            getter.getValue(thisRef, property).invoke()

        override fun setValue(thisRef: Reflector, property: KProperty<*>, value: T) {
            setter.getValue(thisRef, property).invoke(value)
        }
    }

    protected inner class DeclaredField(name: String, private val type: Class) : ReadWriteProperty {

        private val field by lazy {
            reflectedClass.getDeclaredField(name).also { it.isAccessible = true }
        }

        override fun getValue(thisRef: Reflector, property: KProperty<*>): T =
            field.get(instance).let { type.cast(it) }

        override fun setValue(thisRef: Reflector, property: KProperty<*>, value: T) {
            field.set(instance, value)
        }
    }

    protected abstract inner class ExtensionFunction(
        name: String,
        extensionClassFqName: String,
        private val returnType: Class,
        parameterTypes: Array>,
    ) : ReadOnlyProperty {

        private val method by lazy {
            val extensionClass = this::class.java.classLoader.loadClass(extensionClassFqName)

            extensionClass.getDeclaredMethod(name, reflectedClass, *parameterTypes).also { it.isAccessible = true }
        }

        protected operator fun invoke(arguments: Array): R =
            method.invoke(null, *arguments).let { returnType.cast(it) }
    }

    protected inner class ExtensionFunction0(
        name: String,
        extensionClassFqName: String,
        returnType: Class,
    ) : ExtensionFunction<() -> R, R>(name, extensionClassFqName, returnType, emptyArray()) {

        override fun getValue(thisRef: Reflector, property: KProperty<*>): () -> R = {
            invoke(arrayOf(instance))
        }
    }

    protected inner class ExtensionFunction1(
        name: String,
        extensionClassFqName: String,
        param1: Class,
        returnType: Class,
    ) : ExtensionFunction<(P1) -> R, R>(name, extensionClassFqName, returnType, arrayOf(param1)) {

        override fun getValue(thisRef: Reflector, property: KProperty<*>): (P1) -> R = {
            invoke(arrayOf(instance, it))
        }
    }

    protected inner class ExtensionProperty(
        name: String,
        extensionClassFqName: String,
        type: Class,
    ) : ReadWriteProperty {

        private val getter by lazy {
            ExtensionFunction0("get" + name.replaceFirstChar { it.uppercase() }, extensionClassFqName, type)
        }
        private val setter by lazy {
            ExtensionFunction1("set" + name.replaceFirstChar { it.uppercase() }, extensionClassFqName, type, Unit::class.java)
        }

        override fun getValue(thisRef: Reflector, property: KProperty<*>): T =
            getter.getValue(thisRef, property).invoke()

        override fun setValue(thisRef: Reflector, property: KProperty<*>, value: T) {
            setter.getValue(thisRef, property).invoke(value)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy