kotlin-hocon-mapper
Overview
A lightweight Typesafe Config (HOCON) mapper for Kotlin classes based on kotlinx.serialization.
- Provides serializers and deserializers based on
kotlinx.serialization
- Deserializers convert
com.typesafe.config.Config
into a class annotated with@Serializable
- Serializers convert a serializable object into a JSON (Beta: intended to support writing HOCON config during development)
- No reflection at runtime. Those serializers and deserializers are generated at compile time.
- Deserializers convert
- Supports basic types such as
String
,Boolean
,Int
,Long
,Float
,Double
,Enum
,List
,Map
and nested object - Supports additional types for unit conversion such as
Period
,Duration
andConfigMemorySize
Core Dependencies
-
version 1.4.10:
- kotlin: 1.4.10
- kotlinx.serialization: 1.0.0-RC
- typesafe.config: 1.4.0
-
version 0.9.0:
- kotlin: 1.3.72
- kotlinx.serialization: 0.20.0
- typesafe.config: 1.4.0
-
version 0.1.0:
- kotlin: 1.3.50
- kotlinx.serialization: 0.13.0
- typesafe.config: 1.3.4
Getting Started
-
Gradle
implementation "com.github.uharaqo.kotlin-hocon-mapper:kotlin-hocon-mapper:$hocon_mapper_version"
-
Maven
<dependency> <groupId>com.github.uharaqo.kotlin-hocon-mapper</groupId> <artifactId>kotlin-hocon-mapper</artifactId> <version>${hocon.mapper.version}</version> </dependency>
-
Setup the kotlinx.serializer compiler plugin
-
To convert a
Config
object into a data object,@Serializable data class BasicTypes( val char: Char, val string: String, val bool: Boolean, val byte: Byte, val int: Int, val long: Long, val short: Short, val float: Float, val double: Double, val enum: BasicModels.SampleEnum, val nullable: String?, val list: List<Int>, val map: Map<String, Int>, val nested: Nested ) @Serializable data class Nested(val value: String) // Config and ConfigFactory are found in com.typesafe.config package val config: Config = ConfigFactory.parseString( """{ | char: a, | string: abc, | bool: true, | byte: 1, | int: ${Int.MAX_VALUE}, | long: ${Long.MAX_VALUE}, | short: ${Short.MAX_VALUE}, | float: ${Float.MAX_VALUE}, | double: ${Double.MAX_VALUE}, | enum: ${BasicModels.SampleEnum.ELEMENT} | nullable: null, | list: [1, 2, 3] | map: { first: 1, second: 2} | nested: { value: nested } | unknown: "this value is ignored becuase 'unknown' is not defined in the data object" |} """.trimMargin() ) val obj = BasicTypes.serializer().load(config)
-
To convert additional types for unit conversion,
// file targeted annotation to enable these deserializers @file:UseSerializers( DurationSerializer::class, PeriodSerializer::class, ConfigMemorySizeSerializer::class ) @Serializable data class UnitConversion( val duration: Duration, // -> Duration.ofMinutes(10) val period: Period, // -> Period.ofWeeks(1) val memSize: ConfigMemorySize, // -> ConfigMemorySize.ofBytes(1024) // this is another option to enable an additional serializer for a field @Serializable(with = StringBooleanSerializer::class) val textBoolean: Boolean // -> true ) val config: com.typesafe.config.Config = ConfigFactory.parseString( """{ | duration: 10m | period: 1w | memSize: 1KiB | textBoolean: yes |} """.trimMargin() ) val converted = UnitConversion.serializer().load(conf)
More examples can be found in test code
-
To serialize an object into a JSON String (Beta)
val json: String = BasicTypes.serializer().stringify(data) // or ConfigSerializer.stringify(BasicTypes.serializer(), data)
Deserialization details
All the arguments in a constructor should be provided by a Config
object
- When a key is not found in the
Config
,MissingFieldException
will be thrown null
can be injected into a nullable argument, but it should be explicitly defined like{"path.to.prop": null}
)- Default values in a constructor are ignored
- How to handle defaults explains why we should not define configs in various places
Example usage
Production code
- Create a data class with the
@Serializable
annotation - Load config files by using the Typesafe Config
- Load the
Config
object into the data class by using the deserializer
Setup the config by temporary code
- Instantiate the class with default values
- Generate a JSON with the object by using the serializer
- Put the JSON into a config source such as application.conf
Links
-
- Human-Optimized Config Object Notation
- JSON-like intuitive configuration syntax
- Supports lots of useful features
- Adopted by popular libraries such as Ktor
-
- A library for managing HOCON files
- merge configs from multiple source such as files, system properties, environment variables
-
- A compiler plugin which generates code to serialize objects without reflection.
- A runtime library which provides APIs for Encoder and Decoder
-
- Kotlin extension functions for Typesafe Config
- Object mapper:
config.extract<MyData>("path.to.mydata")
- Serializer:
MyData("foo", 42).toConfig("path.to.mydata")
- Unfortunately, this project has been inactive since Jan 2019 (as of Sep 2019). It didn't work with the latest kotlin reflection library.