Play Framework JSON阅读器

时间:2014-06-06 20:48:07

标签: json scala playframework-2.0

我正在尝试以下列格式阅读JSON

[
{type: "city",name:"Paris",lan:10.1,lot:20.0},
{type: "country",name:"France",...}

]

to Array [GeoObject],其中GeoObject是Country和City类的父级

我怎么能用Json Readers做这个技巧?我试过像

这样的东西
def mkObject(..,type:String,..):GeoObject = type match {
case 'city' => City(...)
case 'country' => Country(...)
}
implicit val geoobjectReads = (
      (JsPath \ "name").read[String] and
....
)(mkObject _)

但没有成功。

实际上我还有另一个不同的问题。

我在JSON中有两个字段'lan','lot' - 但是GeoObject只有一个

coordinates:LanLot

其中LanLot只是具有2个参数的case类。

2 个答案:

答案 0 :(得分:2)

如果您希望将它们放在一个单独的案例类中,您还希望为您的坐标创建json读/写,并且可以将它们解析为GeoObject内的嵌套对象。不过,你肯定是在正确的轨道上。

全部放在一起:

case class Coordinates(latitude: Double, longitude: Double)

object Coordinates {

    implicit val jsonReads: Reads[Coordinates] = (
        (__ \ "latitude").read[Double] and 
        (__ \ "longitude").read[Double]
    )(Coordinates.apply _)

}

class GeoObject(`type`: String, name: String, coordinates: Coordinates)

object GeoObject {

    def apply(`type`: String, name: String, coordinates: Coordinates) = {
        `type` match {
            case "city" => City(`type`, name, coordinates)
            case "country" => Country(`type`, name, coordinates)
        }
    }

    implicit val jsonReads: Reads[GeoObject] = (
        (__ \ "type").read[String] and 
        (__ \ "name").read[String] and 
        (__ \ "coordinates").read[Coordinates]
    )(GeoObject.apply _)

 }

case class City(`type`: String, name: String, coordinates: Coordinates) extends GeoObject(`type`, name, coordinates)

case class Country(`type`: String, name: String, coordinates: Coordinates) extends GeoObject(`type`, name, coordinates)

行动中(play console):

scala> Json.parse("""{"type":"city", "name": "New York", "coordinates": {"latitude": 40.77, "longitude": -73.92}}""").as[GeoObject]
res2: GeoObject = City(city,New York,Coordinates(40.77,-73.92))

我覆盖GeoObject.apply以始终转换为CityCountry,但您可以使用您想要的任何功能。

编辑:我继续使用type和Vikas指出的反叛。

答案 1 :(得分:0)

我不是Play的忠实粉丝! json读取语法。 所以我更愿意使用Json Inception来读入临时案例类,然后我会在代码中明确地从一个案例类转换为另一个案例类。

像这样的东西。我将type替换为typ,以避免使用反引号污染代码。

import play.api.libs.json.Json

// let's just define all the structures you need
case class Coordinates(latitude: Double, longitude: Double)

abstract class GeoObject {
  def typ: String
  def name: String
  def coordinates: Coordinates
}

val CityType = "city"
val CountryType = "country"

case class City(name: String, coordinates: Coordinates) extends GeoObject {
  val typ = CityType
}

case class Country(name: String, coordinates: Coordinates) extends GeoObject {
  val typ = CountryType
}

// case class representing json
case class GeoObjectJson(typ: String, name: String, lat: Double, long: Double)
implicit val geoObjectJsonReads = Json.reads[GeoObjectJson]

// companion object (as a factory)
object GeoObject {

  def apply(geoJson: GeoObjectJson): GeoObject = {
    val coord = Coordinates(geoJson.lat, geoJson.long)
    geoJson.typ match {
      case CityType => City(geoJson.name, coord)
      case CountryType => Country(geoJson.name, coord)
    }
  }
}
// tests

val cityJsonString = """{"typ":"city", "name": "New York", "lat": 40.77, "long": -73.92}"""
val cityJson = Json.parse(cityJsonString).as[GeoObjectJson]
val cityGeoObject = GeoObject(cityJson)
// City(New York,Coordinates(40.77,-73.92))
val countryJsonString = """{"typ":"country", "name": "Canada", "lat": 40.77, "long": -73.92}"""
val countryJson = Json.parse(countryJsonString).as[GeoObjectJson]
val countryGeoObject = GeoObject(countryJson)
// Country(Canada,Coordinates(40.77,-73.92))