Giter Site home page Giter Site logo

Support "custom types" about config4k HOT 3 CLOSED

config4k avatar config4k commented on June 11, 2024
Support "custom types"

from config4k.

Comments (3)

jbunting avatar jbunting commented on June 11, 2024

And for reference, this is the sort of thing that I'm wanting to implement. I make some very opinionated decisions in this code and wouldn't really see fit to put it into the library:

package com.example.extensibleConfig

import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigValue
import io.github.config4k.ClassContainer
import io.github.config4k.CustomType
import io.github.config4k.readers.SelectReader
import io.github.config4k.toConfig
import javax.inject.Named
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor

class SubclassingType<T: Any>(private val parentType: KClass<T>): CustomType {
    private val mappedTypes: Map<String, KClass<*>>
    init {
        val mutableMap = mutableMapOf<String, KClass<*>>()

        parentType.nestedClasses
                .filter { nc -> nc.isSubclassOf(parentType) }
                .forEach { nc ->
                    val typeName = nc.findAnnotation<Named>()?.value ?: throw IllegalStateException("Config Subtype must have @Named annotation.")
                    mutableMap.put(typeName, nc)
                }

        mappedTypes = mutableMap
    }

    override fun parse(clazz: ClassContainer, config: Config, name: String): Any? {
        val type = config.getConfig(name).getString("type")
        val kType = mappedTypes.get(type) ?: throw IllegalArgumentException("'$type' is not an allowable type for $name")

        val reader = SelectReader.getReader(ClassContainer(kType)) ?: throw IllegalStateException("Could not select reader for type $kType")
        return reader.invoke(config, name)
    }

    override fun testParse(clazz: ClassContainer): Boolean {
        return clazz.mapperClass == parentType
    }

    private fun findMappedType(obj: Any): Pair<String, KClass<*>>? {
        return mappedTypes.entries.filter { (_, v) -> v.isInstance(obj) }.singleOrNull()?.toPair()
    }

    override fun testToConfig(obj: Any): Boolean {
        return findMappedType(obj) != null
    }

    override fun toConfig(obj: Any, name: String): Config {
        val (typeName, cl) = findMappedType(obj) ?: throw IllegalStateException("toConfig should not be called if testToConfig is false")

        return ConfigFactory.parseMap(getConfigMap(obj, typeName, cl as KClass<Any>))

    }

    private fun Any.toConfigValue(): ConfigValue {
        val name = "dummy"
        return this.toConfig(name).root()[name]!!
    }

    private fun getConfigMap(receiver: Any, typeName: String,
                              clazz: KClass<Any>): Map<String, *> =
            clazz.primaryConstructor!!.parameters.mapNotNull {
                val parameterName = it.name!!
                clazz.memberProperties
                        .find { it.name == parameterName }!!
                        .get(receiver)
                        ?.let {parameterValue  ->
                            parameterName to parameterValue.toConfigValue()
                        }

            }.toMap().plus("type" to typeName)
}

from config4k.

mmorihiro avatar mmorihiro commented on June 11, 2024

I agree that adding the ability to register custom types is useful. So, could you give an example(like test snippet) in order to make the design clearer?

from config4k.

jbunting avatar jbunting commented on June 11, 2024

I added a pull request with the idea plus a test case. It is simple static registration which I felt went with the existing pattern of the library. However things like dynamic registration or local registration might be useful as well. I'm not crazy about the "static state" thing.

from config4k.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.