Search code examples
scalatype-conversionavroplay-json

Scala Play JSON Type conversion


I'm currently struggling with the type conversion of the Play! Json library for Scala...
I have data that looks like this:

val myJson = Json.parse(...)

val mapping = Map[String, Option(JsValue)](
    "id" -> (myJson \ "Path" \ stringValue),
    "num" -> (myJson \ "Path" \ intValue),
    "precision" -> (myJson \ "Path" \ "floatValue")
)

Also, I have an Avro Schema that defines the data types of each field, in this case it's:
- id: String
- num: Int
- precision: Float

If I now iterate over the fields and check the types against the Avro Schema like this (Note that field in this case is the name of the value to get, e.g. "id"):

    ...
    case Schema.Type.STRING => mapping.getOrElse(field, None) match {
      case Some(stringVal: JsValue) => stringVal.as[String]
      case None => null
    }
    case Schema.Type.INT => mapping.getOrElse(field, None) match {
      case Some(intVal) => intVal.as[Int]
      case None => null
    }
    case Schema.Type.FLOAT => mapping.getOrElse(field, None) match {
      case Some(floatVal) => floatVal.as[Float]
      case None => null
    }
    ...

I always get this Error:

[org.apache.kafka.streams.processor.internals.StreamThread]  - Streams application error during processing in thread [StreamThread-1]:play.api.libs.json.JsResultException: JsResultException(errors:List((,List(JsonValidationError(List(error.expected.jsnumber),WrappedArray())))))

(Note: of course the error.expected.jsnumber can also be jsstring sometimes)

Here are the ways of conversion that I already tried, and did not work (I have several different of the mappings that in the end still contain either None or a value of given type):

floatVal.as[Float]
floatVal.as[JsNumber].as[Float]
floatVal.as[JsNumber].value.toFloat
Hi,

I'm currently struggling with the type conversion of the Play! Json library for Scala...
I have data that looks like this:

val myJson = Json.parse(...)

val mapping = Map[String, Option(JsValue)](
    "id" -> (myJson \ "Path" \ stringValue),
    "num" -> (myJson \ "Path" \ intValue),
    "precision" -> (myJson \ "Path" \ "floatValue")
)

Also, I have an Avro Schema that defines the data types of each field, in this case it's:
- id: String
- num: Int
- precision: Float

If I now iterate over the fields and check the types against the Avro Schema like this (Note that field in this case is the name of the value to get, e.g. "id"):

    ...
    case Schema.Type.STRING => mapping.getOrElse(field, None) match {
      case Some(stringVal: JsValue) => stringVal.as[String]
      case None => null
    }
    case Schema.Type.INT => mapping.getOrElse(field, None) match {
      case Some(intVal) => intVal.as[Int]
      case None => null
    }
    case Schema.Type.FLOAT => mapping.getOrElse(field, None) match {
      case Some(floatVal) => floatVal.as[Float]
      case None => null
    }
    ...

I always get this Error:

[org.apache.kafka.streams.processor.internals.StreamThread]  - Streams application error during processing in thread [StreamThread-1]:play.api.libs.json.JsResultException: JsResultException(errors:List((,List(JsonValidationError(List(error.expected.jsnumber),WrappedArray())))))

(Note: of course the error.expected.jsnumber can also be jsstring sometimes)

Here are the ways of conversion that I already tried, and did not work (I have several different of the mappings that in the end still contain either None or a value of given type):

floatVal.as[Float]
floatVal.as[JsNumber].as[Float]
floatVal.as[JsNumber].value.toFloat
floatVal.as[String].value.toFloat
floatVal.as[JsString].value.toString.toFloat
floatVal.as[String].toFloat
floatVal.as[String].value.toFloat
floatVal.as[JsString].value.toString.toFloat
floatVal.as[JsString].as[String].toFloat
floatVal.as[JsString].as[String].value.toFloat
floatVal.as[JsString].as[String].value.toString.toFloat

Somehow I have problems for all the types, only in some cases, but I have them...
What is also interesting is, that even though the type is JsValue, when I look at them with the Debugger, the type says Js<type>, e.g. JsString instead of JsValue.
In some occasions, however not always, it also displays JsString for the Int type...

Why doesn't it keep them as JsValue?

What is the right way to convert the Play! Json types?

Thank you All the best Tim


Solution

  • just making sure to update with the way that worked for me.

    In my case I just did the JsString, JsNumber, ... conversion right away on my own so that the framework is not inferring the type of it on it's own.