【问题标题】:Use a custom type parameter to auto map a JSON response使用自定义类型参数自动映射 JSON 响应
【发布时间】:2017-11-29 06:06:13
【问题描述】:

我可以将自定义类型作为参数传递给方法并使用它从外部 API读取 JSON 吗?所以如果我有这个:

trait ApiInfo
case class SunInfoResults(sunrise: String, sunset: String, solar_noon: String, day_length: Long, civil_twilight_begin: String, civil_twilight_end: String, nautical_twilight_begin: String, nautical_twilight_end: String, astronomical_twilight_begin: String, astronomical_twilight_end: String)
case class SunInfo(results: SunInfoResults, status: String) extends ApiInfo
case class TvInfo(url: String, name: String, gender: String, culture: String, born: String, died: String, titles: Array[String], aliases: Array[String], father: String, mother: String, spouse: String, allegiances: Array[String], books: Array[String], povBooks: Array[String], tvSeries: Array[String], playedBy: Array[String]) extends ApiInfo

在对外部 API 进行服务调用之前,我需要声明一个隐式序列化 JSON。那么我将如何指定需要映射到的类(使用JSON automated mapping in Play 2.5)?我确信这一定是可能的,因为 Scala 是建立在减少重复代码的概念之上的——如果没有这样的解决方案,我将不得不这样做。这是我在将任何自定义类型传递到时遇到的问题:

implicit val infoReads = Json.reads[p] // where p is SunInfo or TvInfo

只是在对类型主题进行了一些研究后也包括在内;我想知道我是否必须使用phantom types,因为该类在正确映射到 JSON 响应之前不会被实例化。

【问题讨论】:

    标签: json scala playframework json-deserialization jsonreader


    【解决方案1】:

    我想我理解您的问题,否则请告诉我:Play 无法自动映射 InfoReads,因为它缺少用于其中一种属性类型 SunInfoResults 的 Json 转换器?

    Play JSON API 为大多数基本类型(int、boolean)提供隐式读/写。要将您自己的模型与 JsValues 相互转换,您必须定义隐式读取和写入转换器并在范围内提供它们。因此,如果您将 Automated Conversion 用于 SunInfo

    implicit val sunInfoReads: Reads[SunInfo] = Json.reads[SunInfo]
    

    只要您在范围内为自定义数据类型SunInfoResults 定义了隐式Reads,Play 就可以读取属性results: SunInfoResults

    implicit val sunInfoResultsReads: Reads[SunInfoResults] = Json.reads[SunInfoResults]
    

    如果我不需要定义任何自定义读/写或添加验证,我通常会在案例类的伴随对象中使用格式化程序,它会自动导入到使用 SunInfoResult 的范围中:

    case class SunInfoResults(sunrise: String, sunset: String, solar_noon: String, day_length: Long, civil_twilight_begin: String, civil_twilight_end: String, nautical_twilight_begin: String, nautical_twilight_end: String, astronomical_twilight_begin: String, astronomical_twilight_end: String)
    
    object SunInfoResults {
      implicit val sunInfoResultsFormat = Json.format[SunInfoResults]
    }
    

    【讨论】:

    • 谢谢。是的 - Json.reads[SunInfoResults] 需要在 Json.reads[SunInfo] 之前隐式声明,但我仍然无法将类引用传递给隐式以避免重复,即 Json.reads[p] - p 是 SunInfo 或 TvInfo。正如我在对原始问题的编辑中提到的,我现在想知道是否必须使用幻像类型 - ktoso.github.io/scala-types-of-types/#phantom-type - 因为该类在正确映射到 JSON 响应之前不会被实例化
    • 所以目标是不必在每次使用自定义数据类型时都在范围内定义隐式?
    • 是的 - 如果可能的话!
    • 将读取和写入添加到案例类的伴随对象中——如我上面的示例和这篇文章中所示:stackoverflow.com/a/36952218/3384225 请参阅“这样,每当您导入 Resident,它的写入将在隐式范围内。”
    猜你喜欢
    • 2011-03-05
    • 2014-01-21
    • 1970-01-01
    • 2014-03-04
    • 1970-01-01
    • 2019-01-25
    • 2012-12-23
    • 2018-08-23
    • 2021-11-15
    相关资源
    最近更新 更多