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

com.mayabot.nlp.injector.Injector.kt Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
package com.mayabot.nlp.injector

import org.jetbrains.annotations.Nullable

// 单例标记注解
// 默认实现注解
// 不支持泛型

interface Injector {
    fun  getInstance(clazz: Class): T?
    fun  getInstance(clazz: Class, tag: String): T?
}

private fun  makeKey(clazz: Class, tag: String): String {
    return "${clazz.name}-$tag"
}

class InjectorImpl(
        val bindMap: HashMap

) : Injector {

    override fun  getInstance(
            clazz: Class
    ): T? {
        return this.getInstance(clazz,"")
    }

    override fun  getInstance(
            clazz: Class,
            name: String
    ): T? {

        val injector = this

        val key = makeKey(clazz, name)

        var beanFactory = bindMap[key]

        if (beanFactory != null) {
            if (beanFactory == NULLBeanFactory) {
                return null
            }
            if (beanFactory is InstanceBeanFactory) {
                return beanFactory.obj as T
            }

            return beanFactory.create(this) as T
        }

        if (name == "") {
            beanFactory = makeAtomBeanFactory(clazz)
        }

        if (beanFactory == null) {
            bindMap[key] = NULLBeanFactory
            return null
        } else {
            bindMap[key] = beanFactory
        }

        return beanFactory.create(injector) as T
    }

    // 关键点在于自动产生
    fun makeAtomBeanFactory(clazz: Class<*>): BeanFactory {
        val ans = clazz.declaredAnnotations
        val defaultImpl: Class<*>? = ans.filterIsInstance(ImplementedBy::class.java).map { it.value.java }.firstOrNull()

        if (clazz.isInterface && defaultImpl == null) {
            return NULLBeanFactory
        }

        val targetClass = if (clazz.isInterface) defaultImpl!! else clazz

        val bf = TargetClassFactory(targetClass)

        return bf
    }

}

val NULLBeanFactory = InstanceBeanFactory(Unit)


fun createInjector(modules: List): Injector {
    val mergeMap = HashMap()
    modules.forEach {
        it.configure()
        val map = it.result()
        map.forEach { (t, u) ->
            mergeMap[t] = u
        }
    }

    return InjectorImpl(mergeMap)
}

class CacheBeanFactory(val from: BeanFactory) : BeanFactory {

    var value: Any? = null

    override fun create(injector: Injector): Any {
        val the = value
        return if (the == null) {
            val h = from.create(injector)
            value = h
            h
        } else {
            the
        }

    }
}

class InstanceBeanFactory(val obj: Any) : BeanFactory {
    override fun create(injector: Injector): Any {
        return obj
    }
}

/**
 * 用反射自动创建一个Class的工厂
 */
class TargetClassFactory(val clazz: Class<*>) : BeanFactory {

    val constructors = clazz.declaredConstructors

    var singleton = clazz.declaredAnnotations.any { it is Singleton }

    var cacheValue:Any? = null

    init {
        if (clazz.isInterface) {
            throw java.lang.RuntimeException("$clazz must not be interface")
        }

        if (constructors.size > 1) {
            throw RuntimeException("${clazz} has more Constructors")
        }
    }


    override fun create(injector: Injector): Any {
        if (singleton) {
            val x = cacheValue
            if (x == null) {
                val c2 = create2(injector)
                cacheValue = c2
                return c2
            }else{
                return x
            }
        }else{
            return create2(injector)
        }
    }

    private fun create2(injector: Injector): Any {
        // class,如果存在唯一一个构造函数
        // 如果构造函数里面的参数是Nullable的,那么autoBind=false


        if (constructors.isEmpty()) {
            return clazz.newInstance()!!
        } else {
            val constructor = constructors.first()

            val count = constructor.parameterCount
            val parameterTypes = constructor.parameterTypes
            val parameterAnnotations = constructor.parameterAnnotations

            if (count == 0) {
                return constructor.newInstance()
            }

            val varpars = Array(count) { null }

            for (i in 0 until count) {
                val pc = parameterTypes[i]
                val nullAble = parameterAnnotations[i].any { it is Nullable }
                val obj = injector.getInstance(pc)

                varpars[i] = obj

                if (!nullAble && obj == null) {
                    throw RuntimeException("Init $clazz ,$pc is null")
                }

            }

            return constructor.newInstance(*varpars)
        }
    }
}

interface Module {
    fun configure()
    fun result(): Map
}

abstract class AbstractModule : Module {

    val bindMap = HashMap()

    fun  bind(clazz: Class): BindCallback {
        return BindCallback(makeKey(clazz, ""))
    }

    fun  bind(clazz: Class, tag: String): BindCallback {
        return BindCallback(makeKey(clazz, tag))
    }

    override fun result() = bindMap

    inner class BindCallback(val key: String) {
        fun toInstance(obj: X) {
            bindMap[key] = InstanceBeanFactory(obj as Any)
        }

        fun toClass(clazz: Class<*>) {
            bindMap[key] = TargetClassFactory(clazz)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy