For this case class:
import io.circe.generic.JsonCodec
@JsonCodec
case class Stuff(things: Array[String])
This test passes ok (case class to json test):
import io.circe.parser.decode
import io.circe.syntax._
import org.scalatest._
val caseClass = Stuff(things = Array("one", "two"))
val json = caseClass.asJson.spaces2
json shouldEqual
"""{
| "things" : [
| "one",
| "two"
| ]
|}""".stripMargin
However, this is failing (json to case class test)
import io.circe.parser.decode
import io.circe.syntax._
import org.scalatest._
val json =
"""{
| "things" : [
| "one",
| "two"
| ]
|}""".stripMargin
val caseClass = Right(decode[Stuff](json))
caseClass shouldEqual Stuff(things = Array("one", "two"))
Stepping through it in a debugger, it seems that the array doesn not get decoded as I would expect, it seems to be the object identity/memory address, which is always different, and so my test is failing:
[Ljava.lang.String;@2fa7ae9
Note this just seems to happen for Arrays, there is lots more stuff in my json blob that I have left out for this example - Maps and nested case-classes all get decoded and can be compared ok, its only when Arrays are added that the comparison fails - am I missing something?
This is more a Scala issue (or a ScalaTest issue) than a circe one. Scala's ==
method on arrays uses reference equality, and while ScalaTest's shouldEqual
will work "correctly" on arrays (i.e. it'll compare contents rather than references), it will still use ==
for array members when comparing two case class instances.
There are lots of ways you could work around this: by writing your own Equality
instance for Stuff
, by comparing caseClass.things shouldEqual Array("one", "two")
, etc. Having a mutable collection (like Array
) as a case class member is not idiomatic Scala and is almost certainly a bad idea, though, and I'd strongly suggest fixing this issue by changing it to something like List
or Vector
.