反序列化后受 case class 定义位置影响的结构平等

Structural equality affected by location of case class definition after deserialisation

为什么在反序列化为 case class 实例之后,由于 case class 定义的位置在另一个 class 内部或外部,结构相等性比较会受到影响。例如,以下片段中的断言

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 的影响?

这是一个错误。

https://github.com/json4s/json4s/issues/564 "Deserialized inner case classes cannot be compared with case classes initialized in code"

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

  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