Play JSON reads:读取值,可以多种形式呈现
Play JSON Reads: read value which can be presented in multiple types
我有 JSON ship
:
{
"name" : "Watership Elizbeth",
"sea": "white",
"size": 100500,
"residents" : [ {
"type" : "men",
"age" : 4,
"sex": 0
}, {
"type" : "cat",
"legs" :4,
"color" : "black",
"leg1" :{
"color" : "black"
},
"leg2" :{
"color" : "white"
},
"leg3" :{
"color" : "brown"
},
"leg4" :{
"color" : "black"
}
},{
"type" : "bird",
"size" : "XXL",
"name": "ostrich"
}, {"type": "water",...}, {"type": "mice",...}, {...}]
}
如您在 JsArray residents
中所见,我有不同的居民:men
、cat
、bird
、...water
。 .. ship
的所有居民在 Scala 代码中都有自己的简单案例 classes:
case class Men (type: String, age: Int, sex: Int)
case class Leg (color: String)
case class Cat (type: String, legs: Int, color: String, leg1: Leg, leg2: Leg, leg3: Leg, leg4: Leg)
case class Bird (...)
同样对于每个简单的案例 class 我在他们的伴随对象中写 readers
:
object Men {
implicit val reads: Reads[Ship] = (
(JsPath \ "type").read[String] and
(JsPath \ "age").read[Int] and
(JsPath \ "sex").read[Int]
)(Ship.apply _)
}
// and so on for another objects...
我找不到如何为 Ship
及其 reads
创建案例 class 的主要问题:
case class Ship (name: String, sea: String, size: Int, residents: Seq[???])
object Ship {
implicit val reads: Reads[Ship] = (
(JsPath \ "name").read[String] and
(JsPath \ "sea").read[String] and
(JsPath \ "size").read[Int] and
(JsPath \ "residents").read[Seq[???]]
)(Ship.apply _)
}
如您所见,residents
是数组,其元素可以是不同的类型:Men
、Cat
、Bird
..我想改为 ???
在读取 Ship
我类型的所有对象或类似`AnyVal 的对象时,但它不起作用:
// for case classes
case class Ship (name: String, sea: String, size: Int, residents: Seq[Man,Cat,Bird,...])
case class Ship (name: String, sea: String, size: Int, residents: Seq[AnyVal])
// for case reads
(JsPath \ "residents").read[Seq[Man,Cat,Bird,...]]
(JsPath \ "residents").read[Seq[AnyVal]]
如何写case class Ship
及其reads
可以读入其key的多种类型?
最简单的方法是从密封特征扩展所有大小写 类。这样play-json可以自动生成一个Reads:
sealed trait Resident
case class Men (age: Int, sex: Int) extends Resident
case class Leg (color: String) extends Resident
case class Cat (legs: Int, color: String, leg1: Leg, leg2: Leg, leg3: Leg, leg4: Leg) extends Resident
case class Bird (...) extends Resident
object Resident {
private val cfg = JsonConfiguration(
discriminator = "type",
typeNaming = JsonNaming { fullName =>
fullName
.replaceFirst(".*[.]", "")
.toLowerCase
}
)
implicit val reads = Json.configured(cfg).reads[Resident]
}
case class Ship (name: String, sea: String, size: Int, residents: Seq[Resident])
object Ship {
implicit val reads: Reads[Ship] = Json.reads[Ship]
}
Here 是一个完整的例子。
我有 JSON ship
:
{
"name" : "Watership Elizbeth",
"sea": "white",
"size": 100500,
"residents" : [ {
"type" : "men",
"age" : 4,
"sex": 0
}, {
"type" : "cat",
"legs" :4,
"color" : "black",
"leg1" :{
"color" : "black"
},
"leg2" :{
"color" : "white"
},
"leg3" :{
"color" : "brown"
},
"leg4" :{
"color" : "black"
}
},{
"type" : "bird",
"size" : "XXL",
"name": "ostrich"
}, {"type": "water",...}, {"type": "mice",...}, {...}]
}
如您在 JsArray residents
中所见,我有不同的居民:men
、cat
、bird
、...water
。 .. ship
的所有居民在 Scala 代码中都有自己的简单案例 classes:
case class Men (type: String, age: Int, sex: Int)
case class Leg (color: String)
case class Cat (type: String, legs: Int, color: String, leg1: Leg, leg2: Leg, leg3: Leg, leg4: Leg)
case class Bird (...)
同样对于每个简单的案例 class 我在他们的伴随对象中写 readers
:
object Men {
implicit val reads: Reads[Ship] = (
(JsPath \ "type").read[String] and
(JsPath \ "age").read[Int] and
(JsPath \ "sex").read[Int]
)(Ship.apply _)
}
// and so on for another objects...
我找不到如何为 Ship
及其 reads
创建案例 class 的主要问题:
case class Ship (name: String, sea: String, size: Int, residents: Seq[???])
object Ship {
implicit val reads: Reads[Ship] = (
(JsPath \ "name").read[String] and
(JsPath \ "sea").read[String] and
(JsPath \ "size").read[Int] and
(JsPath \ "residents").read[Seq[???]]
)(Ship.apply _)
}
如您所见,residents
是数组,其元素可以是不同的类型:Men
、Cat
、Bird
..我想改为 ???
在读取 Ship
我类型的所有对象或类似`AnyVal 的对象时,但它不起作用:
// for case classes
case class Ship (name: String, sea: String, size: Int, residents: Seq[Man,Cat,Bird,...])
case class Ship (name: String, sea: String, size: Int, residents: Seq[AnyVal])
// for case reads
(JsPath \ "residents").read[Seq[Man,Cat,Bird,...]]
(JsPath \ "residents").read[Seq[AnyVal]]
如何写case class Ship
及其reads
可以读入其key的多种类型?
最简单的方法是从密封特征扩展所有大小写 类。这样play-json可以自动生成一个Reads:
sealed trait Resident
case class Men (age: Int, sex: Int) extends Resident
case class Leg (color: String) extends Resident
case class Cat (legs: Int, color: String, leg1: Leg, leg2: Leg, leg3: Leg, leg4: Leg) extends Resident
case class Bird (...) extends Resident
object Resident {
private val cfg = JsonConfiguration(
discriminator = "type",
typeNaming = JsonNaming { fullName =>
fullName
.replaceFirst(".*[.]", "")
.toLowerCase
}
)
implicit val reads = Json.configured(cfg).reads[Resident]
}
case class Ship (name: String, sea: String, size: Int, residents: Seq[Resident])
object Ship {
implicit val reads: Reads[Ship] = Json.reads[Ship]
}
Here 是一个完整的例子。