play-json icon indicating copy to clipboard operation
play-json copied to clipboard

Error when reading nested value class

Open tomakita opened this issue 4 years ago • 0 comments

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)
  }
}

tomakita avatar Apr 06 '20 22:04 tomakita