DepInj/src/main/kotlin/nl/voidcorp/depinj/DepInj.kt

83 lines
2.6 KiB
Kotlin

package nl.voidcorp.depinj
import java.io.File
import java.io.IOException
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.full.isSuperclassOf
import kotlin.reflect.jvm.jvmName
private val classes = mutableListOf<KClass<out Any>>()
val classesP: List<KClass<out Any>>
get() {
if (classes.isEmpty()) init()
return classes
}
class Dep<T>(val block: (property: KProperty<*>) -> T) {
operator fun getValue(thisRef: Any?, property: KProperty<*>) = block(property)
}
inline fun <reified T : Any> single(): Dep<T> {
return Dep {
classesP
.first { T::class.isSuperclassOf(it) && !it.java.isInterface }
.constructors.first { it.parameters.isEmpty() }.call() as T
}
}
inline fun <reified T : Any> multi(): Dep<List<T>> {
return Dep {
classesP
.filter { T::class.isSuperclassOf(it) && !it.java.isInterface }
.map { cls -> cls.constructors.first { it.parameters.isEmpty() }.call() as T }
}
}
private fun init() {
classes.addAll(Package.getPackages().map { getClasses(it.name) }.flatten())
}
@Throws(ClassNotFoundException::class, IOException::class)
private fun getClasses(packageName: String): List<KClass<out Any>> {
val classLoader = Thread.currentThread().contextClassLoader!!
val path = packageName.replace('.', '/')
val resources = classLoader.getResources(path)
val dirs = mutableListOf<File>()
while (resources.hasMoreElements()) {
val resource = resources.nextElement()
dirs.add(File(resource.file))
}
val classes = mutableListOf<Class<*>>()
for (directory in dirs) {
classes.addAll(findClasses(directory, packageName))
}
return classes.map { it.kotlin }.filterNot { it.java.isSynthetic }
.filterNot { Class.forName("kotlin.jvm.internal.Lambda").isAssignableFrom(it.java) }
.filterNot { it.jvmName.endsWith("Kt") }
.filterNot { it.jvmName.contains("$1") }
}
@Throws(ClassNotFoundException::class)
private fun findClasses(directory: File, packageName: String): List<Class<*>> {
val classes = mutableListOf<Class<*>>()
if (!directory.exists()) {
return classes
}
val files = directory.listFiles()
for (file in files!!) {
if (file.isDirectory) {
assert(!file.name.contains("."))
classes.addAll(findClasses(file, packageName + "." + file.name))
} else if (file.name.endsWith(".class")) {
classes.add(Class.forName(packageName + '.'.toString() + file.name.substring(0, file.name.length - 6)))
}
}
return classes
}