Fully Native and Multiplatform Kotlin serialization library for serialization/deserialization of toml format.
Uses native kotlinx.serialization, provided by Kotlin. This library contains no Java code and no Java dependencies.
We believe that TOML is actually the most readable and user-friendly configuration file format.
So we decided to support this format for the kotlinx
serialization library.
As this young and big project is needed by the Kotlin community, we need your help.
We will be glad if you will test ktoml
or contribute to this project.
In case you don't have much time for this - at least spend 5 seconds to give us a star to attract other contributors!
Thanks! 🙏
All the code is written in Kotlin common module. This means that it can be built for each and every Kotlin native platform. However, to reduce the scope, ktoml now supports only the following platforms:
- jvm
- mingwx64
- linuxx64
- macosx64
Other platforms could be added later on the demand or easily built by users on their machines.
❗ Please note, that TOML standard does not define Java-like types: Char
, Short
, etc.
You can check types that are supported in TOML here.
We will support all Kotlin primitive types in the future with the non-strict configuration of ktoml, but now
only String, Long, Double and Boolean are supported from the list of Kotlin primitives.
General
We are still developing and testing this library, so it has several limitations:
✅ deserialization (with some parsing limitations)
❌ serialization (not implemented yet, less important for TOML config-files)
Parsing
✅ Table sections (single and dotted)
✅ Key-value pairs (single and dotted)
✅ Integer type
✅ Float type
✅ String type
✅ Float type
✅ Boolean type
✅ Simple Arrays
✅ Comments
❌ Arrays: nested; multiline; of Different Types
❌ Literal Strings
❌ Multiline Strings
❌ Inline Tables
❌ Array of Tables
❌ Offset Date-Time, Local: Date-Time; Date; Time
The library is hosted on the Maven Central.
To import ktoml
library you need to add following dependencies to your code:
Maven
<dependency>
<groupId>com.akuleshov7</groupId>
<artifactId>ktoml-core</artifactId>
<version>0.2.7</version>
</dependency>
<dependency>
<groupId>com.akuleshov7</groupId>
<artifactId>ktoml-file</artifactId>
<version>0.2.7</version>
</dependency>
Gradle Groovy
implementation 'com.akuleshov7:ktoml-core:0.2.7'
implementation 'com.akuleshov7:ktoml-file:0.2.7'
Gradle Kotlin
implementation("com.akuleshov7:ktoml-core:0.2.7")
implementation("com.akuleshov7:ktoml-file:0.2.7")
❗ as TOML is a foremost language for config files, we have also supported the deserialization from file. However, we are using okio to read the file, so it will be added as a dependency to your project if you will import ktoml-file. For basic scenarios of decoding strings you can simple use ktoml-core.
Deserialization:
Straight-forward deserialization
// include extensions from 'kotlinx' lib to improve user experience
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.serializer
// including com.akuleshov7:ktoml-core
import com.akuleshov7.ktoml.deserialize
@Serializable
data class MyClass(/* your fields */)
// to deserialize toml input in a string format (separated by newlines '\n')
// no need to provide serializer() explicitly if you will use extension method from
// <kotlinx.serialization.decodeFromString>
val resultFromString = Toml.decodeFromString<MyClass>(/* string with a toml input */)
val resultFromList = Toml.decodeFromString<MyClass>(serializer(), /* list with lines of strings with a toml input */)
Partial deserialization
Partial Deserialization can be useful when you would like to deserialize only one single table and you do not want to reproduce whole object structure in your code.
// If you need to deserialize only some part of the toml - provide the full name of the toml table.
// The deserializer will work only with this table and it's children.
// For example if you have the following toml, but you want only to decode [c.d.e.f] table:
// [a]
// b = 1
// [c.d.e.f]
// d = "5"
val result = Toml.partiallyDecodeFromString<MyClassOnlyForTable>(serializer(), /* string with a toml input */, "c.d.e.f")
val result = Toml.partiallyDecodeFromString<MyClassOnlyForTable>(serializer(), /* list with toml strings */, "c.d.e.f")
Toml File deserialization
// including com.akuleshov7:ktoml-file
import com.akuleshov7.ktoml.deserialize
val resultFromString = TomlFileReader.decodeFromFile<MyClass>(serializer(), /* file path to toml file */)
val resultFromList = TomlFileReader.partiallyDecodeFromFile<MyClass>(serializer(), /* file path to toml file */, /* table name */)
Parser to AST:
Simple parser
import com.akuleshov7.ktoml.parsers.TomlParser
import com.akuleshov7.ktoml.KtomlConf
/* ========= */
var tomlAST = TomlParser(KtomlConf()).parseStringsToTomlTree(/* list with toml strings */)
tomlAST = TomlParser(KtomlConf()).parseString(/* the string that you want to parse */)
tomlAST.prettyPrint()
Ktoml parsing and deserialization was made configurable to fit all the requirements from users. We have created a special configuration class that can be passed to the decoder method:
Toml(
ktomlConf = KtomlConf(
// allow/prohibit unknown names during the deserialization, default false
ignoreUnknownNames = false,
// allow/prohibit empty values like "a = # comment", default true
emptyValuesAllowed = true
)
).decodeFromString<MyClass>(
tomlString
)
This tool natively deserializes toml expressions using native Kotlin compiler plug-in and kotlinx.serialization.
The following example:
someBooleanProperty = true
[table1]
property1 = 5
property2 = 6
[table2]
someNumber = 5
[table2."akuleshov7.com"]
name = "my name"
configurationList = ["a", "b", "c"]
# such redeclaration of table2
# is prohibited in toml specification;
# but ktoml is allowing it in non-strict mode:
[table2]
otherNumber = 5.56
can be deserialized to MyClass
:
@Serializable
data class MyClass(
val someBooleanProperty: Boolean,
val table1: Table1,
val table2: Table2
)
@Serializable
data class Table1(val property1: Int, val property2: Int)
@Serializable
data class Table2(
val someNumber: Int,
@SerialName("akuleshov7.com")
val inlineTable: InlineTable,
val otherNumber: Double
)
@Serializable
data class InlineTable(
val name: String,
@SerialName("configurationList")
val overriddenName: List<String>
)
with the following code:
Toml.decodeFromString<MyClass>(/* toml string */)
Translation of the example above to json-terminology:
{
"someBooleanProperty": true,
"table1": {
"property1": 5,
"property2": 5
},
"table2": {
"someNumber": 5,
"akuleshov7.com": {
"name": "my name",
"configurationList": ["a", "b", "c"],
"otherNumber": 5.56
}
}
}
You can check how this example works in ReadMeExampleTest.