使用 Circe 将包含 HList 的案例 class 解析为 JSON 字符串
Parse a case class containing an HList into a JSON string, using Circe
我正在用 Scala 做一件事。我有以下案例 class:
import shapeless._
case class Foo(param1: String, param2: HList)
我想获得这种类型的JSON表示,使用Circe。我还想 将生成的 JSON 字符串映射回类型。
circe-shapes 模块自动推导 HList,从 HList 到 JSON 来回很容易。看这个例子:
scala> import shapeless._
import shapeless._
scala> import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
scala> import io.circe.shapes._
import io.circe.shapes._
scala> val myList = 30 :: "car" :: HNil
myList: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 30 :: car :: HNil
scala> val listJson = myList.asJson
listJson: io.circe.Json =
[
30,
"car"
]
scala> listJson.as[HList] // won't work
<console>:32: error: could not find implicit value for parameter d: io.circe.Decoder[shapeless.HList]
listJson.as[HList]
^
scala> listJson.as[::[Int, ::[String, HNil]]]
res3: io.circe.Decoder.Result[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]] = Right(30 :: car :: HNil)
包含 "standard" 类型的案例 class 也是微不足道的:
scala> case class Bar(one: String, a: Double, andAn: Int)
defined class Bar
scala> val myBar = Bar("pie", 4.35, 2)
myBar: Bar = Bar(pie,4.35,2)
scala> val barJson = myBar.asJson
barJson: io.circe.Json =
{
"one" : "pie",
"a" : 4.35,
"andAn" : 2
}
scala> barJson.as[Bar]
res5: io.circe.Decoder.Result[Bar] = Right(Bar(pie,4.35,2))
明确 HList 的类型会产生奇迹,但它有点违背 HList 的目的:
scala> case class Foo2(a: String, b: ::[Int, ::[String, HNil]])
defined class Foo2
scala> val myFoo2 = Foo2("ark", 42 :: "meg" :: HNil)
myFoo2: Foo2 = Foo2(ark,42 :: meg :: HNil)
scala> val foo2Json = myFoo2.asJson
foo2Json: io.circe.Json =
{
"a" : "ark",
"b" : [
42,
"meg"
]
}
scala> foo2Json.as[Foo2]
res8: io.circe.Decoder.Result[Foo2] = Right(Foo2(ark,42 :: meg :: HNil))
Circe 可以解码任意 HList 吗?
是的,circe 可以做到这一点,但您需要更改您的案例 class 以使其保留有关 HList
:
的更多信息
import shapeless._
case class Foo[L <: HList](param1: String, param2: L)
然后是导入:
import io.circe.generic.auto._, io.circe.shapes._, io.circe.parser._, io.circe.syntax._
然后可以调用asJson
,等等:
scala> val foo = Foo("ark", 42 :: "meg" :: HNil)
foo: Foo[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]] = Foo(ark,42 :: meg :: HNil)
scala> foo.asJson
res0: io.circe.Json =
{
"param1" : "ark",
"param2" : [
42,
"meg"
]
}
scala> decode[Foo[Int :: String :: HNil]](res0.noSpaces).right.foreach(println)
Foo(ark,42 :: meg :: HNil)
在这种情况下,circe 中的推导机制需要有关 hlist 元素的静态信息,以便生成编码器和解码器,但更一般地说,当您使用 hlist 时,您会希望避免类型为普通旧 HList
.
的成员或值
对于 HList
类型的东西,您无能为力。你可以在它前面加上值,你可以通过 toString
获得一个字符串表示,但仅此而已——你不能使用任何 Shapeless 的 ops
类型 classes,你可以' t 恢复有关单个类型等的任何信息。您几乎总是(可能总是总是)想要一个 L <: HList
,它允许您保留使该类型有用的信息。
我正在用 Scala 做一件事。我有以下案例 class:
import shapeless._
case class Foo(param1: String, param2: HList)
我想获得这种类型的JSON表示,使用Circe。我还想 将生成的 JSON 字符串映射回类型。
circe-shapes 模块自动推导 HList,从 HList 到 JSON 来回很容易。看这个例子:
scala> import shapeless._
import shapeless._
scala> import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
scala> import io.circe.shapes._
import io.circe.shapes._
scala> val myList = 30 :: "car" :: HNil
myList: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 30 :: car :: HNil
scala> val listJson = myList.asJson
listJson: io.circe.Json =
[
30,
"car"
]
scala> listJson.as[HList] // won't work
<console>:32: error: could not find implicit value for parameter d: io.circe.Decoder[shapeless.HList]
listJson.as[HList]
^
scala> listJson.as[::[Int, ::[String, HNil]]]
res3: io.circe.Decoder.Result[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]] = Right(30 :: car :: HNil)
包含 "standard" 类型的案例 class 也是微不足道的:
scala> case class Bar(one: String, a: Double, andAn: Int)
defined class Bar
scala> val myBar = Bar("pie", 4.35, 2)
myBar: Bar = Bar(pie,4.35,2)
scala> val barJson = myBar.asJson
barJson: io.circe.Json =
{
"one" : "pie",
"a" : 4.35,
"andAn" : 2
}
scala> barJson.as[Bar]
res5: io.circe.Decoder.Result[Bar] = Right(Bar(pie,4.35,2))
明确 HList 的类型会产生奇迹,但它有点违背 HList 的目的:
scala> case class Foo2(a: String, b: ::[Int, ::[String, HNil]])
defined class Foo2
scala> val myFoo2 = Foo2("ark", 42 :: "meg" :: HNil)
myFoo2: Foo2 = Foo2(ark,42 :: meg :: HNil)
scala> val foo2Json = myFoo2.asJson
foo2Json: io.circe.Json =
{
"a" : "ark",
"b" : [
42,
"meg"
]
}
scala> foo2Json.as[Foo2]
res8: io.circe.Decoder.Result[Foo2] = Right(Foo2(ark,42 :: meg :: HNil))
Circe 可以解码任意 HList 吗?
是的,circe 可以做到这一点,但您需要更改您的案例 class 以使其保留有关 HList
:
import shapeless._
case class Foo[L <: HList](param1: String, param2: L)
然后是导入:
import io.circe.generic.auto._, io.circe.shapes._, io.circe.parser._, io.circe.syntax._
然后可以调用asJson
,等等:
scala> val foo = Foo("ark", 42 :: "meg" :: HNil)
foo: Foo[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]] = Foo(ark,42 :: meg :: HNil)
scala> foo.asJson
res0: io.circe.Json =
{
"param1" : "ark",
"param2" : [
42,
"meg"
]
}
scala> decode[Foo[Int :: String :: HNil]](res0.noSpaces).right.foreach(println)
Foo(ark,42 :: meg :: HNil)
在这种情况下,circe 中的推导机制需要有关 hlist 元素的静态信息,以便生成编码器和解码器,但更一般地说,当您使用 hlist 时,您会希望避免类型为普通旧 HList
.
对于 HList
类型的东西,您无能为力。你可以在它前面加上值,你可以通过 toString
获得一个字符串表示,但仅此而已——你不能使用任何 Shapeless 的 ops
类型 classes,你可以' t 恢复有关单个类型等的任何信息。您几乎总是(可能总是总是)想要一个 L <: HList
,它允许您保留使该类型有用的信息。