从json字符串创建listmap[string,int]以在case类中使用

ukxgm1gy  于 2021-06-04  发布在  Kafka
关注(0)|答案(2)|浏览(365)

我有一个来自Kafka主题的json字符串

{"id": 12345, "items": {"unit17": 0, "unit74": 0, "unit42": 0, "unit96": 0, "unit13": 0, "unit16": 0, "unit11": 0, "z10": 0, "z0": 1}}

通过使用spray json(版本1.3.5),我想解析它,所以我要:

val parsedStream = stream.map( event => event.parseJson )

这很好,但使用“parsejson”时,项的嵌套json是按字母顺序排列的,并且在一个列表中:

parsedStream.print()
--> List(12345,{"unit11": 0, "unit13": 0, "unit16": 0, "unit17":0, "unit42": 0, "unit74": 0, "unit96": 0, "z0": 1, "z10": 0}}

你知道为什么spray-json会这样并自动排序吗?有什么设置可以避免这种情况,或者有什么选项可以应用?
我试着用另一个库play json(play.api.libs.json.json)做同样的事情,它工作正常,所以我可以使用这个库,但我很好奇,我是否缺少一些关于spray json的东西:

val parsedStream = stream.map( event => Json.parse(event))
    parsedStream.print()

    --> {"id":12345,"items":{"unit17":0,"unit74":0,"unit42":0,"unit96":0,"unit13":0,"unit16":0,"unit11":0,"z10":0,"z0":1}}

最后,我想给case类提供该流的值;为此,我实现了以下元素:

case class MyCaseClass(id:Int,items:Map[String,Int])
    val parsedStream = stream.map{ value => MyCaseClass( (value \ "id").as[Int], 
                                                         (value \ "items").as[Map[String,Int]] ) }

这很顺利,但由于我使用了“items”属性的Map,json中的顺序没有强制保持,我需要这样做,因为这将被发送到一个模型来预测一些东西,并且模型训练已经用kafka主题生成的相同的项顺序完成。我知道scala提供了一个listmap,它是一种带有list接口的“有序”Map,但在这样使用它时:

case class MyCaseClass(id:Int,items:ListMap[String,Int])
    val parsedStream = stream.map{ value => MyCaseClass( (value \ "id").as[Int], 
                                                         (value \ "items").as[ListMap[String,Int]] ) }

编译器声明“找不到类型的json反序列化程序” scala.collection.immutable.ListMap[String,Int] . 尝试为这个类型实现一个隐式读取或格式“,我想是因为没有一个适合这个类型的自动json宏,应该实现它。关于如何对listmap或我可以实现的任何其他方法来实现,使case类中的项与json中的项具有相同的顺序,您有什么提示吗?也许把“items”json字符串改成json数组就可以了,有没有关于如何实现这一点的提示?
编辑-用circe json解析
在使用play json进行了一些测试之后,将listmap用于reads宏有点棘手,因此我阅读了circe json并进行了实验,最后一个测试对这两个方面都非常直接,解析顺序和到listmap的转换。只需要一些导入和一行代码就可以完成解析并转换到case类:

import io.circe._
import io.circe.parser._
import io.circe.generic.auto._

[...]

case class MyCaseClass(id:Int,items:ListMap[String,Int])

[...]

val streamParsed = stream.map{ event => parser.decode[MyCaseClass](event) match {
   case Left(failure) => [...]
   case Right(myCaseClassInstance) => { myCaseClassInstance }
}}

[...]

它将自动解析保持顺序,并使用listmap生成一个数据流[mycaseclass],以保持生成的Map中的顺序。从json到listmap的Map可以通过“io.circe.generic.auto.\”实现,它支持listmap并透明地处理这个转换。

jhkqcmku

jhkqcmku1#

在1.3.0中引入的github上,这似乎是一个开放的问题。您可以尝试降级到1.2.6或使用另一个json库,如circe
https://github.com/spray/spray-json/issues/119

3z6pesqy

3z6pesqy2#

json格式不能保证密钥的顺序,spray也遵守规范。
就像bellam说的,你可能想要使用一个库,它比规范做的更多,并且让你的密钥保持有序,比如circe。

相关问题