diff --git a/src/main/kotlin/no/telenor/kt/env/MapEnv.kt b/src/main/kotlin/no/telenor/kt/env/MapEnv.kt new file mode 100644 index 0000000..9315aa2 --- /dev/null +++ b/src/main/kotlin/no/telenor/kt/env/MapEnv.kt @@ -0,0 +1,9 @@ +package no.telenor.kt.env + +@Target(AnnotationTarget.TYPE) +annotation class MapEnv( + /** Separates key and value */ + val eq: String = "=", + /** Separates key1=value1 key2=value2 */ + val separator: String = ";", +) diff --git a/src/main/kotlin/no/telenor/kt/env/parsers/ListParser.kt b/src/main/kotlin/no/telenor/kt/env/parsers/ListParser.kt index 2015c1c..0b7fca1 100644 --- a/src/main/kotlin/no/telenor/kt/env/parsers/ListParser.kt +++ b/src/main/kotlin/no/telenor/kt/env/parsers/ListParser.kt @@ -12,7 +12,7 @@ class ListParser : Parser { val separator = arrayEnvAnnot?.separator ?: "," // val regex = arrayEnvAnnot?.regex ?: false - val itemType = type.arguments[0].type ?: throw Throwable("Could not detect array item type") + val itemType = type.arguments[0].type ?: throw Throwable("Could not detect list item type") // val items = if (regex) value.split(Regex(separator)) else value.split(separator) val items = value.split(separator) val outputs = mutableListOf() diff --git a/src/main/kotlin/no/telenor/kt/env/parsers/MapParser.kt b/src/main/kotlin/no/telenor/kt/env/parsers/MapParser.kt new file mode 100644 index 0000000..273a470 --- /dev/null +++ b/src/main/kotlin/no/telenor/kt/env/parsers/MapParser.kt @@ -0,0 +1,30 @@ +package no.telenor.kt.env.parsers + +import no.telenor.kt.env.MapEnv +import no.telenor.kt.env.Parser +import no.telenor.kt.env.parseValue +import kotlin.reflect.KType + +class MapParser : Parser { + fun parseMap(type: KType, name: String, value: String): Map { + val mapEnvAnnot: MapEnv? = type.annotations.find { it is MapEnv } as MapEnv? + + val eq = arrayOf(mapEnvAnnot?.eq ?: "=") + val separator = mapEnvAnnot?.separator ?: ";" + + val keyType = type.arguments[0].type ?: throw Throwable("Could not detect map key type") + val valueType = type.arguments[1].type ?: throw Throwable("Could not detect map value type") + + val keyValuePairs = value.split(separator) + val outputs = mutableMapOf() + + for (n in keyValuePairs.indices) { + val arr = keyValuePairs[n].split(delimiters = eq, ignoreCase = false, limit = 2) + @Suppress("USELESS_ELVIS") val key = arr[0] ?: continue + @Suppress("USELESS_ELVIS") val str = arr[1] ?: "" + outputs[parseValue(keyType, "$name[$n#key]", key)] = parseValue(valueType, "$name[$key:$n#value]", str) + } + + return outputs + } +} diff --git a/src/main/resources/META-INF/services/no.telenor.kt.env.Parser b/src/main/resources/META-INF/services/no.telenor.kt.env.Parser index 2913799..c3a3439 100644 --- a/src/main/resources/META-INF/services/no.telenor.kt.env.Parser +++ b/src/main/resources/META-INF/services/no.telenor.kt.env.Parser @@ -4,3 +4,4 @@ no.telenor.kt.env.parsers.ListParser no.telenor.kt.env.parsers.NumberParser no.telenor.kt.env.parsers.RegexParser no.telenor.kt.env.parsers.StringParser +no.telenor.kt.env.parsers.MapParser diff --git a/src/test/kotlin/Tests.kt b/src/test/kotlin/Tests.kt index afaa9c3..5ae2a68 100644 --- a/src/test/kotlin/Tests.kt +++ b/src/test/kotlin/Tests.kt @@ -3,6 +3,7 @@ import no.telenor.kt.env.EnvConstructor import no.telenor.kt.env.Environment import no.telenor.kt.env.EnvironmentSnapshot import no.telenor.kt.env.ListEnv +import no.telenor.kt.env.MapEnv import no.telenor.kt.env.construct import kotlin.test.AfterTest import kotlin.test.BeforeTest @@ -19,6 +20,8 @@ data class TestClass @EnvConstructor(prefix = "TEST_") constructor( @Env val int: Int, @Env val numbers: @ListEnv(separator = ";") List<@ListEnv(separator = ".") List>, @Env val lol: Lol, + @Env val map1: Map, + @Env val map2: @MapEnv(eq = ":", separator = ",") Map, ) class Tests { @@ -43,11 +46,16 @@ class Tests { Environment.set( "TEST_INT" to "123", "TEST_NUMBERS" to "1.2;3.4;5.6;7.8", - "TEST_LOL" to "Foo" + "TEST_LOL" to "Foo", + "TEST_MAP1" to "john=doe;foo=bar=baz", + "TEST_MAP2" to "john:doe,foo:bar:baz", ) val derived = construct() assertEquals(derived.int, 123) assertEquals(derived.numbers, listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6), listOf(7, 8))) + assertEquals(derived.lol, Lol.Foo) + assertEquals(derived.map1, mapOf("john" to "doe", "foo" to "bar=baz")) + assertEquals(derived.map2, mapOf("john" to "doe", "foo" to "bar:baz")) } }