This is a Json codec implementation for E
and EOr
types based on circe. It provides circe's Decoder
s and Encoder
s as well as e's own Codec
(see e-scala docs).
If you use SBT, add following to your build.sbt
:
libraryDependencies += "dev.akif" %% "e-circe" % "@VERSION@"
If you use Maven, add following to your pom.xml
:
<dependencies>
<dependency>
<groupId>dev.akif</groupId>
<artifactId>e-circe_3</artifactId>
<version>@VERSION@</version>
</dependency>
</dependencies>
If you use Gradle, add following to your project's build.gradle
:
dependencies
{
implementation('dev.akif:e-circe_3:@VERSION@')
}
Below are some details and examples of e-circe's content. For more, please check corresponding automated tests and e-circe's documentation.
To get started, add following import which will cover all your needs:
import e.circe.{*, given}
e-circe provides implicit definitions so that regular circe decoding can be done. However, it also provides e's own Codec. Using this is convenient as it reports decoding failures as E errors.
import e.circe.{*, given}
import io.circe.{Decoder => CirceDecoder, Encoder => CirceEncoder, Json}
import io.circe.syntax.*
decode[String](123.asJson)
decode[String]("test".asJson)
case class Foo(bar: Boolean)
given fooDecoder: CirceDecoder[Foo] = CirceDecoder.forProduct1("bar")(Foo.apply)
given fooEncoder: CirceEncoder[Foo] = CirceEncoder.forProduct1("bar")(_.bar)
decode[Foo](Json.obj())
decode[Foo](Foo(false).asJson)
Decoding a Json as E yields EOr[E]
whose error is the decoding failure. If the decoding succeeds, the provided value is the decoded E.
import e.circe.{*, given}
import e.scala.E
import io.circe.Json
import io.circe.syntax.*
// Decodes as `E.empty`
decode[E](Json.obj())
// Decoding failure, also an E
decode[E](Json.arr())
val decoder = makeDecoder[E]
decoder.decode(Json.obj("code" := 1, "name" := "test"))
e-circe provides implicit definitions so that regular circe encoding can be done. It also provides e's own Codec and encoding can be done with it too.
import e.circe.{*, given}
import e.scala.E
encode(E.empty)
encode(E.name("test").message("Test").cause(E.code(1)))
val encoder = makeEncoder[E]
encoder.encode(E.code(2))
import e.circe.{*, given}
import e.scala.*
encode[EOr[String]](E.name("test").toEOr[String])
encode[EOr[Int]](123.toEOr)
val encoder = makeEncoder[EOr[String]]
encoder.encode(E.name("test").toEOr[String])
encoder.encode("123".toEOr)
Since e's Codec is a combination of decoding and encoding, you can use makeCodec
instead of separately using makeDecoder
and makeEncoder
if you have both capabilities for a type.
import e.circe.{*, given}
import e.scala.*
import io.circe.{Decoder => CirceDecoder, Encoder => CirceEncoder, Json}
import io.circe.syntax.*
case class User(name: String, age: Int)
object User:
given userDecoder: CirceDecoder[User] = CirceDecoder.forProduct2("n", "a")(User.apply)
given userEncoder: CirceEncoder[User] = CirceEncoder.forProduct2("n", "a")(u => (u.name, u.age))
val codec = makeCodec[User]
codec.decode(Json.obj("foo" := "bar"))
codec.decode(Json.obj("n" := "Akif", "a" := 29))
codec.encode(User("Akif", 29))