jvmAndroidMain.korlibs.inject.AsyncInjectorJvmExt.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of korinject Show documentation
Show all versions of korinject Show documentation
Asynchronous Injector for Kotlin
package korlibs.inject
import java.lang.reflect.*
import kotlin.reflect.*
@Target(AnnotationTarget.CLASS)
annotation class Prototype
@Target(AnnotationTarget.CLASS)
annotation class Singleton
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
annotation class Optional
fun AsyncInjector.jvmAutomapping(): AsyncInjector = this.apply {
this.fallbackProvider = { kclazz, ctx -> AsyncInjector.jvmFallback(this, kclazz, ctx) }
}
suspend fun AsyncInjector.Companion.jvmFallback(
injector: AsyncInjector,
kclazz: KClass<*>,
ctx: AsyncInjector.RequestContext
): AsyncObjectProvider<*> {
return fallback(injector, kclazz, ctx)
}
fun AsyncInjector.jvmRemoveMappingsByClassName(classNames: Set) {
val classes = providersByClass.keys.filter { it.qualifiedName in classNames }
for (clazz in classes) providersByClass.remove(clazz)
parent?.jvmRemoveMappingsByClassName(classNames)
}
private suspend fun fallback(
injector: AsyncInjector,
kclazz: KClass<*>,
ctx: AsyncInjector.RequestContext
): AsyncObjectProvider<*> {
val clazz = (kclazz as kotlin.reflect.KClass<*>).java
//println("Requested $clazz")
val isPrototype = clazz.getAnnotation(Prototype::class.java) != null
val isSingleton = clazz.getAnnotation(Singleton::class.java) != null
val isAsyncFactoryClass = clazz.getAnnotation(AsyncFactoryClass::class.java) != null
//println("isPrototype=$isPrototype, isSingleton=$isSingleton, isAsyncFactoryClass=$isAsyncFactoryClass")
//println(clazz.declaredAnnotations.toList())
val generator: suspend AsyncInjector.() -> Any? = {
try {
// @TODO: Performance: Cache all this!
// Use: ClassFactory and stuff
val loaderClass = clazz.getAnnotation(AsyncFactoryClass::class.java)
val actualClass = loaderClass?.clazz?.java ?: clazz
if (actualClass.isInterface || Modifier.isAbstract(actualClass.modifiers)) throw IllegalArgumentException("Can't instantiate abstract or interface: $actualClass in $ctx")
val constructor = actualClass.declaredConstructors.firstOrNull()
?: throw IllegalArgumentException("No available constructor for $clazz")
val out = arrayListOf()
val allInstances = arrayListOf()
for ((paramType, annotations) in constructor.parameterTypes.zip(constructor.parameterAnnotations)) {
var isOptional = false
val i = if (annotations.isNotEmpty()) {
val i = this.child()
for (annotation in annotations) {
when (annotation) {
is Optional -> isOptional = true
else -> i.mapInstance(annotation.annotationClass as KClass, annotation as Any)
}
}
i
} else {
this
}
if (isOptional) {
out.add(if (i.has(paramType.kotlin)) i.getOrNull(paramType.kotlin, ctx) else null)
} else {
out.add(
i.getOrNull(paramType.kotlin, ctx) ?: throw AsyncInjector.NotMappedException(
paramType.kotlin,
actualClass.kotlin,
ctx
)
)
}
}
allInstances.addAll(out)
constructor.isAccessible = true
val instance = constructor.newInstance(*out.toTypedArray())
// @TODO: Cache this!
val allDeclaredFields = clazz.allDeclaredFields
//for (field in allDeclaredFields.filter { it.getAnnotation(Inject::class.java) != null }) {
// if (Modifier.isStatic(field.modifiers)) continue
// var isOptional = false
// val i = if (field.annotations.isNotEmpty()) {
// val i = this.child()
// for (annotation in field.annotations) {
// when (annotation) {
// is Optional -> isOptional = true
// else -> i.mapInstance(annotation.annotationClass as KClass, annotation as Any)
// }
// }
// i
// } else {
// this
// }
// field.isAccessible = true
// val res = if (isOptional) {
// if (i.has(field.type.kotlin)) i.get(field.type.kotlin, ctx) else null
// } else {
// i.get(field.type.kotlin, ctx)
// }
// allInstances.add(res)
// field.set(instance, res)
//}
if (instance is AsyncDependency) instance.init()
for (createdInstance in allInstances) {
if (createdInstance is InjectedHandler) {
createdInstance.injectedInto(instance)
}
}
if (loaderClass != null) {
(instance as AsyncFactory).create()
} else {
instance
}
} catch (e: Throwable) {
println("$this error while creating '$clazz': (${e.message}):")
e.printStackTrace()
throw e
}
}
return when {
isPrototype -> PrototypeAsyncObjectProvider(generator)
isSingleton -> SingletonAsyncObjectProvider(generator)
isAsyncFactoryClass -> FactoryAsyncObjectProvider(generator as suspend AsyncInjector.() -> AsyncFactory)
//else -> invalidOp("Unmapped jvmAutomapping: $clazz")
else -> PrototypeAsyncObjectProvider(generator)
}
}
private val Class<*>.allDeclaredFields: List
get() = this.declaredFields.toList() + (this.superclass?.allDeclaredFields?.toList() ?: listOf())
© 2015 - 2025 Weber Informatics LLC | Privacy Policy