0

I have the following case class:

case class VirtualAssetConfigParam(
  id: Long,
  pMin: Double,
  pMax: Double,
  dispatchPriority: Int
)

object VirtualAssetConfigParam {

  implicit val virtualAssetConfigParamReads: Reads[VirtualAssetConfigParam] = (
    (JsPath \ "id").read[Long] and
      (JsPath \ "power_min").read[Double] and
      (JsPath \ "power_max").read[Double] and
      (JsPath \ "dispatch_priority").read[Int]
    )(VirtualAssetConfigParam.apply _)
}

This is the JSON that I get from the database:

[{"id":"1","power_min":"200","power_max":"400","dispatch_priority":"1"},{"id":"2","power_min":"200","power_max":"400","dispatch_priority":"2"},{"id":"3","power_min":"-700","power_max":"0","dispatch_priority":"3"}]

When I tried to validate it as (where virtualAssetConfigParam is a String that I get from the database):

Json.parse(virtualAssetConfigParam).validate[List[VirtualAssetConfigParam]]

I get the following as the validated result:

JsError(
    List(
        ((0)/dispatchPriority,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((0)/pMin,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((0)/pMax,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((0)/id,List(ValidationError(List(error.expected.jsnumber),WrappedArray()))), 
        ((1)/dispatchPriority,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((1)/pMin,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((1)/pMax,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((1)/id,List(ValidationError(List(error.expected.jsnumber),WrappedArray()))), 
        ((2)/dispatchPriority,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((2)/pMin,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((2)/pMax,List(ValidationError(List(error.path.missing),WrappedArray()))), 
        ((2)/id,List(ValidationError(List(error.expected.jsnumber),WrappedArray())))
    )
)

What is the problem? I could not see why this should fail!

joesan
  • 13,963
  • 27
  • 95
  • 232
  • `Json.parse` is used to parse a `Json-string` into PlayJson's Json representation which is `JsValue`. If you already have a JsValue... neither do you need to parse it nor can you parse it. – sarveshseri Oct 04 '16 at 08:56
  • Ok! Sorry for the confusion. The JSON is read as a String from the database and I parse it to a JsValue using the Json.parse(...) – joesan Oct 04 '16 at 09:05
  • If this is a simple string, you could use Json.toJson("string") – Arpit Suthar Oct 04 '16 at 09:25
  • Where and why should I use Json.toJson("string")? I'm trying to read a String as a Json and then validating that Json to my model! – joesan Oct 04 '16 at 09:53
  • Can you post your sample JSON `virtualAssetConfigParam` that you get from the database ? – Barry Oct 04 '16 at 12:53
  • I have ti above already! – joesan Oct 04 '16 at 12:59
  • Possible duplicate of [How to parse JSON in Scala using standard Scala classes?](http://stackoverflow.com/questions/4170949/how-to-parse-json-in-scala-using-standard-scala-classes) – pedrorijo91 Oct 29 '16 at 08:19

2 Answers2

0

If you look at your error you will notice that it is trying to find paths - dispatchPriority, pMin, pMax and id which is different from the paths that you wanted in your read. This indicates that the read implementation that you have shown in code is not being used here.

this leads me to think that probably you are not importing your implicit read into the scope of your code.

case class VirtualAssetConfigParam(
  id: Long,
  pMin: Double,
  pMax: Double,
  dispatchPriority: Int
)

object VirtualAssetConfigParam {

  implicit val virtualAssetConfigParamReads: Reads[VirtualAssetConfigParam] = (
    (JsPath \ "id").read[Long] and
    (JsPath \ "power_min").read[Double] and
    (JsPath \ "power_max").read[Double] and
    (JsPath \ "dispatch_priority").read[Int]
  )(VirtualAssetConfigParam.apply _)

}

object Demo extends App {

  // I think you are missing this import
  import VirtualAssetConfigParam.virtualAssetConfigParamReads

  val virtualAssetConfigParam = [{"id":"1","power_min":"200","power_max":"400","dispatch_priority":"1"},{"id":"2","power_min":"200","power_max":"400","dispatch_priority":"2"},{"id":"3","power_min":"-700","power_max":"0","dispatch_priority":"3"}]

 // It should work if you have that import
 val jsonValidate = Json.parse(virtualAssetConfigParam).validate[List[VirtualAssetConfigParam]]


}
sarveshseri
  • 13,738
  • 28
  • 47
  • Did you try running the code that you posted? I know that I have to import the implicit val. If not how would I be able to compile it in the first place? Your Demo object will fail when running as you can see that the data types in the Json does not match. For example., power_min is String in the Json, but the case class tries to read it as a Double and this fails. So try running it and then post your results. I have found a solution that I have posted here! – joesan Oct 05 '16 at 05:33
0

The data types in the JSON does not match the expected data types in the case class. So the case class should be as:

  implicit val virtualAssetConfigParamReads: Reads[VirtualAssetConfigParam] = new Reads[VirtualAssetConfigParam] {
    override def reads(json: JsValue): JsResult[VirtualAssetConfigParam] = {
      JsSuccess(VirtualAssetConfigParam(
        (json \ "id").as[String].toLong,
        (json \ "power_min").as[String].toDouble,
        (json \ "power_max").as[String].toDouble,
        (json \ "dispatch_priority").as[String].toInt
      ))
    }
  }

When I now call the parse function on the JSON, I do it like this:

Try((Json.parse(json)).validate[Seq[VirtualAssetConfigParam]])

and then fold on the Success of the Try!

joesan
  • 13,963
  • 27
  • 95
  • 232