在这里盘旋菜鸟。我正在尝试使用circe解码Scala中的case类的JSON字符串。我希望将输入JSON中的嵌套字段之一解码为Map [String,String],而不是为其创建单独的case类。
示例代码:
import io.circe.parser
import io.circe.generic.semiauto.deriveDecoder
case class Event(
action: String,
key: String,
attributes: Map[String, String],
session: String,
ts: Long
)
case class Parsed(
events: Seq[Event]
)
Decoder[Map[String, String]]
val jsonStr = """{
"events": [{
"ts": 1593474773,
"key": "abc",
"action": "hello",
"session": "def",
"attributes": {
"north_lat": -32.34375,
"south_lat": -33.75,
"west_long": -73.125,
"east_long": -70.3125
}
}]
}""".stripMargin
implicit val eventDecoder = deriveDecoder[Event]
implicit val payloadDecoder = deriveDecoder[Parsed]
val decodeResult = parser.decode[Parsed](jsonStr)
val res = decodeResult match {
case Right(staff) => staff
case Left(error) => error
}
我最终在属性字段上遇到了解码错误,如下所示:
DecodingFailure(String, List(DownField(north_lat), DownField(attributes), DownArray, DownField(events)))
我在这里找到了有关如何将JSON字符串解码为地图的有趣链接:Convert Json to a Map[String, String]
但是我对如何去做没什么运气。
如果有人可以指出正确的方向或帮助我,那将很棒。
让我们分析错误:
DecodingFailure(String, List(DownField(geotile_north_lat), DownField(attributes), DownArray, DownField(events)))
这意味着我们应该在“事件”中查找名为“属性”的数组,并在其中查找名为“ geotile_north_lat”的字段。最后的错误是该字段不能作为字符串读取。确实,在您提供的有效负载中,该字段不是字符串,而是双精度型。
因此,您的问题与Map解码无关。只需使用Map [String,Double],它应该可以工作。
因此您可以执行以下操作:
final case class Attribute(
key: String,
value: String
)
object Attribute {
implicit val attributesDecoder: Decoder[List[Attribute]] =
Decoder.instance { cursor =>
cursor
.value
.asObject
.toRight(
left = DecodingFailure(
message = "The attributes field was not an object",
ops = cursor.history
)
).map { obj =>
obj.toList.map {
case (key, value) =>
Attribute(key, value.toString)
}
}
}
}
final case class Event(
action: String,
key: String,
attributes: List[Attribute],
session: String,
ts: Long
)
object Event {
implicit val eventDecoder: Decoder[Event] = deriveDecoder
}
您可以这样使用:
val result = for {
json <- parser.parse(jsonStr).left.map(_.toString)
obj <- json.asObject.toRight(left = "The input json was not an object")
eventsRaw <- obj("events").toRight(left = "The input json did not have the events field")
events <- eventsRaw.as[List[Event]].left.map(_.toString)
} yield events
// result: Either[String, List[Event]] = Right(
// List(Event("hello", "abc", List(Attribute("north_lat", "-32.34375"), Attribute("south_lat", "-33.75"), Attribute("west_long", "-73.125"), Attribute("east_long", "-70.3125")), "def", 1593474773L))
// )
您可以自定义 Attribute 类及其 Decoder ,因此其值为 Doubles 或 Jsons 。< / p>