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

com.mitteloupe.randomgenkt.JavaDefaultValuesInstanceProvider.kt Maven / Gradle / Ivy

The newest version!
package com.mitteloupe.randomgenkt

import com.mitteloupe.randomgenkt.model.DataProviderMap
import com.mitteloupe.randomgenkt.model.InstanceProvider
import java.lang.reflect.Constructor

internal class JavaDefaultValuesInstanceProvider(
    private val generatedInstanceClass: Class
) : InstanceProvider {
    private var validConstructor: Constructor? = null

    private val allPublicConstructors: MutableList>

    init {
        @Suppress("UNCHECKED_CAST")
        val typedConstructors =
            generatedInstanceClass.constructors as Array>
        allPublicConstructors = typedConstructors.toMutableList()
    }

    override fun invoke(dataProviders: DataProviderMap) = try {
        instanceFromAnyConstructor()
    } catch (exception: Exception) {
        throw InstanceCreationException(
            "Failed to instantiate ${generatedInstanceClass.simpleName}. " +
                "Try providing a ValuesInstanceProvider.",
            exception
        )
    }

    @Throws(Exception::class)
    private fun instanceFromAnyConstructor(): GENERATED_INSTANCE {
        validConstructor?.let {
            return getInstance(validConstructor)
        }

        do {
            val constructorToUse = allPublicConstructors.firstOrNull()
            try {
                val instance = getInstance(constructorToUse)
                validConstructor = constructorToUse
                return instance
            } catch (throwable: Throwable) {
                constructorToUse?.let {
                    allPublicConstructors.remove(it)
                }
            }
        } while (allPublicConstructors.isNotEmpty())

        return generateInstanceWithNewConstructor()
    }

    @Throws(Exception::class)
    private fun getInstance(constructorToUse: Constructor?) =
        if (constructorToUse == null) {
            generateInstanceWithNewConstructor()
        } else {
            val parameterTypes = constructorToUse.parameterTypes
            val parameterValues = getParameterValues(parameterTypes)

            generatedInstanceWithParameters(constructorToUse, *parameterValues)
        }

    private fun getParameterValues(parameters: Array>) = parameters.map { parameter ->
        when (parameter) {
            Short::class.javaPrimitiveType, Short::class.javaObjectType -> 0.toShort()
            Int::class.javaPrimitiveType, Int::class.javaObjectType -> 0
            Long::class.javaPrimitiveType, Long::class.javaObjectType -> 0L
            Float::class.javaPrimitiveType, Float::class.javaObjectType -> 0f
            Double::class.javaPrimitiveType, Double::class.javaObjectType -> 0.0
            Byte::class.javaPrimitiveType, Byte::class.javaObjectType -> '\u0000'.code.toByte()
            Boolean::class.javaPrimitiveType, Boolean::class.javaObjectType -> false
            String::class.javaPrimitiveType, String::class.javaObjectType -> ""
            Any::class.javaObjectType -> Any()
            List::class.javaObjectType -> emptyList()
            Array::class.javaObjectType -> emptyArray()
            Map::class.javaObjectType -> emptyMap()
            Set::class.javaObjectType -> emptySet()
            else -> null
        }
    }.toTypedArray()

    @Throws(Exception::class)
    private fun generatedInstanceWithParameters(
        constructor: Constructor,
        vararg parameterValues: Any?
    ): GENERATED_INSTANCE {
        constructor.isAccessible = true

        return constructor.newInstance(*parameterValues)
    }

    @Throws(Exception::class)
    private fun generateInstanceWithNewConstructor() =
        generateInstanceWithNewConstructorUsingReflectionFactory()

    @Throws(Exception::class)
    private fun generateInstanceWithNewConstructorUsingReflectionFactory(): GENERATED_INSTANCE =
        generatedInstanceClass.constructors.firstNotNullOf { constructor ->
            constructor.newInstance()
        } as GENERATED_INSTANCE

    class InstanceCreationException(message: String, exception: Exception) :
        RuntimeException(message, exception)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy