Circe - 在解析/编码json时使用case class中的默认字段

13

假设我有这个case类:

case class Foo(bar: String, baz: Boolean = false)

该类用于解码/编码API请求/响应,使用akka-http-json

类似此示例

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"},让结果使用Foobaz默认值。在circeakka-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消息中不需要默认字段的一般情况。


使用 Option[Boolean] 是否是一个有效的解决方法?当不需要时将其设置为 None - Yuval Itzchakov
@YuvalItzchakov 这是一个好建议,但在这种情况下,我们还使用quill的case class。由于默认字段应该在我们的数据库中为NOT NULL,因此最好将其保留为case class中的非选项。 - simen-andresen
@simen-andresen 你应该考虑接受以下的解决方案。 - Lukasz
1个回答

21

你可以使用circe-generic-extras软件包来实现这一点。这是一个单独的依赖项,您需要将其放入构建中。对于sbt来说,它是:

您可以使用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


这对我没有起作用。配置类不在extras.auto中,只在extras中。而且我只能使用0.14.3版本,而不能使用0.14.5版本,因为它与scala 2.13不兼容。 - Cheruvim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接