jsonscalaexceptionakkajson4s

How to know which field is missed while parsing json in Json4s


I have made a generic method which parses json to case class and it also works fine. But if tries to parse big json which have one or two mandatory field then I am not able to figure out which particular mandatory f ield is missing. I am only able to handle it with IllegalArgumentException. Is there a way to handle to know which is field is missing while parsing Json by using json4s.

Here is my code ->

object JsonHelper {

  implicit val formats: DefaultFormats = DefaultFormats

  def write[T <: AnyRef](value: T): String = jWrite(value)

  def parse(value: String): JValue = jParser(value)

}

And this is the method I am using to parse Json and handle failed case ->

def parseJson[M](json: String)(implicit m: Manifest[M]): Either[ErrorResponse, M] = {
    try
      Right(JsonHelper.parse(json).extract[M])
    catch {
      case NonFatal(th) =>
        th.getCause.getCause match {
          case e: java.lang.IllegalArgumentException =>
            error(s"Invalid JSON - $json", e)
            Left(handle(exception = EmptyFieldException(e.getMessage.split(":").last)))
          case _ =>
            error(s"Invalid JSON - $json", th)
            Left(handle(exception = new IllegalArgumentException("Invalid Json", th)))
        }
    }
  }

Like for a Json ->

{
   "name": "Json"
}

And case class ->

case class(name: String, profession: String)

if I try to parse above json into case class currently I am getting Invalid JSON - IllegalArgumentException. But is there a way that the exception tells which is field is missing like in above example "profession" is missing.


Solution

  • Is there a way to handle to know which is field is missing while parsing Json by using json4s.

    Maybe you have more complicated setting, but for example for

    import org.json4s._
    import org.json4s.jackson.JsonMethods._
    
    val str = """{
                 |  "name": "Json"
                 |}""".stripMargin
    
    val json = parse(str) // JObject(List((name,JString(Json))))
    
    implicit val formats: Formats = DefaultFormats
    
    case class MyClass(name: String, profession: String)
    
    json.extract[MyClass]
    

    it produces

    org.json4s.MappingException: No usable value for profession
    Did not find value which can be converted into java.lang.String
        at org.json4s.reflect.package$.fail(package.scala:56)
        at ...
    

    with the name of missing field and if the class is just case class MyClass(name: String) then this produces MyClass(Json).

    If the class is case class MyClass(name: String, profession: Option[String]) then this produces MyClass(Json,None).


    So normally IllegalArgumentException should be followed by Caused by: org.json4s.MappingException with the field name. I guess now you're swallowing json4s MappingException somewhere. Maybe in th.getCause.getCause match .... It's hard to say without MCVE.