Automatic Encoding/Decoding
The @json
annotation will provide the decoder and encoder for that data class,
so we are able to read from and write to Json.
@json
data class Person(val name: String, val age: Int) {
companion object // <- This is needed
}
You will be able to encode and decode using the following:
import arrow.core.*
import helios.*
import helios.core.*
import helios.typeclasses.*
//sampleStart
val personJson = with(Person.encoder()) { Person("Abc", 10).encode() }
Person.decoder().decode(personJson)
//sampleEnd
Enum Encoding/Decoding
The @json
annotation does not support Enum
types, so a custom Encoder
and Decoder
must be used.
For example, given the following Enum
:
enum class Foo {
A
}
You will be able to encode and decode using the following:
import arrow.core.*
import helios.*
import helios.instances.*
val fooJson = Enum.encoder<Foo>().run {
Foo.A.encode()
}
Enum.decoder<Foo>().decode(fooJson)
Building a Json
You can build your own Json
object like this:
val jObject = JsObject(
"name" to JsString("Elia"),
"age" to JsNumber(23)
)
jObject.spaces2()
Custom Encoders
To create a custom Encoder
, you need to inherit from the Encoder
interface and implement the encode
method.
val personCustomEncoder = object : Encoder<Person> {
override fun Person.encode(): Json =
JsObject(
"first_name" to JsString("John"),
"age" to JsNumber(28)
)
}
val personCustomJson = with(personCustomEncoder) { Person("Abc", 10).encode() }
personCustomJson.spaces2()
Custom Decoders
You can follow the same approach to create a custom Decoder
:
import arrow.core.extensions.either.applicative.applicative
import helios.instances.decoder
val personCustomDecoder = object : Decoder<Person> {
override fun decode(value: Json): Either<DecodingError, Person> =
Either.applicative<DecodingError>().map(
value["first_name"].fold({ Either.Left(KeyNotFound("first_name")) }, { it.decode(String.decoder()) }),
value["age"].fold({ Either.Left(KeyNotFound("age")) }, { it.decode(Int.decoder()) })
) { tuple ->
Person(tuple.a, tuple.b)
}.fix()
}
personCustomDecoder.decode(personCustomJson)
Navigation through Json
You can navigate Json
using the Json.path
DSL to select keys or traverse collections.
import helios.optics.*
Json.path.select("name").string.modify(jObject, String::toUpperCase).spaces2()
Note that the code generation will give you an accessor for each json field.
Json.path.name.string.modify(jObject, String::toUpperCase).spaces2()