【问题标题】:json4s deserialized object does not match originaljson4s反序列化对象与原始对象不匹配
【发布时间】:2017-08-07 21:52:46
【问题描述】:

在 Scala 2.10.6 中,使用我现在受限的 json4s 3.2.11,使用以下代码:

object Thing1 extends Enumeration {
    type Thing1 = Value
    val A = Value(0, "A")
    val B = Value(1, "B")
}

object Thing2 extends Enumeration {
    type Thing2 = Value
    val A = Value(0, "A")
    val B = Value(1, "B")
    val C = Value(2, "C")
}

case class ThingHolder(thing1: Thing1, thing2: Thing2)

class ThingSpec extends FlatSpec with Matchers {
    "desrialized" should "match original" in {
        import org.json4s.native.Serialization.writePretty
        implicit val formats = DefaultFormats + new EnumNameSerializer(Thing1) + new EnumNameSerializer(Thing2)

        val original = ThingHolder(Thing1.A, Thing2.C)
        println(original)

        val serialized = writePretty(original)
        println(serialized)

        val jValue = JsonParser.parse(serialized)
        val deserialized = jValue.camelizeKeys.extract[ThingHolder]
        println(deserialized)
        println(deserialized.thing1)

        deserialized should be(original)
    }
}

结果:

ThingHolder(A,C)
{
  "thing1":"A",
  "thing2":"C"
}
ThingHolder(A,C)
A

ThingHolder(A,C) was not equal to ThingHolder(A,C)

这发生在 Enumeration 中,但不是其他类型,例如 String。如果案例类只有一个枚举,它工作正常。这是为什么?我可以通过反序列化到带有字符串的案例类来纠正这个问题,然后按照我想要的方式映射到案例类。有没有办法哄json4s直接反序列化,使反序列化的对象与原始对象匹配?

编辑:

这是我提到的用于映射的技巧:

case class ThingHolderSerialized(thing1: String, thing2: String)

...

val deserialized = jValue.camelizeKeys.extract[ThingHolderSerialized]
val reconstituted = ThingHolder(Thing1.withName(deserialized.thing1), Thing2.withName(deserialized.thing2))

编辑:

其实不需要单独的序列化器类:

val deserialized = jValue.camelizeKeys.extract[ThingHolder]
val reconstituted = ThingHolder(Thing1.withName(deserialized.thing1.toString), Thing2.withName(deserialized.thing2.toString))

编辑:

似乎是 thing1 没有正确反序列化,因为这也构建了一个匹配的重组对象:

val reconstituted = deserialized.copy(thing1 = Thing1.withName(deserialized.thing1.toString))

但不是这个:

val reconstituted = deserialized.copy(thing2 = Thing2.withName(deserialized.thing2.toString))

【问题讨论】:

  • 我不确定在这种情况下问题出在哪里,但过去为了弄清楚为什么两个对象不匹配,我通常将我的单个 should be 语句分解为一系列语句,一个对于对象上的每个字段,准确查看哪个字段不匹配。
  • @Tyler - 在这个例子中,有两个枚举,我不确定。但是,如果 ThingHolder 只有一个 Thing1,如果将第二个 EnumNameSerializer 留在隐式语句中,它仍然会失败。在这种情况下,只有一个字段会失败。不过,这似乎并不意味着解决方案。
  • @Tyler - 这就是事情1。见第三次编辑。

标签: scala json4s


【解决方案1】:

我将其作为解决方案提供给需要在存在多个枚举的情况下支持 json4s 案例类反序列化的人。这不是我正在寻找的答案,但同时有效:

object Thing1 extends Enumeration {
    type Thing1 = Value
    val A = Value(0, "A")
    val B = Value(1, "B")
}

object Thing2 extends Enumeration {
    type Thing2 = Value
    val A = Value(0, "A")
    val B = Value(1, "B")
    val C = Value(2, "C")
}

case class ThingHolder(thing1: Thing1, thing2: Thing2)

class ThingSpec extends FlatSpec with Matchers {
    "reconstituted" should "match original" in {
        import org.json4s.native.Serialization.writePretty
        implicit val formats = DefaultFormats + new EnumNameSerializer(Thing1) + new EnumNameSerializer(Thing2)

        val original = ThingHolder(Thing1.A, Thing2.C)
        println(original)

        val serialized = writePretty(original)
        println(serialized)

        val jValue = JsonParser.parse(serialized)
        val deserialized = jValue.camelizeKeys.extract[ThingHolder]
        println(deserialized)

        val reconstituted = deserialized.copy(thing1 = Thing1.withName(deserialized.thing1.toString))
        reconstituted should be(original)
    }
}

关键在于我们正在构建reconstituted 的那一行。我们制作一个副本,并在此过程中将 thing1 转换为字符串并返回为枚举。幸运的是,toString 可以在没有正确反序列化该字段的情况下工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 2016-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多