所以我有一个这种格式的JSON,我试图将它从蛇形案例转换为与相应案例类匹配的骆驼案例
val json = """
{
"items": [
{
"id": "7913",
"route_id": "33",
"predictable": true,
"run_id": "33_486_1",
"latitude": 34.0234949,
"longitude": -118.398712,
"heading": 236,
"seconds_since_report": 59
},
{
"id": "4140",
"route_id": "76",
"predictable": true,
"run_id": "76_174_0",
"latitude": 34.0331945,
"longitude": -118.2646534,
"heading": 122,
"seconds_since_report": 12
},
{
"id": "7620",
"route_id": "20",
"predictable": true,
"run_id": "20_669_0",
"latitude": 34.013733,
"longitude": -118.490067,
"heading": 334,
"seconds_since_report": 172
}
]
}
""".stripMargin
我想要转换为
final case class Sample(
id: Int,
routeId: Int,
predictable: Boolean,
runId: String,
latitude: Double,
longitude: Double,
heading: Int,
secondsSinceReport: Int
)
尝试使用
implicit val sampleDecoder = Decoder[List[Sample]].prepare(_.downField("items"))
val decodingResult = parser.decode(json)(sampleDecoder)
但结果为
Attempt to decode value on failed cursor: DownField(routeId),DownArray,DownField(items)
但是如果我从案例类中注释掉带有驼峰案例的字段,我会得到
Sample(7913,true,34.0234949,-118.398712,236)
Sample(4140,true,34.0331945,-118.2646534,122)
Sample(7620,true,34.013733,-118.490067,334)
答案 0 :(得分:1)
如果您可以使用另一个JSON库,则可以使用“ play-json”。这是一个独立的库。
final case class Sample(
id: String,
routeId: String,
predictable: Boolean,
runId: String,
latitude: Double,
longitude: Double,
heading: Int,
secondsSinceReport: Int)
final case class Samples(items: Seq[Sample])
import play.api.libs.json._
implicit val jsonCaseConversion = JsonConfiguration(JsonNaming.SnakeCase)
implicit val sampleJsonFormat = Json.format[Sample]
implicit val samplesJsonFormat = Json.format[Samples]
val json = """
{
"items": [
{
"id": "7913",
"route_id": "33",
"predictable": true,
"run_id": "33_486_1",
"latitude": 34.0234949,
"longitude": -118.398712,
"heading": 236,
"seconds_since_report": 59
},
{
"id": "4140",
"route_id": "76",
"predictable": true,
"run_id": "76_174_0",
"latitude": 34.0331945,
"longitude": -118.2646534,
"heading": 122,
"seconds_since_report": 12
},
{
"id": "7620",
"route_id": "20",
"predictable": true,
"run_id": "20_669_0",
"latitude": 34.013733,
"longitude": -118.490067,
"heading": 334,
"seconds_since_report": 172
}
]
}
""".stripMargin
val optSamples = Json.parse(json).asOpt[Samples]
我已将Sample.id
更改为String
的类型。如果您希望将其设置为Int
,最简单的方法是添加这样的方法
// this might thorw an exception.
// maybe there is a reason why id in json is string
def intId: Int = id.toInt
答案 1 :(得分:1)
您的用例直接来自文档:https://circe.github.io/circe/codecs/custom-codecs.html
import io.circe.generic.extras._, io.circe.syntax._
// import io.circe.generic.extras._
// import io.circe.syntax._
implicit val config: Configuration = Configuration.default.withSnakeCaseMemberNames
// config: io.circe.generic.extras.Configuration = Configuration(io.circe.generic.extras.Configuration$$$Lambda$9172/0x0000000801132040@69e0f3f6,io.circe.generic.extras.Configuration$$$Lambda$9171/0x0000000801133040@66433b0e,false,None,false)
@ConfiguredJsonCodec case class User(firstName: String, lastName: String)
// defined class User
// defined object User
User("Foo", "McBar").asJson
// res1: io.circe.Json =
// {
// "first_name" : "Foo",
// "last_name" : "McBar"
// }
您需要build.sbt
中的通用扩展名依赖项:
libraryDependencies ++= Seq(
"io.circe" %% "circe-core",
"io.circe" %% "circe-generic",
"io.circe" %% "circe-generic-extras",
"io.circe" %% "circe-parser"
).map(_ % circeVersion)
addCompilerPlugin("org.scalamacros" %% "paradise" % "2.1.1" cross CrossVersion.full)
文档说您在2.13.x中不需要编译器插件,但我无法对其进行编译。此外,尚无适用于2.13.x的天堂。因此,此解决方案仅适用于2.12和更早版本。
如果这是一次性的事情,则可以在不使用编译器宏的情况下手动进行转换:
implicit val decodeSample: Decoder[Sample] = new Decoder[Sample] {
final def apply(c: HCursor): Decoder.Result[Sample] =
for {
id <- c.downField("id").as[Int]
routeId <- c.downField("route_id").as[Int]
predictable <- c.downField("predictable").as[Boolean]
runId <- c.downField("run_id").as[String]
latitude <- c.downField("latitude").as[Double]
longitude <- c.downField("longitude").as[Double]
heading <- c.downField("heading").as[Int]
secondsSinceReport <- c.downField("seconds_since_report").as[Int]
} yield {
new Sample(id, routeId, predictable, runId, latitude, longitude, heading, secondsSinceReport)
}
}
答案 2 :(得分:1)
最后想通了
implicit val encoder : Encoder[Sample] =
Encoder.forProduct8(
"id",
"route_id",
"predictable",
"run_id",
"latitude",
"longitude",
"heading",
"seconds_since_report"
)(Sample.unapply(_).get)
implicit val decoder : Decoder[Sample] =
Decoder.forProduct8(
"id",
"route_id",
"predictable",
"run_id",
"latitude",
"longitude",
"heading",
"seconds_since_report"
)(Sample.apply)
implicit val sampleDecoder = Decoder[List[Sample]].prepare(_.downField("items"))
val decodingResult = parser.decode(json)(sampleDecoder)
decodingResult match {
case Left(value) => println(value.getMessage())
case Right(value) => value.foreach(println)
}
结果与提供的json匹配
Sample(7913,33,true,33_486_1,34.0234949,-118.398712,236,59)
Sample(4140,76,true,76_174_0,34.0331945,-118.2646534,122,12)
Sample(7620,20,true,20_669_0,34.013733,-118.490067,334,172)