Json jackson模块scala将映射中的长键序列化/反序列化为字符串

Json jackson模块scala将映射中的长键序列化/反序列化为字符串,json,scala,serialization,jackson,circe,Json,Scala,Serialization,Jackson,Circe,使用jackson模块Scala,我尝试使用Long as key对具有内部映射的对象进行序列化和反序列化,但是jackson将键序列化为字符串,如果忽略类中定义的类型,则不会反序列化它。 是虫子吗?我做错什么了吗 import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.fasterxml.jackson.m

使用jackson模块Scala,我尝试使用Long as key对具有内部映射的对象进行序列化和反序列化,但是jackson将键序列化为字符串,如果忽略类中定义的类型,则不会反序列化它。 是虫子吗?我做错什么了吗

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

case class InnerMap(map: Map[Long, Long])

object CrazyJackson {

  def main(args: Array[String]): Unit = {
    val mapper = new ObjectMapper() with ScalaObjectMapper
    mapper.registerModule(DefaultScalaModule)

    val innerMap = InnerMap(Map(1L->1L))
    val serialized = mapper.writeValueAsString(innerMap)
    val newObj = mapper.readValue(serialized, classOf[InnerMap])
    println(serialized) // Why the key is serialized as a String?
    println(innerMap)
    println(newObj)
    assert(newObj == innerMap)
  }

}
断言失败,println(序列化)语句的输出为:

{"map":{"1":1}}
奇怪的是,打印newObj和innerMap是一样的:

InnerMap(Map(1 -> 1))
InnerMap(Map(1 -> 1))
正如@Varren所说,问题实际上在于断言。但是:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import org.scalatest.FunSuite

class CrazyJacksonTest extends FunSuite {
  test("test json comparision") {
    val mapper = new ObjectMapper() with ScalaObjectMapper
    mapper.registerModule(DefaultScalaModule)

    val innerMap = InnerMap(Map(1L->1L))
    val serialized = mapper.writeValueAsString(innerMap)
    val newObj = mapper.readValue(serialized, classOf[InnerMap])
    assert(newObj.map == innerMap.map)
  }
}
断言结果:

Map("1" -> 1) did not equal Map(1 -> 1)
ScalaTestFailureLocation: CrazyJacksonTest$$anonfun$1 at (CrazyJacksonTest.scala:17)
Expected :Map(1 -> 1)
Actual   :Map("1" -> 1)
我迷路了地图必须是地图[长,长]

由于Spark依赖关系,我必须使用此版本:

  • Scala 2.11.11
  • jackson模块scala 2.6.5,并使用版本2.9.1进行测试,结果相同
其他资料:

  • 例如:

JSON只允许键名是字符串

对象结构表示为一对花括号标记 围绕零个或多个名称/值对名称是字符串。

你是对的,断言问题来自Jackson。 如您所见,
classOf[InnerMap]
实际上映射到
Map
内部
InnerMap
但您必须将此映射的typeinfo提交给jackson才能正确反序列化。它在中有解释,根据它你可以直接使用

case class InnerMap(@JsonDeserialize(keyAs = classOf[java.lang.Long])
                    map: Map[Long, Long])

JSON只允许键名是字符串

对象结构表示为一对花括号标记 围绕零个或多个名称/值对名称是字符串。

你是对的,断言问题来自Jackson。 如您所见,
classOf[InnerMap]
实际上映射到
Map
内部
InnerMap
但您必须将此映射的typeinfo提交给jackson才能正确反序列化。它在中有解释,根据它你可以直接使用

case class InnerMap(@JsonDeserialize(keyAs = classOf[java.lang.Long])
                    map: Map[Long, Long])

Scala Jackson模块不会推断映射中的密钥类型。 正如@Varren所回应的,解决方案是使用Jackson注释对模型进行注释,但采用这种方式:

  • 模型绑定到特定的解析器(模型定义中的Jackson注释)
  • 代码不那么清晰
因此,我决定从Jackson迁移到并删除注释,以保持代码干净。 这是一个测试,可以证明它正在正确解析和解析:

  test("test json circe comparision") {

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

    val innerMap = InnerMap(Map(1L -> 1L))

    val jsonStr = innerMap.asJson.noSpaces
    decode[InnerMap](jsonStr) match {
      case Right(innerMap2) => assert(innerMap2 == innerMap)
      case Left(error) => fail(error)
    }

  }
这并不意味着这是每个人的最佳解决方案。
Circe有一个插件可以将其与Jackson解析器结合使用,但我没有对其进行测试。

Scala Jackson模块不会推断映射中的键的类型。 正如@Varren所回应的,解决方案是使用Jackson注释对模型进行注释,但采用这种方式:

  • 模型绑定到特定的解析器(模型定义中的Jackson注释)
  • 代码不那么清晰
因此,我决定从Jackson迁移到并删除注释,以保持代码干净。 这是一个测试,可以证明它正在正确解析和解析:

  test("test json circe comparision") {

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

    val innerMap = InnerMap(Map(1L -> 1L))

    val jsonStr = innerMap.asJson.noSpaces
    decode[InnerMap](jsonStr) match {
      case Right(innerMap2) => assert(innerMap2 == innerMap)
      case Left(error) => fail(error)
    }

  }
这并不意味着这是每个人的最佳解决方案。
Circe有一个插件可以将它与Jackson解析器结合使用,但我没有对它进行测试。

所以问题在于断言。我认为case类实现了equals和hashCode。事实上,为什么“assert(InnerMap(Map(1L->1L))==InnerMap(Map(1L->1L))”可以?请检查我的新示例好吗?我错过了一些东西。如果case类被定义为Map[Long,Long],那么断言如何以Map[String,Long]的形式管理内部对象?指向“如何在Scala中比较对象是否相等?”的链接是另一种情况,因为它是比较类而不是比较case类。@angelcervera yeah,sry,我错了,你是对的,它来自杰克逊,而不是来自平等者。更新了我的答案。裁判官的回应!我现在明白了。我在README.md中查找链接后的文档,所有链接都是错误的。现在检查wiki部分。也谢谢你。所以问题在于断言。我认为case类实现了equals和hashCode。事实上,为什么“assert(InnerMap(Map(1L->1L))==InnerMap(Map(1L->1L))”可以?请检查我的新示例好吗?我错过了一些东西。如果case类被定义为Map[Long,Long],那么断言如何以Map[String,Long]的形式管理内部对象?指向“如何在Scala中比较对象是否相等?”的链接是另一种情况,因为它是比较类而不是比较case类。@angelcervera yeah,sry,我错了,你是对的,它来自杰克逊,而不是来自平等者。更新了我的答案。裁判官的回应!我现在明白了。我在README.md中查找链接后的文档,所有链接都是错误的。现在检查wiki部分。也谢谢你。