Search code examples
jsonscalajson4s

In Json4s why does an integer field in a JSON object get automatically converted to a String?


If I have a JSON object like:

{
  "test": 3
}

Then I would expect that extracting the "test" field as a String would fail because the types don't line up:

import org.json4s._
import org.json4s.jackson.JsonMethods
import org.json4s.JsonAST.JValue

def getVal[T: Manifest](json: JValue, fieldName: String): Option[T] = {
  val field = json findField {
    case JField(name, _) if name == fieldName => true
    case _ => false
  }

  field.map {
    case (_, value) => value.extract[T]
  }
}

val json = JsonMethods.parse("""{"test":3}""")
val value: Option[String] = getVal[String](json, "test") // Was Some(3) but expected None

Is this automatic conversion from a JSON numeric to a String expected in Json4s? If so, are there any workarounds for this where the extracted field has to be of the same type that is specified in the type parameter to the extract method?


Solution

  • This is the default nature of most if not all of the parsers. If you request a value of type T and if the value can be safely cast to that specific type then the library would cast it for you. for instance take a look at the typesafe config with the similar nature of casting Numeric field to String.

    import com.typesafe.config._
    val config = ConfigFactory parseString """{ test = 3 }"""
    val res1 = config.getString("test")
    res1: String = 3
    

    if you wanted not to automatically cast Integer/Boolean to String you could do something like this manually checking for Int/Boolean types as shown below.

    if(Try(value.extract[Int]).isFailure || Try(value.extract[Boolean]).isFailure) {
        throw RuntimeException(s"not a String field. try Int or Boolean")
    } else {
     value.extract[T]
    }