Yar Yar - 2 months ago 27
JSON Question

Scala pattern match multiple types

I have a code for extracting

Int
from
JValue
that should look exactly the same for multiple
JValue
subclasses, so I'm trying to avoid repeating myself. However, as it is (see below), scala thinks that
j
is a generic
JValue
, and that
j.values
returns a value of type
Values
, which, of course, does not have
isValidInt
and
toInt
methods.

jvalue \ name match {
case j @ (JInt | JDecimal | JDouble) => {
val num = j.values
if (num.isValidInt) num.toInt.success else reportError(name + " is not a valid int")
}


The question is what is the proper way to avoid repetition here? I'm not that crazy about converting a
JValue
into string, because this code works with json just parsed from a string into an AST. I started thinking about writing wrappers for the three types I need matched and implicit converters from these types into wrappers, and then making a superclass just for these wrappers for use as a pattern, but I am not sure how to pull it off.

And yes, I realize there are multiple similar questions here (such as this and this), but each of them only contains part of the solution at most.

Answer

Implement an extractor to get the Int value out of arbitrary json values, then use the extractor in your mattern match.

object JsonInt {
  def unapply(json: JValue): Option[Int] = json match {
    case JInt(i) if i.isValidInt => Some(i.toInt)
    case JDecimal(d) if d.isValidInt => Some(d.toInt)
    case JDouble(d) if d.isValidInt => Some(d.toInt)
    case _ => None
  }
}

jvalue \ name match {
  case JsonInt(num) => num.success
  case _ => reportError(s"$name is not a valid int")
}
Comments