17

GitHub - valderman/4koma: A TOML 1.0 parser library for Kotlin

 3 years ago
source link: https://github.com/valderman/4koma
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

4koma

A small, stand-alone, easy to use TOML parser library for Kotlin.

4koma supports an array of convenient features, such as full TOML 1.0 compliance, type-safe decoding of configurations into arbitrary data classes using Kotlin generics, serialization support, and easy access to individual properties for when you don't need the entire document.

4koma follows the UNIX philosophy, in that it tries to do one thing, and do it well. If what you need is no-nonsense TOML processing for your Kotlin project, 4koma might be just what you need. If you need support for multiple configuration formats, or are using a JVM language other than Kotlin, some of the projects listed in the Alternatives section might serve you better.

Usage

Getting started with 4koma is super easy.

1. Add a dependency on 4koma

For build.gradle.kts:

repositories {
    maven {
        url = uri("https://jitpack.io")
    }
}

dependencies {
    implementation("cc.ekblad:4koma:1.0.1")
}

2. Obtain a TOML file

[settings]
maxLoginRetries = 3

[[user]]
name = "Alice"
password = "password123"

[[user]]
name = "Bob"
password = "correct horse battery staple"

3. Write some code

A minimal example

import cc.ekblad.toml.decode
import cc.ekblad.toml.tomlMapper
import java.nio.file.Path

data class Config(
    val settings: Settings,
    val user: List<User>
) {
    data class User(val name: String, val password: String)
    data class Settings(val maxLoginRetries: Int)
}

fun main() {
    // Create a TOML mapper without any custom configuration
    val mapper = tomlMapper { }

    // Read our config from file
    val tomlFile = Path.of("test.toml")
    val config = mapper.decode<Config>(tomlFile)
    println(config)
}

Default values

import cc.ekblad.toml.decodeWithDefaults
import cc.ekblad.toml.tomlMapper
import java.nio.file.Path

// We extend our config with extra fields (e.g. isAdmin, realmName and useTLS)
// which are not configured in our example TOML document.
data class Config(
    val settings: Settings,
    val user: List<User>
) {
    data class User(val name: String, val password: String, val isAdmin: Boolean)
    data class Settings(val maxLoginRetries: Int, val realmName: String, val useTLS: Boolean)
}

// Then, we define a default configuration, from which we will fill in any missing values when we read the config.
val defaultConfig = Config(
    settings = Config.Settings(
        maxLoginRetries = 5,
        realmName = "Example Realm",
        useTLS = true
    ),
    user = emptyList()
)

// We also define a default value for our user type, as we extended it with an extra field.
val defaultUser = Config.User(
    name = "default name",
    password = "default password",
    isAdmin = false
)

fun main() {
    // Create a TOML mapper with default fields configured for our Config.User type.
    val mapper = tomlMapper {
        default(defaultUser)
    }

    // Read our config from file, replacing any missing values with the defaults from defaultConfig and defaultUser.
    val tomlFile = Path.of("test.toml")
    val config = mapper.decodeWithDefaults<Config>(defaultConfig, tomlFile)
    println(config)
}

Mapping between TOML and Kotlin field names

import cc.ekblad.toml.decode
import cc.ekblad.toml.tomlMapper
import java.nio.file.Path

data class Config(
    val settings: Settings,
    val users: List<User>
) {
    data class User(val userName: String, val password: String)
    data class Settings(val retriesAfterWhichToDisableLogin: Int)
}

fun main() {
    // Set up a mapper which maps "user", "name", etc. fields found in the TOML file onto fields "users", "userName",
    // etc. in their respective Kotlin data types
    val mapper = tomlMapper {
        mapping<Config>("user" to "users")
        mapping<Config.User>(
            "name" to "userName",
            "password" to "userSecret"
        )
        mapping<Config.Settings>(
            "maxLoginRetries" to "retriesAfterWhichToDisableLogin"
        )
    }

    // Read our config from file, using our custom field name mappings
    val tomlFile = Path.of("test.toml")
    val config = mapper.decode<Config>(tomlFile)
    println(config)
}

Custom decoders

import cc.ekblad.toml.decode
import cc.ekblad.toml.model.TomlValue
import cc.ekblad.toml.tomlMapper
import java.nio.file.Path

fun main() {
    // Set up a mapper which replaces any string appearing in the list of bad words with a number of asterisks
    val listOfBadWords = listOf("poop", "darn", "blockchain")
    val mapper = tomlMapper {
        decoder { it: TomlValue.String ->
            if (it.value in listOfBadWords) {
                // We don't allow any swearing in our strings!
                it.value.map { '*' }.joinToString("")
            } else {
                it.value
            }
        }
    }

    // Read an arbitrary TOML document from file, using our custom string decoder
    val tomlFile = Path.of("test.toml")
    val config = mapper.decode<Map<String, Any>>(tomlFile)
    println(config)
}

For more detailed information, see the API documentation.

Alternatives

Why should you use 4koma? Maybe you shouldn't! When it comes to TOML libraries there are several to choose from. This table compares 4koma with a number of alternatives that (a) can parse TOML, (b) can be reasonably easily used in a Kotlin/JVM project, and (c) have seen at least one new commit in the last four years.

If you'd like your library to be on this list, or it's already there and you believe it's being misrepresented, please open a pull request to rectify the situation.

Feature 4koma KToml konf konfy toml4j tomlj jtoml Night Config Jackson

TOML 1.0 compliant white_check_mark x white_check_mark x x x x white_check_mark white_check_mark

TOML 0.4 compliant white_check_mark x white_check_mark x white_check_mark white_check_mark x white_check_mark white_check_mark

Inline tables white_check_mark white_check_mark white_check_mark x white_check_mark white_check_mark x white_check_mark white_check_mark

Table arrays white_check_mark x white_check_mark x x white_check_mark x white_check_mark white_check_mark

Date/time literals white_check_mark x white_check_mark x x white_check_mark white_check_mark white_check_mark white_check_mark

Easy property access¹ white_check_mark x white_check_mark x white_check_mark white_check_mark white_check_mark white_check_mark white_check_mark

Decodes to Kotlin types white_check_mark white_check_mark white_check_mark white_check_mark white_check_mark x white_check_mark white_check_mark white_check_mark

...without extra boilerplate² white_check_mark x x x white_check_mark x white_check_mark white_check_mark white_check_mark

...without modification to type white_check_mark x x x white_check_mark x white_check_mark white_check_mark white_check_mark

Type-safe generic decoding³ white_check_mark grey_question white_check_mark white_check_mark x x x x x

Kotlin multiplatform x white_check_mark x x x x x x x

Serialization white_check_mark x white_check_mark x white_check_mark x white_check_mark white_check_mark white_check_mark

Online API docs white_check_mark x x x x white_check_mark x white_check_mark white_check_mark

Small and lean⁴ white_check_mark white_check_mark x x white_check_mark white_check_mark white_check_mark x x

Everything but the kitchen sink⁵ x x white_check_mark white_check_mark x x x white_check_mark white_check_mark

(¹) Individual properties can be accessed by means of parsedConfig.get("foo.bar") or similar, without requiring the entire document to be decoded into some model type.

(²) The library does not require annotations or other modifications to existing code in order to support decoding to complex model types.

(³) The library does not rely on type-erased JVM generics for decoding to complex model types.

(⁴) The library focuses on reading/writing/processing TOML and does not contain any "unnecessary" features unrelated to that scope.

(⁵) The library aims to provide a comprehensive configuration platform, with support for multiple configuration file formats and all sorts of associated bells and whistles.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK