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

e.ultra.kontainer.0.77.0.source-code.TypeLookup.kt Maven / Gradle / Ivy

The newest version!
package de.peekandpoke.ultra.kontainer

import kotlin.reflect.KClass

/**
 * Helpers for looking up base and super types.
 */
abstract class TypeLookup {

    /**
     * Get all matching types for the given [type]
     */
    abstract fun getAllCandidatesFor(type: KClass<*>): Set>

    /**
     * Gets a distinct candidate for the given [type]
     *
     * If there is no super type or more than one found, a [ServiceNotFound] is thrown.
     */
    fun getDistinctFor(type: KClass<*>): KClass<*> {

        // TODO: we should have the cache layer at this point and not in the subsclasses
        val candidates = getAllCandidatesFor(type)

        if (candidates.isEmpty()) {
            throw ServiceNotFound("Service ${type.qualifiedName} was not found")
        }

        if (candidates.size > 1) {
            throw ServiceAmbiguous(
                "Service ${type.qualifiedName} is ambiguous. It has multiple candidates: " +
                        candidates.map { it.qualifiedName }.joinToString(", ")
            )
        }

        return candidates.first()
    }

    /**
     * Helper class for finding [baseTypes] of a given super type
     *
     * Result to calls of [getAllCandidatesFor] and cached internally for future reuse.
     */
    data class ForBaseTypes(val baseTypes: Set>) : TypeLookup() {

        /**
         * Internal cache map from classes to their base types
         */
        private val cache = mutableMapOf, Set>>()

        /**
         * Gets all [baseTypes] that are base types of the given super [type]
         */
        override fun getAllCandidatesFor(type: KClass<*>): Set> =
            cache.getOrPut(type) {
                baseTypes.filter { baseType ->
                    baseType.java.isAssignableFrom(type.java)
                }.toSet()
            }
    }

    /**
     * Helper class for finding [superTypes] of given base type
     *
     * Result to calls of [getAllCandidatesFor] and cached internally for future reuse.
     */
    data class ForSuperTypes(val superTypes: Set>) : TypeLookup() {

        /**
         * Internal cache map from classes to their super types
         */
        private val candidatesCache = mutableMapOf, Set>>()

        /**
         * Internal cache map from classes to [LazyServiceLookupBlueprint]
         */
        private val lookupBlueprintCache = mutableMapOf, LazyServiceLookupBlueprint<*>>()

        /**
         * Gets all [superTypes] for the given base [type]
         */
        override fun getAllCandidatesFor(type: KClass<*>): Set> =
            candidatesCache.getOrPut(type) {
                superTypes
                    .filter { superType -> type.java.isAssignableFrom(superType.java) }
                    .toSet()
            }

        /**
         * Get all [superTypes] for the given base [type] as a [LazyServiceLookupBlueprint]
         */
        fun getLookupBlueprint(type: KClass<*>): LazyServiceLookupBlueprint<*> =
            lookupBlueprintCache.getOrPut(type) {

                val map = getAllCandidatesFor(type)
                    .associateWith {
                        { kontainer: Kontainer, context: InjectionContext ->
                            kontainer.get(it, context)
                        }
                    }

                LazyServiceLookupBlueprint(map)
            }

        /**
         * Get a distinct super type of the given [type] or null if there is none or multiple candidates
         */
        fun  getDistinctForOrNull(type: KClass): KClass? {
            @Suppress("UNCHECKED_CAST")
            return getAllCandidatesFor(type).firstOrNull() as KClass?
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy