我有一个来自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并透明地处理这个转换。
2条答案
按热度按时间jhkqcmku1#
在1.3.0中引入的github上,这似乎是一个开放的问题。您可以尝试降级到1.2.6或使用另一个json库,如circe
https://github.com/spray/spray-json/issues/119
3z6pesqy2#
json格式不能保证密钥的顺序,spray也遵守规范。
就像bellam说的,你可能想要使用一个库,它比规范做的更多,并且让你的密钥保持有序,比如circe。