代码之家  ›  专栏  ›  技术社区  ›  angelcervera

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

  •  1
  • angelcervera  · 技术社区  · 8 年前

    使用jackson模块Scala,我尝试使用 只要钥匙 是虫子吗?我做错什么了吗?

    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进行测试,结果相同。

    2 回复  |  直到 8 年前
        1
  •  1
  •   varren    8 年前

    JSON只允许键名为字符串。 ECMA-404 The JSON Data Interchange Standard

    对象结构表示为一对花括号标记 名称是一个字符串。

    你是对的,断言问题来自杰克逊。 enter image description here classOf[InnerMap] 实际上映射到 Map<Object, Object> 在…内 InnerMap 但是你必须将这个地图的typeinfo提交给jackson才能正确地反序列化它。解释见 this documentation 根据它,你可以使用

    case class InnerMap(@JsonDeserialize(keyAs = classOf[java.lang.Long])
                        map: Map[Long, Long])
    
        2
  •  -1
  •   angelcervera    8 年前

    Scala-Jackson模块不会推断地图中键的类型。

    • 该模型绑定到特定的解析器(模型定义中的Jackson注释)。
    • 代码不太清楚。

    Circe 删除批注 保持代码整洁。 这是一个测试,证明它正在正确解析和解压:

      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解析器结合使用,但我没有测试它。