A Kotlin wrapper for Typesafe Config

Overview

Config4k

Build Status codecov ktlint Maven Central Sonatype Nexus (Snapshots) javadoc GitHub

Config for Kotlin.

Config4k is a lightweight Typesafe Config wrapper for Kotlin and inspired by ficus, providing simple extension functions Config.extract<T> and Any.toConfig to convert between Config and Kotlin Objects.

example

Table of Contents

Installation

Gradle:

repositories {
    mavenCentral()
}


dependencies {
    compile 'io.github.config4k:config4k:xxx' // See the `Download` badge
}

Usage

Delegated Properties

By far the simplest way to use config4k is via Kotlin Delegated Properties:

val config = ConfigFactory.parseString("""
                                          |stringValue = hello
                                          |booleanValue = true
                                          |""".trimMargin())

val stringValue: String by config
println(stringValue) // hello

val nullableStringValue: String? by config
println(nullableStringValue) // null

val booleanValue: Boolean by config
println(booleanValue) // true

Deserialization

Config.extract<T> converts Config to T.

Map

Maps can be serialized with String keys

val config = ConfigFactory.parseString("""
                                          |map {  
                                          |  foo = 5
                                          |  bar = 6
                                          |}""".trimMargin())
val map: Map<String, Int> = config.extract<Map<String, Int>>("map")
println(map["foo"] == 5) // true
println(map["bar"] == 6) // true

or with arbitrary keys

val config = ConfigFactory.parseString("""
                                          |map = [{  
                                          |  key = 5
                                          |  value = "foo"
                                          |}
                                          |{
                                          |  key = 6
                                          |  value = "bar"
                                          |}]""".trimMargin())
val map: Map<Int, String> = config.extract<Map<Int, String>>("map")
println(map[5] == "foo") // true
println(map[6] == "bar") // true

Test Class: TestMap.kt

Data Classes

Config4k has no option to use different names between code and config file.

data class Person(val name: String, val age: Int)

val config = ConfigFactory.parseString("""
                                          |key {  
                                          |  name = "foo"
                                          |  age = 20
                                          |}""".trimMargin())
val person: Person = config.extract<Person>("key")
println(person.name == "foo") // true
println(person.age == 20) // true

For more details, please see TestArbitraryType.kt

Nullable

Using extract<T?> is the better way than Config.hasPath(). extract<T?> returns T when the path exists and null when it does not exist.

val config = ConfigFactory.parseString("""key = 10""")
val key = config.extract<Int?>("key")
val foo = config.extract<Int?>("foo")
println(key == 10) // true
println(foo == null) // true

Test Class: TestNullable.kt

Enum

Config4k also supports Enum. Enum is converted to String of its name in the config file.

enum class Size {
    SMALL,
    MEDIUM,
    LARGE
}

val config = ConfigFactory.parseString("""key = SMALL""")
val small = config.extract<Size>("key")
println(small == Size.SMALL) // true

Test Class: TestEnum.kt

Serialization

Any.toConfig converts the receiver object to Config.

String

You can use ConfigValue.render() to serialize Config. Config4k helps getting Config of the class you want to serialize.

data class Person(val name: String, val age: Int)
val person = Person("foo", 20).toConfig("person")
println(person.root().render())

Output:

{
    # hardcoded value
    "person" : {
        # hardcoded value
        "age" : 20,
        # hardcoded value
        "name" : "foo"
    }
}

Test Class: TestToConfigForArbitraryType.kt

ConfigRenderOptions

Typesafe Config's class ConfigRenderOptions is the argument of ConfigValue.render.

// If setJson(false) is called, ConfigValue.render returns HOCON
data class Person(val name: String, val age: Int)
val person = Person("foo", 20).toConfig("person")
val options = ConfigRenderOptions.defaults().setJson(false)
println(person.root().render(options))

Output:

    # hardcoded value
person {
    # hardcoded value
    age=20
    # hardcoded value
    name=foo
}
// setOriginComments(false) removes comments
data class Person(val name: String, val age: Int)
val person = Person("foo", 20).toConfig("person")
val options = ConfigRenderOptions.defaults()
                        .setJson(false)
                        .setOriginComments(false)
println(person.root().render(options))

Output:

person {
    age=20
    name=foo
}

Supported types

