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.

0

1 Answer 1

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

}
Sign up to request clarification or add additional context in comments.

5 Comments

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 <offending symbol>.asTerm.alternatives and manually picking the required method
So you need to provide one! Edited again.
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...
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.
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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.