如何将 JSON 转换为 Scala shapeless.hlist?
How to convert JSON to scala shapeless.hlist?
我得到了 json 像 {"name":"susan","age":25},还有 json 键集的提示,如 "name:String,age:Int",如何从 json?
创建一个 HList
基于 code you added and then deleted, it seems, having a runtime-string hint "name:String,age:Int"
and runtime-string json {"name":"susan","age":25}
, you want to get an HList
with runtime reflection。您可以按如下方式进行
import shapeless.HList
import scala.reflect.runtime
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val tb = runtime.currentMirror.mkToolBox()
val jsonStr = """{"name":"susan","age":25}"""
val hint = "name:String,age:Int"
val classType = tb.define(tb.parse(s"case class Test($hint)").asInstanceOf[ImplDef]).asClass.toType
val hlist = tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($jsonStr)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get)
""").asInstanceOf[HList]
println(hlist) // susan :: 25 :: HNil
请注意,您在 运行 时执行所有操作,因此您无法在编译时访问类型 String :: Int :: HNil
,并且 hlist
仅具有静态类型 HList
(不是 String :: Int :: HNil
)和 HList
实际上并不比 List[Any]
.
build.sbt
libraryDependencies ++= Seq(
scalaOrganization.value % "scala-reflect" % scalaVersion.value,
scalaOrganization.value % "scala-compiler" % scalaVersion.value,
"com.chuusai" %% "shapeless" % "2.4.0-M1",
"io.circe" %% "circe-core" % "0.13.0",
"io.circe" %% "circe-parser" % "0.13.0",
"io.circe" %% "circe-generic" % "0.13.0"
)
实际上,我想我们做了一些奇怪的事情。我们使用高度 type-level 旨在静态类型安全的库 (shapeless, circe),然后 运行 它们在 运行 时反射忽略类型安全并实际获得 List[Any]
( HList
).
我想如果 List[Any]
(字段值列表)对你来说足够了,那么你只需要使用更多 运行time 库。例如,使用 json4s
import org.json4s.{JInt, JObject, JString, JValue}
import org.json4s.jackson.JsonMethods._
val jsonStr: String = """{"name":"susan","age":25}"""
val json: JValue = parse(jsonStr) //JObject(List((name,JString(susan)), (age,JInt(25))))
val l: List[JValue] = json.asInstanceOf[JObject].obj.map(_._2) //List(JString(susan), JInt(25))
val res: List[Any] = l.map {
case JString(s) => s
case JInt(n) => n
} //List(susan, 25)
build.sbt
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.9"
其实 Circe 也可以做同样的事情,只是用 parse
而不是 decode[A]
import io.circe.{Json, JsonNumber}
import io.circe.parser.parse
val jsonStr: String = """{"name":"susan","age":25}"""
val json: Json = parse(jsonStr).toOption.get //{"name":"susan","age":25}
val l: List[Json] = json.asObject.get.values.toList //List("susan", 25)
val res: List[Any] = l.map(_.fold[Any](null, null, (_: JsonNumber).toInt.get, identity[String], null, null)) //List(susan, 25)
如果你需要一个 case class 的实例或一个元组而不是 HList
替换
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($jsonStr)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get)
""").asInstanceOf[HList] // susan :: 25 :: HNil
和
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
decode[$classType]($json).toOption.get
""").asInstanceOf[Product] //Test(susan,25)
或
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($json)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get).tupled
""").asInstanceOf[Product] //(susan,25)
相应地。
我得到了 json 像 {"name":"susan","age":25},还有 json 键集的提示,如 "name:String,age:Int",如何从 json?
创建一个 HList基于 code you added and then deleted, it seems, having a runtime-string hint "name:String,age:Int"
and runtime-string json {"name":"susan","age":25}
, you want to get an HList
with runtime reflection。您可以按如下方式进行
import shapeless.HList
import scala.reflect.runtime
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val tb = runtime.currentMirror.mkToolBox()
val jsonStr = """{"name":"susan","age":25}"""
val hint = "name:String,age:Int"
val classType = tb.define(tb.parse(s"case class Test($hint)").asInstanceOf[ImplDef]).asClass.toType
val hlist = tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($jsonStr)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get)
""").asInstanceOf[HList]
println(hlist) // susan :: 25 :: HNil
请注意,您在 运行 时执行所有操作,因此您无法在编译时访问类型 String :: Int :: HNil
,并且 hlist
仅具有静态类型 HList
(不是 String :: Int :: HNil
)和 HList
实际上并不比 List[Any]
.
build.sbt
libraryDependencies ++= Seq(
scalaOrganization.value % "scala-reflect" % scalaVersion.value,
scalaOrganization.value % "scala-compiler" % scalaVersion.value,
"com.chuusai" %% "shapeless" % "2.4.0-M1",
"io.circe" %% "circe-core" % "0.13.0",
"io.circe" %% "circe-parser" % "0.13.0",
"io.circe" %% "circe-generic" % "0.13.0"
)
实际上,我想我们做了一些奇怪的事情。我们使用高度 type-level 旨在静态类型安全的库 (shapeless, circe),然后 运行 它们在 运行 时反射忽略类型安全并实际获得 List[Any]
( HList
).
我想如果 List[Any]
(字段值列表)对你来说足够了,那么你只需要使用更多 运行time 库。例如,使用 json4s
import org.json4s.{JInt, JObject, JString, JValue}
import org.json4s.jackson.JsonMethods._
val jsonStr: String = """{"name":"susan","age":25}"""
val json: JValue = parse(jsonStr) //JObject(List((name,JString(susan)), (age,JInt(25))))
val l: List[JValue] = json.asInstanceOf[JObject].obj.map(_._2) //List(JString(susan), JInt(25))
val res: List[Any] = l.map {
case JString(s) => s
case JInt(n) => n
} //List(susan, 25)
build.sbt
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.9"
其实 Circe 也可以做同样的事情,只是用 parse
而不是 decode[A]
import io.circe.{Json, JsonNumber}
import io.circe.parser.parse
val jsonStr: String = """{"name":"susan","age":25}"""
val json: Json = parse(jsonStr).toOption.get //{"name":"susan","age":25}
val l: List[Json] = json.asObject.get.values.toList //List("susan", 25)
val res: List[Any] = l.map(_.fold[Any](null, null, (_: JsonNumber).toInt.get, identity[String], null, null)) //List(susan, 25)
如果你需要一个 case class 的实例或一个元组而不是 HList
替换
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($jsonStr)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get)
""").asInstanceOf[HList] // susan :: 25 :: HNil
和
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
decode[$classType]($json).toOption.get
""").asInstanceOf[Product] //Test(susan,25)
或
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($json)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get).tupled
""").asInstanceOf[Product] //(susan,25)
相应地。