我正在尝试以下列格式阅读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类。
答案 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
以始终转换为City
或Country
,但您可以使用您想要的任何功能。
编辑:我继续使用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))