In the latest
branch of openrndr-template
we have switched from gson
to kotlinx-serialization
.
What both of these libraries do is making it easy to save and load program state. Gson comes from Google and kotlinx-serialization from the developers of Kotlin.
The syntax when using the second one is a bit less verbose.
Here the official introduction:
If you want to add kotlinx-serialization it to your openrndr-template based program, take a look at the required changes in this commit:
I’m copying here the notes from that commit:
Save JSON (before)
val gson = Gson()
val json = gson.toJson(points)
File(path).writeText(json)
Save JSON (new syntax)
val json = Json.encodeToString(points)
File(path).writeText(json)
if points
is a List
of Point
, and Point
is @Serializable
Load JSON (before)
val gson = Gson()
val typeToken = object : TypeToken<List<Point>>() {}
val json = File(path).readText()
val points: List<Point> = gson.fromJson(json, typeToken.type)
Load JSON (new syntax)
val json = File(path).readText()
val poinsts = Json.decodeFromString<List<Point>>(json)
Use these imports with the new syntax
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
OPENRNDR classes are already annotated as @Serializable so that’s taken care of. If you want to serialize your own classes, you need to annotate them. For example:
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
...
@Serializable
data class Point(
var position: Vector2,
var radius: Double,
var completeness: Double = 1.0,
var rotation: Double = 0.0
) {
@Transient
var contour: ShapeContour? = null
init {
...
}
....
You can mark as @Transient
members that do not need serialized. In this example, contour
is generated out of position
, radius
, completeness
and rotation
, so there’s no need to save the contour
to the JSON file, which would make it heavier and less readable. I simply reconstruct that contour inside init
, or any time one of the four properties of Point are changed. The init
method is called when you deserialize (load a JSON file to construct object instances).
With these annotations, one could easily load and save a list of Point
with functions like these:
fun saveJson(points: MutableList<Point>) {
File(pointsPath).writeText(Json.encodeToString(points))
println("saved")
}
fun loadJson(): MutableList<Point> {
return if(File(pointsPath).exists()) {
val json = File(pointsPath).readText()
println("loaded")
Json.decodeFromString<MutableList<Point>>(json)
} else mutableListOf()
}