play-json
play-json copied to clipboard
Error when reading nested value class
Are you looking for help?
This seems to be a bug, but it's hard to be certain.
Play JSON Version (2.5.x / etc)
I've tried 2.8.1 and 2.7.3, both with the same result
API (Scala / Java / Neither / Both)
Scala
Operating System (Ubuntu 15.10 / MacOS 10.10 / Windows 10)
Ubuntu 18.04
JDK (Oracle 1.8.0_72, OpenJDK 1.8.x, Azul Zing)
java version "1.8.0_102" Java(TM) SE Runtime Environment (build 1.8.0_102-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
Library Dependencies
None
Expected Behavior
JSON strings can be deserialized to a class that has a field which is a value class using Json.valueFormat
, as described in the docs (https://www.playframework.com/documentation/2.8.x/ScalaJsonAutomated).
Actual Behavior
When trying to deserialize a JSON string to a class that has a field which is a value class, deserialization fails (using validate[T]
returns a JsError object) when using Json.valueFormat
to generate the Formatter code, but succeeds when using Json.format
.
Reproducible Test Case
I wasn't able to get the play-json project to build locally, so I didn't feel comfortable submitting a PR, but here's a test that I'm hoping you can run in order to observe the unexpected behavior:
package com.x.y.z
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import play.api.libs.json.{Format, Json}
object Inner {
// Results in JsError at read time. I would expect to be able to
// use this, since Inner is a value class.
implicit val format: Format[Inner] = Json.valueFormat[Inner]
// Results in JsSuccess at read time
//implicit val format: Format[Inner] = Json.format[Inner]
}
// Value class
case class Inner(id: Int) extends AnyRef
object Outer {
implicit val format: Format[Outer] = Json.format[Outer]
}
case class Outer(inner: Inner)
class JsonSpec
extends AnyFlatSpec
with Matchers {
"Play" should "be able to read and write a nested value class" in {
val outer = Outer(Inner(5))
// Writes succeed
val jsValue = Json.toJson(outer).toString()
// Reads fail
val jsResult = Json.parse(
""" {
| "inner": {
| "id": 1
| }
| }""".stripMargin
).validate[Outer]
println(jsResult)
}
}