Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play Framework: How to convert strings to numbers while validating JSON

Given the following JSON..

{
    "ask":"428.00",
    "bid":"424.20"
}

... I need to convert the values of ask and bid to numbers:

{
    "ask": 428.00,
    "bid": 424.20
}

To do that, I've created a validator that reads the string value and passes it to method toNumber, which validates and converts the given string:

def validate = (
  ((__ \ 'ask).json.pickBranch(Reads.of[JsString] <~ toNumber)) ~
  ((__ \ 'bid).json.pickBranch(Reads.of[JsString] <~ toNumber))
).reduce

private def toNumber(implicit reads: Reads[String]) = {
  Reads[Double](js =>
    reads.reads(js).flatMap { value =>
      parse[Double](value) match {
        case Some(number) => JsSuccess(number)
        case _ => JsError(ValidationError("error.number", value))
      }
    }
  )
}

The code above only validates the value but of course does not replace the original string with the converted number. How do I convert string values to numbers while validating?

EDIT

Just wanted to share the solution provided by Ben:

def validate = (
  ((__ \ 'ask).json.update(toNumber)) ~
  ((__ \ 'bid).json.update(toNumber))
).reduce

private def toNumber(implicit reads: Reads[String]) = {
  Reads[JsNumber](js =>
    reads.reads(js).flatMap { value =>
      parse[Double](value) match {
        case Some(number) => JsSuccess(JsNumber(number))
        case _ => JsError(ValidationError("error.number", value))
      }
    }
  )
}
like image 910
j3d Avatar asked Mar 05 '26 03:03

j3d


1 Answers

If you make toNumber a Reads[JsNumber] instead of a Reads[Double] (simply by wrapping number in JsNumber), then you can use transform together with update:

val transformer = (__ \ "ask").json.update(toNumber)
val json = Json.parse(""" { "ask" : "44" } """)
json.transorm(transformer) //JsSuccess({"ask":44.0},/ask)

val json = Json.parse(""" { "ask" : "foo" } """)
json.transorm(transformer) //JsError(List((/ask,List(ValidationError(error.number,WrappedArray(foo))))))

In a sense, transformers are validators. Instead of checking if something is valid, and then transforming it, you can use transform to simply transform the value, and get a JsError if the transformation is invalid. Read more about transform here.

like image 150
Ben Reich Avatar answered Mar 07 '26 16:03

Ben Reich



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!