【问题标题】:Structural equality affected by location of case class definition after deserialisation反序列化后受案例类定义位置影响的结构平等
【发布时间】:2019-09-17 07:11:45
【问题描述】:

为什么在反序列化为案例类实例之后,结构相等比较会受到案例类定义的位置在另一个类内部或外部的影响。比如下面sn -p中的断言

package example

import org.json4s.DefaultFormats
import org.json4s.native.JsonMethods.parse

class Foo {
  case class Person(name: String)
  def bar = {
    implicit val formats = DefaultFormats
    val expected = Person(name = "picard")
    val actual = parse("""{"name": "picard"}""").extract[Person]
    assert(expected == actual, s"$expected == $actual")
  }
}

object Main extends App {
  (new Foo).bar
}

失败

`java.lang.AssertionError: assertion failed: Person(picard) == Person(picard)`

如果我们像这样将 Person 定义移到 class Foo 之外,它就会通过

case class Person(name: String)
class Foo {
  def bar = {
    ...
    assert(expected == actual, s"$expected == $actual")
  }
}

注意,在这两种情况下,反序列化似乎都是成功的,例如,

assert(expected.name == actual.name)

无论case class Person 定义位置如何,都可以满足。

也许它受到传递给extract 的隐式Manifest 的影响?

【问题讨论】:

  • 如果你将 Foo 设为内部 Person 的对象,你将拥有 Exception in thread "main" org.json4s.package$MappingException: unknown error Caused by: java.lang.NullPointerException
  • 我无法复制它。 object Foo { case class Person(name: String) ... 似乎没有给我抛出异常。
  • 我把它们做成了内部object App { object Foo { case class Person(name: String) ...
  • Scala 2.12.8 + json4s-native 3.6.5

标签: scala equals json4s


【解决方案1】:

看起来无法有意义地检查内部类是否相等,因为每个实例都包含对外部对象的引用。这些引用是相等性检查的一部分:

  class Outer {
    case class Inner(s: String)
  }

  val outer = new Outer()
  val a = outer.Inner("x")
  val b = outer.Inner("x")
  println(a==b) //true
  val c = new Outer().Inner("x")
  println(a==c) //false

【讨论】:

  • 问题是为什么expectedactualac 而不像ab
  • 很奇怪:我尝试将equals/hashCode 添加到Outer,但仍然不起作用。但如果我用 Java 做它,它就可以工作。所以Java通过equals比较外部类,Scala通过引用比较。
  • 没那么奇怪。 outer.Innerouter1.Inner 是不同的类型equalshashCode 无关)。如果ac 具有不同的类型,那么自动生成的equals 会为它们提供false。 Java 没有依赖路径的类型。 Java 类型 Outer.Inner 类似于 Scala 类型 Outer#Inner
【解决方案2】:

这是一个错误。

https://github.com/json4s/json4s/issues/564 “反序列化的内部案例类无法与代码中初始化的案例类进行比较”

【讨论】: