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

com.jtransc.injector.Injector.kt Maven / Gradle / Ivy

package com.jtransc.injector

import com.jtransc.annotation.JTranscKeep
import com.jtransc.annotation.JTranscKeepConstructors
import com.jtransc.error.invalidOp
import java.lang.reflect.InvocationTargetException

@Suppress("UNCHECKED_CAST")
class Injector() {
	val maps = hashMapOf, () -> Any>(
		Injector::class.java to { this@Injector }
	)

	inline fun  get(): T = getInstance(T::class.java)
	inline fun  getOrNull(): T? = getInstanceOrNull(T::class.java)
	inline fun  get(default: () -> T): T = if (T::class.java in maps) getInstance(T::class.java) else default()

	fun  getInstance(clazz: Class): T {
		return getInstanceOrNull(clazz)
			?: invalidOp("Cannot automap '$clazz' not @Singleton or @Prototype")
	}

	fun  getInstanceOrNull(clazz: Class): T? {
		if (clazz !in maps) {
			val allAnnotations = getAllAnnotations(clazz)
			val isSingleton = allAnnotations.filterIsInstance().isNotEmpty()
			val isPrototype = allAnnotations.filterIsInstance().isNotEmpty()
			if (!isSingleton && !isPrototype) {
				return null
			}
			mapImplementation(clazz, clazz)
		}
		return this.maps[clazz]!!() as T
	}

	internal fun  createInstance(clazz: Class): T {
		val c = clazz.constructors.firstOrNull() ?: invalidOp("No constructors for $clazz")
		try {
			return c.newInstance(*(c.parameterTypes.map { this.getInstance(it) }).toTypedArray()) as T
		} catch (e: InvocationTargetException) {
			throw InvocationTargetException(e, "Can't construct class $clazz : $c")
		}
	}

	private fun getAllAnnotations(clazz: Class<*>): List {
		return if (clazz.superclass == null) {
			clazz.annotations.toList()
		} else {
			clazz.annotations.toList() + getAllAnnotations(clazz.superclass)
		} + clazz.interfaces.flatMap { getAllAnnotations(it) }
	}

	fun mapImplementation(classInterface: Class<*>, classImpl: Class<*>) {
		val allAnnotations = getAllAnnotations(classImpl)
		val isSingleton = allAnnotations.filterIsInstance().isNotEmpty()
		var cached: Any? = null

		this.maps[classInterface] = {
			if (isSingleton) {
				if (cached == null) cached = createInstance(classImpl)
				cached!!
			} else {
				createInstance(classImpl)
			}
		}
	}

	fun mapInstances(vararg objs: Any) = run { for (obj in objs) mapInstance(obj) }
	fun  mapInstance(obj: T): T = mapInstance(obj, obj.javaClass)
	fun  mapInstance(obj: T, type: Class): T = obj.apply { maps[type] = { obj } }
	inline fun  mapImpl() = mapImplementation(TInt::class.java, TImpl::class.java)
}

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
@JTranscKeepConstructors
annotation class Singleton()

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
@JTranscKeepConstructors
annotation class Prototype()




© 2015 - 2024 Weber Informatics LLC | Privacy Policy