Skip to content

Kotlin Examples

Falkreon edited this page Jan 17, 2019 · 2 revisions

Access to the snapshot

build.gradle.kts

repositories {
    mavenCentral()
}

dependencies {
    implementation(group = "blue.endless", name = "jankson", version = Versions.jankson)
}

Versions.kt

// this file goes in buildSrc/src/main/kotlin
object Versions {
  const val kotlin = "1.3.11"
  
  const val jankson = "1.1.0"
  
  // other versions here
}

Getting started

JanksonSample.kt

import blue.endless.jankson.Comment
import blue.endless.jankson.Jankson
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

val configDirectory = File("run")
    .resolve("config")
    .apply {
        mkdirs()
    }

inline fun <reified T> loadConfig(): T {
    val jankson = Jankson.builder()
        //.registerTypeAdapter(...) //You can register adapters here to customize deserialization
        //.registerSerializer(...)  //Likewise, you can customize serializer behavior
        .build()                   //In most cases, the default Jankson is all you need.

    //Any file, String, or InputStream will do. This is just a Fabric example.
    val configFile = configDirectory.resolve("mymod.json")

    val configJson = jankson.load(configFile) //Takes the file and turns it into an object tree

    //Takes a String or an object tree and deserializes it into a plain-java-object
    val configObject = jankson.fromJson(configJson, T::class.java)

    return configObject
}

/* Saving is more of the same. We just bake the config down to a String and write it out. */
inline fun <reified T> saveConfig(config: T = (T::class.java::newInstance)()) {
    val configFile = configDirectory.resolve("mymod.json")
    val jankson = Jankson.builder().build()
    val result = jankson
        .toJson(config) //The first call makes a JsonObject
        .toJson(true, true, 0)     //The second turns the JsonObject into a String -
    //in this case, preserving comments and inserting newlines
    try {
        if (!configFile.exists()) configFile.createNewFile()
        val out = FileOutputStream(configFile, false)

        out.write(result.toByteArray())
        out.flush()
        out.close()
    } catch (ex: IOException) {
        ex.printStackTrace()
    }
}

/* The main thing you need to have, to benefit from auto-deserialization, is a no-arg constructor.
 * in this case, all fields have default values so a no-arg constructor overload is generated
 */

data class ConfigObject(
    /* Comment annotations populate serialized keys with json5 comments */
    @Comment("why orbs?")
    var maxOrbs: Int = 10,

    /* Collection and map types are properly captured in both directions. Beware of nested collections!
     * We're still working on making List<List<String>> deserialize properly. If you need nested generics
     * like this, skip ahead to the Jankson+GSON setup!
     */
    private val someStrings: List<String> = listOf("abc", "cde"),

    /* While it's always best to have the object initialized in the constructor or initializer, as long
     * as a full, concrete type is declared, Jankson can create the instance and fill it in.
     */
    protected var uninitializedMap: Map<String, String>? = null,
    protected var initializedMap: Map<String, String> = mapOf("a" to "b", "c" to "d"),

    // at runtime this will be java.lang.Integer[]
    val integerArray: Array<Int> = arrayOf(1, 2, 4),

    // at runtime this will be int[]
    val intArray: IntArray = arrayOf(1, 2, 3).toIntArray(),

    val nested: NestedConfig = NestedConfig()
) {
    /*
    nested configurations with inner classes are also possible
     */
    data class NestedConfig(
        val nestedData: Set<Short> = setOf(1, 2, 3)
    )
}

fun main() {
    saveConfig<ConfigObject>()
    val config = loadConfig<ConfigObject>()
    println("config object >>> $config")
}
Clone this wiki locally