在 http4s 上 运行 时使用 Circe 将递归数据结构编码为 Json
Encoding recursive data structure into Json with Circe when running on http4s
我正在构建一个非常简单的服务,它应该 return 一个通过递归案例定义的树状结构 class:
case class Node(id: Int, name: String, children: Seq[Node] = Seq())
但由于某种原因,我不断收到以下编译错误:
Error:(24, 70) could not find implicit value for parameter encoder:
io.circe.Encoder[Seq[com.ansarada.ds.docviewer.server.Main.Node]]
implicit val nodesEncoder: EntityEncoder[Seq[Node]] =
jsonEncoderOf[Seq[Node]]
Error:(24, 70) not enough arguments for
method jsonEncoderOf: (implicit encoder:
io.circe.Encoder[Seq[com.ansarada.ds.docviewer.server.Main.Node]])org.http4s.EntityEncoder[Seq[com.ansarada.ds.docviewer.server.Main.Node]].
Unspecified value parameter encoder. implicit val nodesEncoder:
EntityEncoder[Seq[Node]] = jsonEncoderOf[Seq[Node]]
一旦我删除了一个子元素定义并将一个节点变成一个平面对象,代码就编译好了:
case class Node(id: Int, name: String)
任何人都可以帮我定义正确的 Json 编码器来处理嵌套子项的情况吗?
完整代码:
import org.http4s.circe._
import org.http4s.dsl._
import org.http4s.server.blaze.BlazeBuilder
import org.http4s.server.{Server, ServerApp}
import org.http4s.{EntityEncoder, HttpService}
import scalaz.concurrent.Task
object Main extends ServerApp {
import io.circe.generic.auto._
import io.circe.syntax._
case class Node(id: Int, name: String, children: Seq[Node] = Seq())
def getNodes: Seq[Node] = Seq(
Node(0, "#One"),
Node(1, "#Two"),
Node(2, "#Three")
)
implicit val nodeEncoder: EntityEncoder[Node] = jsonEncoderOf[Node]
implicit val nodesEncoder: EntityEncoder[Seq[Node]] = jsonEncoderOf[Seq[Node]]
override def server(args: List[String]): Task[Server] = {
val nodesService = HttpService {
case _ @ GET -> Root / "nodes" =>
Ok(getNodes.asJson)
}
BlazeBuilder
.bindHttp(8080, "localhost")
.mountService(nodesService, "/api")
.start
}
}
好的。使用 circe json 注释让它工作 - @JsonCodec。
解决上述问题的分步指南:
先决条件 - 导入 circe 库:
"io.circe" %% "circe-core" % "0.8.0",
"io.circe" %% "circe-generic" % "0.8.0",
"io.circe" %% "circe-literal" % "0.8.0",
"io.circe" %% "circe-parser" % "0.8.0",
在你的 build.sbt:
中打开自动编译器插件
autoCompilerPlugins := true
添加scalamacros天堂编译器插件:
lazy val root = Project("root", file("."))
.settings(
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.patch)
)
用@JsonCodec注释案例类:
@JsonCodec case class Node(id: Int, children: Seq[Node] = Seq())
投射对json的回应:
Ok(getNodes.asJson)
完整代码片段:
import org.http4s.circe._
import org.http4s.dsl._
import org.http4s.server.blaze.BlazeBuilder
import org.http4s.server.{Server, ServerApp}
import org.http4s.{EntityEncoder, HttpService}
import scalaz.concurrent.Task
object Main extends ServerApp {
import io.circe.generic.auto._
import io.circe.syntax._
@JsonCodec case class Node(id: Int, name: String, children: Seq[Node] = Seq())
def getNodes: Seq[Node] = Seq(
Node(0, "#One"),
Node(1, "#Two"),
Node(2, "#Three")
)
override def server(args: List[String]): Task[Server] = {
val nodesService = HttpService {
case _ @ GET -> Root / "nodes" =>
Ok(getNodes.asJson)
}
BlazeBuilder
.bindHttp(8080, "localhost")
.mountService(nodesService, "/api")
.start
}
}
我正在构建一个非常简单的服务,它应该 return 一个通过递归案例定义的树状结构 class:
case class Node(id: Int, name: String, children: Seq[Node] = Seq())
但由于某种原因,我不断收到以下编译错误:
Error:(24, 70) could not find implicit value for parameter encoder: io.circe.Encoder[Seq[com.ansarada.ds.docviewer.server.Main.Node]]
implicit val nodesEncoder: EntityEncoder[Seq[Node]] = jsonEncoderOf[Seq[Node]]Error:(24, 70) not enough arguments for method jsonEncoderOf: (implicit encoder: io.circe.Encoder[Seq[com.ansarada.ds.docviewer.server.Main.Node]])org.http4s.EntityEncoder[Seq[com.ansarada.ds.docviewer.server.Main.Node]]. Unspecified value parameter encoder. implicit val nodesEncoder: EntityEncoder[Seq[Node]] = jsonEncoderOf[Seq[Node]]
一旦我删除了一个子元素定义并将一个节点变成一个平面对象,代码就编译好了:
case class Node(id: Int, name: String)
任何人都可以帮我定义正确的 Json 编码器来处理嵌套子项的情况吗?
完整代码:
import org.http4s.circe._
import org.http4s.dsl._
import org.http4s.server.blaze.BlazeBuilder
import org.http4s.server.{Server, ServerApp}
import org.http4s.{EntityEncoder, HttpService}
import scalaz.concurrent.Task
object Main extends ServerApp {
import io.circe.generic.auto._
import io.circe.syntax._
case class Node(id: Int, name: String, children: Seq[Node] = Seq())
def getNodes: Seq[Node] = Seq(
Node(0, "#One"),
Node(1, "#Two"),
Node(2, "#Three")
)
implicit val nodeEncoder: EntityEncoder[Node] = jsonEncoderOf[Node]
implicit val nodesEncoder: EntityEncoder[Seq[Node]] = jsonEncoderOf[Seq[Node]]
override def server(args: List[String]): Task[Server] = {
val nodesService = HttpService {
case _ @ GET -> Root / "nodes" =>
Ok(getNodes.asJson)
}
BlazeBuilder
.bindHttp(8080, "localhost")
.mountService(nodesService, "/api")
.start
}
}
好的。使用 circe json 注释让它工作 - @JsonCodec。 解决上述问题的分步指南:
先决条件 - 导入 circe 库:
"io.circe" %% "circe-core" % "0.8.0", "io.circe" %% "circe-generic" % "0.8.0", "io.circe" %% "circe-literal" % "0.8.0", "io.circe" %% "circe-parser" % "0.8.0",
在你的 build.sbt:
中打开自动编译器插件autoCompilerPlugins := true
添加scalamacros天堂编译器插件:
lazy val root = Project("root", file(".")) .settings( addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.patch) )
用@JsonCodec注释案例类:
@JsonCodec case class Node(id: Int, children: Seq[Node] = Seq())
投射对json的回应:
Ok(getNodes.asJson)
完整代码片段:
import org.http4s.circe._
import org.http4s.dsl._
import org.http4s.server.blaze.BlazeBuilder
import org.http4s.server.{Server, ServerApp}
import org.http4s.{EntityEncoder, HttpService}
import scalaz.concurrent.Task
object Main extends ServerApp {
import io.circe.generic.auto._
import io.circe.syntax._
@JsonCodec case class Node(id: Int, name: String, children: Seq[Node] = Seq())
def getNodes: Seq[Node] = Seq(
Node(0, "#One"),
Node(1, "#Two"),
Node(2, "#Three")
)
override def server(args: List[String]): Task[Server] = {
val nodesService = HttpService {
case _ @ GET -> Root / "nodes" =>
Ok(getNodes.asJson)
}
BlazeBuilder
.bindHttp(8080, "localhost")
.mountService(nodesService, "/api")
.start
}
}