I am trying to use a play-json reads to convert the following Json into a resulting case class. However, I am stuck on the syntax to convert the longitude and Latitude json values into a Point object meanwhile converting the rest of the json values into the same resulting BusinessInput object. Is this syntactically possible?
case class BusinessInput(userId: String, name: String, location: Point, address: Option[String], phonenumber: Option[String], email: Option[String])
object BusinessInput {
implicit val BusinessInputReads: Reads[BusinessInput] = (
(__ \ "userId").read[String] and
(__ \ "location" \ "latitude").read[Double] and
(__ \ "location" \ "longitude").read[Double]
)(latitude: Double, longitude: Double) => new GeometryFactory().createPoint(new Coordinate(latitude, longitude))
Fundamentally, a Reads[T]
just requires a function that turns a tuple into an instance of T
. You can therefore write one for your Point
class, given location
JSON object, like so:
implicit val pointReads: Reads[Point] = (
(__ \ "latitude").read[Double] and
(__ \ "longitude").read[Double]
)((lat, lng) => new GeometryFactory().createPoint(new Coordinate(lat, lng))
and then combine that with the rest of your data for the BusinessInput
class:
implicit val BusinessInputReads: Reads[BusinessInput] = (
(__ \ "userId").read[String] and
(__ \ "name").read[String] and
(__ \ "location").read[Point] and
(__ \ "address").readNullable[String] and
(__ \ "phonenumber").readNullable[String] and
(__ \ "email").readNullable[String]
)(BusinessInput.apply _)
In the second case we use the BusinessInput
classes apply
method as a short cut, but you could just as easily take a tuple of (userId, name, point)
and create one with the optional fields left out.
If you don't want to make a Point
reads separately, just combine them using the same principals:
implicit val BusinessInputReads: Reads[BusinessInput] = (
(__ \ "userId").read[String] and
(__ \ "name").read[String] and
(__ \ "location").read[Point]((
(__ \ "latitude").read[Double] and
(__ \ "longitude").read[Double]
)((lat, lng) => new GeometryFactory().createPoint(new Coordinate(lat, lng)))) and
(__ \ "address").readNullable[String] and
(__ \ "phonenumber").readNullable[String] and
(__ \ "email").readNullable[String]
)(BusinessInput.apply _)