Circe - 在 class when decoding/encoding json 情况下使用默认字段
Circe - Use default fields in case class when decoding/encoding json
假设我有这种情况class:
case class Foo(bar: String, baz: Boolean = false)
用于decoding/encoding API requests/responses using akka-http-json
在类似于this的示例中:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives
import akka.stream.{ ActorMaterializer, Materializer }
import scala.io.StdIn
object ExampleApp {
private final case class Foo(bar: String, baz: Boolean = false)
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
Http().bindAndHandle(route, "127.0.0.1", 8000)
StdIn.readLine("Hit ENTER to exit")
system.terminate()
}
private def route(implicit mat: Materializer) = {
import Directives._
import FailFastCirceSupport._
import io.circe.generic.auto._
pathSingleSlash {
post {
entity(as[Foo]) { foo =>
complete {
foo
}
}
}
}
}
}
只要 json 消息包含 baz
字段,这就可以正常工作。但是,我希望能够发送 json 消息 {bar: "something"}
并让结果使用 Foo
的默认值 baz
。 circe
或 akka-http-json
中是否有任何配置可以使这项工作正常进行?
此外,再次编码为 json 时忽略 baz
字段会很好,但这并不重要。
编辑:
我知道我可以做这样的事情:
implicit val fooEncoder: Encoder[Foo] = new Encoder[Foo] {
final def apply(a: Foo): Json = Json.obj(
("id", Json.fromString(a.bar))
)
}
implicit val fooDecoder: Decoder[Foo] = new Decoder[Decoder] {
final def apply(c: HCursor): Decoder.Result[Decoder] =
for {
bar <- c.downField("bar").as[String]
} yield {
Foo(bar)
}
}
但希望有一个更易于维护的解决方案,解决不需要 json 消息中的默认字段的一般情况。
您可以使用 circe-generic-extras 包来完成此操作。这是一个单独的依赖项,您必须将其放入构建中。对于 sbt,那是:
libraryDependencies += "io.circe" %% "circe-generic-extras" % "0.8.0"
然后,在你的路由函数中,替换
import io.circe.generic.extras.Configuration
import io.circe.generic.auto._
与:
import io.circe.generic.extras.auto._
implicit val customConfig: Configuration = Configuration.default.withDefaults
此生成的编码器将始终包含默认字段。
有关更多信息,请参阅 circe 发行说明:https://github.com/circe/circe/releases/tag/v0.6.0-RC1
假设我有这种情况class:
case class Foo(bar: String, baz: Boolean = false)
用于decoding/encoding API requests/responses using akka-http-json
在类似于this的示例中:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives
import akka.stream.{ ActorMaterializer, Materializer }
import scala.io.StdIn
object ExampleApp {
private final case class Foo(bar: String, baz: Boolean = false)
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
Http().bindAndHandle(route, "127.0.0.1", 8000)
StdIn.readLine("Hit ENTER to exit")
system.terminate()
}
private def route(implicit mat: Materializer) = {
import Directives._
import FailFastCirceSupport._
import io.circe.generic.auto._
pathSingleSlash {
post {
entity(as[Foo]) { foo =>
complete {
foo
}
}
}
}
}
}
只要 json 消息包含 baz
字段,这就可以正常工作。但是,我希望能够发送 json 消息 {bar: "something"}
并让结果使用 Foo
的默认值 baz
。 circe
或 akka-http-json
中是否有任何配置可以使这项工作正常进行?
此外,再次编码为 json 时忽略 baz
字段会很好,但这并不重要。
编辑:
我知道我可以做这样的事情:
implicit val fooEncoder: Encoder[Foo] = new Encoder[Foo] {
final def apply(a: Foo): Json = Json.obj(
("id", Json.fromString(a.bar))
)
}
implicit val fooDecoder: Decoder[Foo] = new Decoder[Decoder] {
final def apply(c: HCursor): Decoder.Result[Decoder] =
for {
bar <- c.downField("bar").as[String]
} yield {
Foo(bar)
}
}
但希望有一个更易于维护的解决方案,解决不需要 json 消息中的默认字段的一般情况。
您可以使用 circe-generic-extras 包来完成此操作。这是一个单独的依赖项,您必须将其放入构建中。对于 sbt,那是:
libraryDependencies += "io.circe" %% "circe-generic-extras" % "0.8.0"
然后,在你的路由函数中,替换
import io.circe.generic.extras.Configuration
import io.circe.generic.auto._
与:
import io.circe.generic.extras.auto._
implicit val customConfig: Configuration = Configuration.default.withDefaults
此生成的编码器将始终包含默认字段。
有关更多信息,请参阅 circe 发行说明:https://github.com/circe/circe/releases/tag/v0.6.0-RC1