Property delegation, extract and toConfig support these types:

  • Primitive types
    • Boolean
    • Byte
    • Int
    • Long
    • Float
    • Double
  • String
  • import java.io.File
  • import java.nio.file.Path
  • java.time.Duration
  • java.time.Period
  • java.time.temporal.TemporalAmount
  • kotlin.text.Regex
  • Collections
    • List
    • Set
    • Map<K, V>
    • Array<T> (You can use Array<Int>, but can't use Array<Array<Int>>)
  • Nullable T?
  • Typesafe Config classes(Calling toConfig is meaningless)
    • com.typesafe.config.Config
    • com.typesafe.config.ConfigValue
    • com.typesafe.config.ConfigMemorySize
  • Enum
  • Data classes

See SelectReader.kt for the exhaustive list.

Snapshots

All snapshot artifacts are available in the Sonatype snapshots repository.

Contribute

Would you like to contribute to Config4k?
Take a look at CONTRIBUTING.md

Comments
  • 1.4.2 release was rolled back

    1.4.2 release was rolled back

    First of all, thanks for making this library. Ran into an issue today.

    I think that the rollback of releases is not a good practice. I'd suggest in the future to release a new version 1.4.3 instead.

    This rollback removed the artifact from bintray and maven central. This will cause builds to break.

    https://github.com/config4k/config4k/commit/d901a4c3d07b4a56eec101b9b907ab1d20495633

    bug 
    opened by mattbroekhuis 6
  • Publish to Maven Central

    Publish to Maven Central

    Hi, @mmorihiro! 👋 Can you publish the artifacts to Maven Central? We use Config4k as a transitive dependency of our library and our customers need manually add JCenter to the list of repositories.

    enhancement 
    opened by ihostage 6
  • Feature request: converting hyphen-case to camelCase

    Feature request: converting hyphen-case to camelCase

    According to docs:

    Config keys are encouraged to be hyphen-separated rather than camelCase.

    So, it would be nice to have this type of conversion as option.

    enhancement 
    opened by ov7a 6
  • Empty sources and javadoc jars

    Empty sources and javadoc jars

    Hello,

    I've just found out, that the javadoc and sources jars in the last release (0.4.2) are empty. Both have only 261B and contain only MANIFEST and nothing else.

    Could this be fixed please? Our documentation contains references to config4k, which are linked to config4k docs on javadoc.io. But since the javadoc jar is empty, javadoc.io has trouble parsing it, as you can see at the linked url.

    bug 
    opened by dolik-rce 5
  • Feature request: treat absent values for dataclasses as default

    Feature request: treat absent values for dataclasses as default

    Suppose we have a config like this:

    some_key {
          importantProperty = some_value
    }
    

    and trying to read data class by some_key:

    data class SomeKeyConfig(
        val importantProperty: String,
        val minorProperty: Int = 500
    )
    
    val config = Config.extract<SomeKeyConfig>("some_key")
    

    Current behavior is IllegalArgumentException. So, one should mark minorProperty as nullable and provide custom getter. It would be nice to avoid that and simply get a data class with default values where needed.

    bug 
    opened by ov7a 5
  • Better version management

    Better version management

    Went to releases page and 0.4.0 release isn't listed there. It would be nice to have some consistency around releases, have them tagged on releases page and perhaps have a list of pull requests merged etc. Right now it seems there is quite a bit of pull request contributions coming in. I would even suggest doing releases via Travis (for minor versions in any case). Once a pull request gets merged it could just do a minor release (0.4.++x). You can then always just do a major release manually when you feel like it, or feel there will be breaking changes. If there is a pull request that you do not want to trigger a release, you can always re-target it to another branch, like develop and merge that manually at a later stage

    opened by martintreurnicht 4
  • ConfigException$BadPath when loading config with empty path.

    ConfigException$BadPath when loading config with empty path.

    I load config like this ConfigFactory.load().extract("") Then it occurred ConfigException$BadPath Maybe I misunderstanding "use quoted "" empty string if you want an empty element"?

    Exception in thread "main" java.lang.ExceptionInInitializerError
    	at io.monchi.pucheen.PucheenKt.main(Pucheen.kt:74)
    Caused by: com.typesafe.config.ConfigException$BadPath: path parameter: Invalid path '': path has a leading, trailing, or two adjacent period '.' (use quoted "" empty string if you want an empty element)
    	at com.typesafe.config.impl.PathParser.parsePathExpression(PathParser.java:170)
    	at com.typesafe.config.impl.PathParser.parsePathExpression(PathParser.java:74)
    	at com.typesafe.config.impl.PathParser.parsePath(PathParser.java:61)
    	at com.typesafe.config.impl.Path.newPath(Path.java:230)
    	at com.typesafe.config.impl.SimpleConfig.hasPathPeek(SimpleConfig.java:83)
    	at com.typesafe.config.impl.SimpleConfig.hasPath(SimpleConfig.java:95)
    	at io.github.config4k.readers.Reader$getValue$1.invoke(Reader.kt:16)
    	at io.github.config4k.readers.Reader$getValue$1.invoke(Reader.kt:13)
    	at io.monchi.pucheen.Pucheen.loadConfig(Pucheen.kt:79)
    	at io.monchi.pucheen.Pucheen.<init>(Pucheen.kt:22)
    	at io.monchi.pucheen.Pucheen.<clinit>(Pucheen.kt:20)
    	... 1 more
    
    opened by yukukotani 4
  • Feature request: In the future think about backward compatibility

    Feature request: In the future think about backward compatibility

    Hi! I understand, that 0.X.Y version is not final and stable. But drop backward compatibility in the bugfix version is very unexpected. 😞

    We use two libraries, both dependent on config4k, but use version 0.4.0 and 0.4.1. And these versions are incompatible. 😢

    TypeReference.kt (0.4.0)

    open class TypeReference<T> {
        fun genericType(): List<ClassContainer> {
           ...
        }
    }
    

    TypeReference.kt (0.4.1)

    open class TypeReference<T> {
        fun genericType(): Map<String, ClassContainer> {
           ...
        }
    }
    
    opened by ihostage 3
  • add support for complex generic arbitrary types

    add support for complex generic arbitrary types

    • reference generics by name and not position
    • add test for generic parameters in constructor with different order as the type parameters
    • add test for generic parameter in a containered type
    opened by EdwarDDay 3
  • Add support for hyphenated paths

    Add support for hyphenated paths

    Right now you cannot extract config where the path is actually hyphenated in the config ex. you have a property nestedObject but in your configuration it is specified as nested-object. This is because the path is specified using reflection from the object property names.

    The easy fix for this is just to try the current property name first and if nothing is found try hyphenated case before returning null.

    opened by martintreurnicht 3
  • Support

    Support "custom types"

    So as I've been using config4k, I've run into a few types that aren't handled natively, and honestly there's not a good way to bake it into the library. It would be nice if it were possible to register custom types in order to extend the functionality available. I've been playing with some approaches and would be happy to implement but I wanted to have a quick discussion around design. Right now I've got something that looks like this working:

    diff --git a/src/main/io.github.config4k/CustomType.kt b/src/main/io.github.config4k/CustomType.kt
    new file mode 100644
    index 0000000..bc43459
    --- /dev/null
    +++ b/src/main/io.github.config4k/CustomType.kt
    @@ -0,0 +1,18 @@
    +package io.github.config4k
    +
    +import com.typesafe.config.Config
    +
    +interface CustomType {
    +    fun testParse(clazz: ClassContainer): Boolean
    +    fun testToConfig(obj: Any): Boolean
    +    fun parse(clazz: ClassContainer, config: Config, name: String): Any
    +    fun toConfig(obj: Any, name: String): Config
    +}
    +
    +private val mutableRegistry: MutableList<CustomType> = mutableListOf()
    +
    +val customTypeRegistry: List<CustomType> = mutableRegistry.toList()
    +
    +fun registerCustomType(customType: CustomType) {
    +    mutableRegistry.add(customType)
    +}
    \ No newline at end of file
    diff --git a/src/main/io.github.config4k/Extension.kt b/src/main/io.github.config4k/Extension.kt
    index 8cca803..ef81ebc 100644
    --- a/src/main/io.github.config4k/Extension.kt
    +++ b/src/main/io.github.config4k/Extension.kt
    @@ -3,6 +3,8 @@ package io.github.config4k
     import com.typesafe.config.Config
     import com.typesafe.config.ConfigException
     import com.typesafe.config.ConfigFactory
    +import com.typesafe.config.ConfigValueFactory
    +import com.typesafe.config.impl.ConfigImpl
     import io.github.config4k.readers.SelectReader
     import java.io.File
     import java.nio.file.Path
    @@ -41,6 +43,11 @@ inline fun <reified T> Config.extract(path: String): T {
      */
     fun Any.toConfig(name: String): Config {
         val clazz = this.javaClass.kotlin
    +    for (customType in customTypeRegistry) {
    +        if (customType.testToConfig(this)) {
    +            return customType.toConfig(this, name)
    +        }
    +    }
         val map = when {
             clazz.javaPrimitiveType != null -> mapOf(name to this)
             this is String -> mapOf(name to this)
    @@ -67,5 +74,6 @@ fun Any.toConfig(name: String): Config {
             clazz.objectInstance != null -> mapOf(name to emptyMap<String, Any>())
             else -> throw Config4kException.UnSupportedType(clazz)
         }
    +
         return ConfigFactory.parseMap(map)
     }
    diff --git a/src/main/io.github.config4k/readers/SelectReader.kt b/src/main/io.github.config4k/readers/SelectReader.kt
    index c2ea8e4..454b78b 100644
    --- a/src/main/io.github.config4k/readers/SelectReader.kt
    +++ b/src/main/io.github.config4k/readers/SelectReader.kt
    @@ -5,6 +5,7 @@ import com.typesafe.config.ConfigMemorySize
     import com.typesafe.config.ConfigValue
     import io.github.config4k.ClassContainer
     import io.github.config4k.Config4kException
    +import io.github.config4k.customTypeRegistry
     import java.io.File
     import java.nio.file.Path
     import java.time.Duration
    @@ -24,33 +25,39 @@ object SelectReader {
          * @param clazz a instance got from the given type by reflection
          * @throws Config4kException.UnSupportedType if the passed type is not supported
          */
    -    fun getReader(clazz: ClassContainer) =
    -            when (clazz.mapperClass) {
    -                Int::class -> IntReader()
    -                String::class -> StringReader()
    -                Boolean::class -> BooleanReader()
    -                Byte::class -> ByteReader()
    -                Double::class -> DoubleReader()
    -                Long::class -> LongReader()
    -                Duration::class -> DurationReader()
    -                Period::class -> PeriodReader()
    -                TemporalAmount::class -> TemporalAmountReader()
    -                ConfigMemorySize::class -> MemorySizeReader()
    -                Config::class -> ConfigReader()
    -                ConfigValue::class -> ConfigValueReader()
    -                List::class -> ListReader(clazz.typeArguments)
    -                Set::class -> SetReader(clazz.typeArguments)
    -                Map::class -> MapReader(clazz.typeArguments)
    -                File::class -> FileReader()
    -                Path::class -> PathReader()
    -                else ->
    -                    when {
    -                        clazz.mapperClass.java.isArray ->
    -                            ArrayReader(clazz.mapperClass.java.componentType.kotlin)
    -                        clazz.mapperClass.java.isEnum -> EnumReader(clazz.mapperClass)
    -                        clazz.mapperClass.primaryConstructor != null -> ArbitraryTypeReader(clazz)
    -                        clazz.mapperClass.objectInstance != null -> ObjectReader(clazz)
    -                        else -> throw Config4kException.UnSupportedType(clazz.mapperClass)
    -                    }
    -            }.getValue
    +    fun getReader(clazz: ClassContainer): (Config, String)->Any? {
    +        for (customType in customTypeRegistry) {
    +            if (customType.testParse(clazz)) {
    +                return Reader({ config, name -> customType.parse(clazz, config, name) }).getValue
    +            }
    +        }
    +        return when (clazz.mapperClass) {
    +            Int::class -> IntReader()
    +            String::class -> StringReader()
    +            Boolean::class -> BooleanReader()
    +            Byte::class -> ByteReader()
    +            Double::class -> DoubleReader()
    +            Long::class -> LongReader()
    +            Duration::class -> DurationReader()
    +            Period::class -> PeriodReader()
    +            TemporalAmount::class -> TemporalAmountReader()
    +            ConfigMemorySize::class -> MemorySizeReader()
    +            Config::class -> ConfigReader()
    +            ConfigValue::class -> ConfigValueReader()
    +            List::class -> ListReader(clazz.typeArguments)
    +            Set::class -> SetReader(clazz.typeArguments)
    +            Map::class -> MapReader(clazz.typeArguments)
    +            File::class -> FileReader()
    +            Path::class -> PathReader()
    +            else ->
    +                when {
    +                    clazz.mapperClass.java.isArray ->
    +                        ArrayReader(clazz.mapperClass.java.componentType.kotlin)
    +                    clazz.mapperClass.java.isEnum -> EnumReader(clazz.mapperClass)
    +                    clazz.mapperClass.primaryConstructor != null -> ArbitraryTypeReader(clazz)
    +                    clazz.mapperClass.objectInstance != null -> ObjectReader(clazz)
    +                    else -> throw Config4kException.UnSupportedType(clazz.mapperClass)
    +                }
    +        }.getValue
    +    }
    

    Thoughts?

    opened by jbunting 3
  • Dependency Dashboard

    Dependency Dashboard

    This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

    This repository currently has no open or pending branches.

    Detected dependencies

    github-actions
    .github/workflows/build-test.yml
    • actions/checkout v3
    • gradle/wrapper-validation-action v1
    • actions/checkout v3
    • actions/setup-java v3
    • codecov/codecov-action v3
    • actions/checkout v3
    • actions/cache v3
    • helaili/jekyll-action v2
    .github/workflows/publish-releases.yml
    • actions/checkout v3
    • gradle/wrapper-validation-action v1
    • actions/checkout v3
    • actions/setup-java v3
    .github/workflows/publish-snapshots.yml
    • actions/checkout v3
    • gradle/wrapper-validation-action v1
    • actions/checkout v3
    • actions/setup-java v3
    • actions/checkout v3
    • actions/cache v3
    • helaili/jekyll-action v2
    .github/workflows/release-drafter.yml
    • release-drafter/release-drafter v5
    gradle
    settings.gradle.kts
    build.gradle.kts
    gradle/libs.versions.toml
    • com.typesafe:config 1.4.2
    • io.kotest:kotest-runner-junit5-jvm 5.5.4
    • org.jetbrains.kotlin.jvm 1.8.0
    • org.jlleitschuh.gradle.ktlint 11.0.0
    • org.jetbrains.dokka 1.7.20
    • io.github.gradle-nexus.publish-plugin 1.1.0
    • fr.brouillard.oss.gradle.jgitver 0.9.1
    • org.jetbrains.kotlinx.binary-compatibility-validator 0.12.1
    gradle-wrapper
    gradle/wrapper/gradle-wrapper.properties
    • gradle 7.6
    html
    docs/_includes/head_custom.html
    • highlight.js 11.7.0
    • highlight.js 11.7.0
    • highlight.js 11.7.0

    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 0
Releases(0.5.0)
  • 0.5.0(Aug 30, 2022)

    :mega: Config4k 0.5.0 released!

    We are pleased to announce the release of Config4k.

    :green_book: What’s Changed

    • Fix broken links on Readme.md (#104) @eduardompinto

    :rocket: Features

    • Added default value at extension Config.extract (#106) @CrazyMoonkin
    • #88 Support java.net.URL (#147) @ihostage
    • #85 Support java.util.UUID (#145) @ihostage
    • #108 Support Mutable* collections (#142) @ihostage
    • #101 Support Java Bean notation (#141) @ihostage

    :bug: Bug Fixes

    • #100 Fix serialization java.time.Duration (#146) @ihostage
    • #103 Fix special characters in Map keys (#144) @ihostage
    • allow private access with getConfigMap (#110) @yoavya

    :toolbox: Maintenance

    • Fix release GitHub action (#148) @ihostage
    • Use Kotlin Explicit API Mode and allWarningsAsErrors = true (#140) @ihostage
    • Enable Kotlin Binary compatibility validator (#138) @ihostage
    • Migrate to JGitVer plugin (#137) @ihostage
    • Update README and CONTRIBUTING for documentation (#136) @ihostage
    • Renovate shouldn't update Ruby dependencies for Jekyll docs (#135) @ihostage
    • Configure baseurl for docs (#131) @ihostage
    • Add documentation (powered by Jekyll) (#130) @ihostage
    • Change commit message for Renovate Bot (#123) @ihostage
    • Configure Renovate (#119) @renovate
    • Migrate to Gradle Version Catalog (#118) @ihostage
    • Bump Gradle to 7.5 (#115) @ihostage
    • Drop Travis CI (#114) @ihostage
    • Migrate publishing to GitHub Actions (#113) @ihostage
    • Change name default branch to main (#112) @ihostage
    • Migrate build to GitHub Actions (#111) @ihostage
    • Update Ktlint Gradle to 9.2.1 (#99) @ihostage
    • Update Gradle to 6.5 (#98) @ihostage
    • Fix codecov reports (#95) @ihostage
    • Use default Gradle source layout (#94) @ihostage
    • Enable ktlint for a code style check (#93) @ihostage
    • Add Release Drafter (#92) @ihostage
    • #81 Publish to Maven Central (#91) @ihostage

    :dart: Dependencies

    • Update org.jlleitschuh.gradle.ktlint to v11 (was 10.3.0) (#143) @renovate
    • Update actions/cache action to v3 (was v2) (#134) @renovate
    • Update io.kotest:kotest-runner-junit5-jvm to v5.4.2 (was 5.4.1) (#129) @renovate
    • Update gradle to v7.5.1 (was 7.5) (#128) @renovate
    • Update io.kotest:kotest-runner-junit5-jvm to v5.4.1 (was 5.4.0) (#127) @renovate
    • Update io.kotest:kotest-runner-junit5-jvm to v5 (was 4.6.4) (#126) @renovate
    • Update org.commonmark:commonmark to v0.19.0 (was 0.17.1) (#124) @renovate
    • Update org.jetbrains.dokka to v1.7.10 (was 1.4.20) (#125) @renovate
    • Update dependency io.kotest:kotest-runner-junit5-jvm to v4.6.4 (#121) @renovate
    • Update dependency com.typesafe:config to v1.4.2 (#120) @renovate
    • Bump ktlint to 0.45.2 and fix gradle warnings (#117) @ihostage
    • Bump Kotlin to 1.7.10 (#116) @ihostage
    • Upgrade kotlin, commonmark, kotest and dokka (#105) @eduardompinto
    • Update Kotlin to 1.3.72 (#97) @ihostage
    • Update Kotlintest (Kotest) to 4.1.0 (#96) @ihostage

    :bow: Credits

    Special thanks to the following contributors who helped with this release: @CrazyMoonkin, @eduardompinto, @ihostage, @mmorihiro, @renovate, @renovate[bot] and @yoavya

    Source code(tar.gz)
    Source code(zip)
  • 0.4.2(Feb 5, 2020)

    ⚠️ From this version, config4k published to Maven Central instead JCenter

    Changes

    #72 Config can be a Property Delegate #84 fix bug with export to map when keys contain dots

    Source code(tar.gz)
    Source code(zip)
  • 0.4.1(Nov 4, 2018)

  • 0.4.0(Oct 29, 2018)

  • 0.3.3(Feb 18, 2018)

    Now, classes can be used as type arguments.

    Related pull requests

    #39 add support for simple generic arbitrary types #41 add support for kotlin objects

    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Feb 25, 2017)

  • 0.2.0(Feb 5, 2017)

Owner
config4k
config4k
Katbox - Kotlin wrapper for catbox.moe and litterbox.catbox.moe

katbox katbox is a Kotlin multiplatform wrapper written with ktor and coroutines

Oliver Berg 2 Oct 5, 2022
Katoot - An easy-to-use (blocking) Kotlin wrapper for Kahoot's REST api

katoot An easy-to-use (blocking) Kotlin wrapper for Kahoot's REST api. Usage Qui

Subham 1 Jul 17, 2022
Asynchronous Spring Initializr API wrapper for Kotlin/JVM

initializr-kt Asynchronous Spring Initializr API wrapper for Kotlin/JVM. This library provides the simplest DSL for initializing Spring Boot projects

Mikhail Titov 2 May 8, 2022
Extensive Redis Pub-Sub wrapper for lettuce written in Kotlin

aware Extensive annotation-based Redis Pub-Sub wrapper for lettuce written in Kotlin. Aware was written to be a replacement for the very dated Banana

Subham 6 Dec 28, 2022
Xoxo is a simple wrapper around org.w3c.dom to parse XML using nice Kotlin APIs

Xoxo ?? Xoxo is a simple wrapper around org.w3c.dom to parse XML using nice Kotlin APIs. No more NodeList, .item(), etc... just use .children, .filter

Martin Bonnin 51 Sep 1, 2022
Simple api wrapper for nekos.life

nekos-kt Simple api wrapper for nekos.life Installation Maven: <repositories> <repository> <id>jitpack.io</id> <url>https://jitpack.io</url>

cattyn 6 Oct 24, 2022
Repo: Programming problems with solutions in Kotlin to help avid Kotlin learners to get a strong hold on Kotlin programming.

Kotlin_practice_problems Repo: Programming problems with solutions in Kotlin to help avid Kotlin learners to get a strong hold on Kotlin programming.

Aman 0 Oct 14, 2021
Mocking for Kotlin/Native and Kotlin Multiplatform using the Kotlin Symbol Processing API (KSP)

Mockative Mocking for Kotlin/Native and Kotlin Multiplatform using the Kotlin Symbol Processing API (KSP). Installation Mockative uses KSP to generate

Mockative 121 Dec 26, 2022
Kotlin-oop - Repositório criado para ser utilizado pelo projeto de Kotlin OOP desenvolvido em Kotlin nas aulas feitas através da plataforma Alura.

Projeto React OOP Repositório criado para ser utilizado pelo projeto de Kotlin OOP desenvolvido em Kotlin nas aulas feitas através da plataforma Alura

Marcos Felipe 1 Jan 5, 2022
Kotlin-koans - Kotlin Koans are a series of exercises to get you familiar with the Kotlin Syntax

kotlin-koans-edu Kotlin Koans are a series of exercises to get you familiar with

null 1 Jan 11, 2022
Kotlin TodoMVC – full-stack Kotlin application demo

Kotlin full stack TodoMVC This project is an example implementation of the TodoMVC app written in Kotlin. More specifically, it's the Kotlin port of t

Gyula Voros 22 Oct 3, 2022
Integration Testing Kotlin Multiplatform Kata for Kotlin Developers. The main goal is to practice integration testing using Ktor and Ktor Client Mock

This kata is a Kotlin multiplatform version of the kata KataTODOApiClientKotlin of Karumi. We are here to practice integration testing using HTTP stub

Jorge Sánchez Fernández 29 Oct 3, 2022
Small kotlin library for persisting _single instances_ of kotlin data classes

PerSista Small library for persisting single instances of kotlin data classes. NB: PerSista uses typeOf() internally which is marked as @ExperimentalS

Eric Donovan 5 Nov 13, 2022
Kotlin Leaning Notes from Udacity Course | Kotlin Bootcamp for Programmers by Google

Kotlin Beginners Notes These are all personal notes taken from the Udacity Course (ud9011) of Kotlin Bootcamp for Programmers by Google as well as oth

Süha Tanrıverdi 34 Dec 10, 2022
Saga pattern implementation in Kotlin build in top of Kotlin's Coroutines.

Module Saga Website can be found here Add in build.gradle.kts repositories { mavenCentral() } dependencies { implementation("io.github.nomisr

Simon Vergauwen 50 Dec 30, 2022
Kotlin microservices with REST, and gRPC using BFF pattern. This repository contains backend services. Everything is dockerized and ready to "Go" actually "Kotlin" :-)

Microservices Kotlin gRPC Deployed in EC2, Check it out! This repo contains microservices written in Kotlin with BFF pattern for performing CRUD opera

Oguzhan 18 Apr 21, 2022
A sample skeleton backend app built using Spring Boot kotlin, Expedia Kotlin Graphql, Reactive Web that can be deployed to Google App Engine Flexible environmennt

spring-kotlin-gql-gae This is a sample skeleton of a backend app that was built using: Spring Boot(Kotlin) Reactive Web Sprinng Data R2DBC with MYSQL

Dario Mungoi 7 Sep 17, 2022
Modular Android architecture which showcase Kotlin, MVVM, Navigation, Hilt, Coroutines, Jetpack compose, Retrofit, Unit test and Kotlin Gradle DSL.

SampleCompose Modular Android architecture which showcase Kotlin, MVVM, Navigation, Hilt, Coroutines, Jetpack compose, Retrofit, Unit test and Kotlin

Mohammadali Rezaei 7 Nov 28, 2022
Learn-kotlin - Learning more about Kotlin in various content

Kotlin study roadmap https://kotlinlang.org/docs/reference/ Getting Started Basi

Danilo Silva 0 Jan 7, 2022