【问题标题】:Play JSON Reads: read value which can be presented in multiple typesPlay JSON Reads:读取值,可以多种类型呈现
【发布时间】:2020-02-20 08:58:51
【问题描述】:

我有 ship 这样的 JSON:

{
  "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 中看到的,我有不同的居民:mencatbird、...water、...ship 的所有居民都有自己的简单Scala 代码中的案例类:

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 (...)

对于每个简单的案例类,我都会在它们的伴随对象中写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 创建案例类的主要问题:

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 是数组,其中元素可以是不同的类型:MenCatBird.. 我想改为 ??? 读取 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类Ship和它的reads可以读入它的key多种类型?

【问题讨论】:

    标签: json scala playframework play-json


    【解决方案1】:

    最简单的方法是从一个密封特征扩展所有案例类。这样 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 是一个完整的例子。

    【讨论】:

      猜你喜欢
      • 2014-07-26
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2020-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多