Is it possible to make json4s not to throw exception when required field is missing ?
When I "extract" object from raw json string it throws exception like this one
org.json4s.package$MappingException: No usable value for pager
No usable value for rpp
Did not find value which can be converted into byte
at org.json4s.reflect.package$.fail(package.scala:98)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:388)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$11.apply(Extraction.scala:396)
Is it possible just to let it be null ?
It's quite simple, you have to use Option
and its potentials, Some
and None
.
val json = ("name" -> "joe") ~ ("age" -> Some(35));
val json = ("name" -> "joe") ~ ("age" -> (None: Option[Int]))
Beware though, in the above case a match
will be performed for your Option
. If it's None
, it will be completely removed from the string, so it won't feed back null.
In the same pattern, to parse incomplete JSON, you use a case class
with Option
.
case class someModel(
age: Option[Int],
name: Option[String]
);
val json = ("name" -> "joe") ~ ("age" -> None);
parse(json).extract[someModel];
There is a method which won't throw any exception, and that is extractOpt
parse(json).extractOpt[someModel];
A way to replicate that with the scala API would be to use scala.util.Try
:
Try { parse(json).extract[someModel] }.toOption
I've dealt with this problem when dealing with data migrations, and I wanted default values to fill undefined fields.
My solution was to merge the defaults into the JValue before extracting the result.
val defaultsJson = Extraction.decompose(defaults)
val valueJson = JsonUtil.jValue(v)
(defaultsJson merge valueJson).extract[T]
JsonUtil.scala
import org.json4s._
object JsonUtil {
import java.nio.charset.StandardCharsets.UTF_8
import java.io.{InputStreamReader, ByteArrayInputStream}
def jValue(json: String): JValue = {
jValue(json.getBytes(UTF_8))
}
def jValue(json: Array[Byte]): JValue = {
val reader = new InputStreamReader(new ByteArrayInputStream(json), UTF_8)
native.JsonParser.parse(reader)
}
}