0

I have a custom data type in Scala:

case class GPID(value: Int) {
    // ... other stuff ...

    implicit val writesGPID = new Writes[GPID] {
        def writes(g: GPID): JsValue = {
            Json.obj(
                "GPID" -> g.value
            )
        }
    }

    implicit val reads: Reads[GPID] = (
        (__ \ "GPID").read[Int]
        ).map(GPID(_))
}

As you can see, it has a reads/writes method, but this result in output like this:

"id":{"GPID":1000}

But, we just want it to serialize/deserialize like a regular Int:

"id":1000

I've been trying to figure out how to rewrite the reads/writes but am not having much luck... Any advice would be appreciated!

Thank you.

yǝsʞǝla
  • 16,272
  • 2
  • 44
  • 65
Zaphod
  • 1,387
  • 2
  • 17
  • 33

1 Answers1

2

I added some validation, amend to your needs.

object GPID {
  def unapply(in: Int): Option[GPID] = Option(in).filter(_ > 0).map(apply)

  implicit val reads = new Reads[GPID] {
    def reads(in: JsValue) =
      Option(in)
        .flatMap {
          case JsNumber(value) => Some(value)
          case _ => None
        }
        .flatMap(num => unapply(num.toInt))
        .map(JsSuccess(_, __))
        .getOrElse(JsError(__, "validate.error.expected.GPID"))
  }

  implicit val writes = new Writes[GPID] {
    def writes(g: GPID) = JsNumber(g.value)
  }

}
goralph
  • 1,076
  • 9
  • 18
  • Hm. Closer, but not quite. It's serializing as `"id":{"id":1000}` so, it's still treating it as an object, not a simple value... Also I can't use an implicit reads because of: `ScalaReflectionException: value apply encapsulates multiple overloaded alternatives and cannot be treated as a method. Consider invoking .asTerm.alternatives and manually picking the required method` – Zaphod May 20 '15 at 15:39
  • So you need to provide one! Edited again. – goralph May 20 '15 at 16:51
  • Ah... Your unapply looks very different from the one I tried! Thank you, that is working perfectly now. I'm a little confused as to why we have to add an `unapply` now, when one is not necessary if we define the original Reads/Writes (from my first post). I'll have to take a closer look and figure it out. The Json Reads/Writes/apply/unapply is still a bit of black magic to me... – Zaphod May 20 '15 at 17:00
  • They're magic in that they give you many ways to achieve the same effect. At the start it's daunting, and frustrating, however once you get used to it they are quite powerful. Good luck. – goralph May 20 '15 at 17:03
  • When it comes to `unapply` I've written them to expect the class being deconstructed. I tried an `unapply(g: GPID)` but you have written an `unapply(in: Int)`, which you call directly from reads... and I'm still confused. I don't understand why or how this would work... I thought `unapply` was used to essentially deconstruct an instance of a thing. In this case the thing is a GPID, so... how can the `unapply` take an Int and actually work? Actually, what you have written as an `unapply` looks like an `apply` method to me! – Zaphod May 20 '15 at 20:02