scala - 在使用 scala 的版本化配置的情况下,如何将解析与验证分开?

标签 scala validation serialization version scala-cats

背景

我有一组配置 JSON 文件,如下所示:

{
  "version" : 1.0,
  "startDate": 1548419535,
  "endDate": 1558419535,
  "sourceData" : [...]  // nested json inside the List.
  "destData" : [...]    // nested json inside the List.
  "extra" : ["business_type"]
}

有几个这样的配置文件。它们是固定的,仅驻留在我的代码目录中。每个配置文件的内部表示由我的案例类 Config 给出:
case class Attribute(name: String, mappedTo: String)

case class Data(location: String, mappings:List[Attribute])

case class Config(version: Double, startDate: Long, endDate: Long, sourceData: List[Data],
                  destData: List[Data], extra: List[String])

我有三个类(class)Provider , ParserValidator .
  • Provider有一个方法 getConfig(date: Long): Config .它必须返回满足 startDate <= date <= endDate 的配置(理想情况下应该只存在一个这样的配置,因为 startDateendDate 定义了要返回的配置版本)。
  • getConfig调用内部的方法 ParserparseList(jsonConfigs: List[String]): Try[List[Config]] .什么 parseList做的是尝试反序列化列表中的所有配置,每个配置到案例类 Config 的一个实例.即使一个 JSON 无法反序列化 parseList返回 scala.util.Failure否则返回 scala.util.Success[List[Config]] .
  • scala.util.Success[List[Config]]从上一步返回,getConfig然后最后调用内部的一个方法 Validatordef validate(List[Config], Date): ValidationResult[Config] ,并返回它的结果。由于我希望累积所有错误,因此我正在使用 Cats Validated用于验证。我什至问了一个关于它正确用法的问题 here .
  • validate执行以下操作:
    检查是否正好 Config在列表中,适用于给定的
    date ( startDate <= date <= endDate ) 然后对该 Config 执行一些验证(否则返回 invalidNel )。我对 Config 执行了一些基本验证例如检查各种列表和字符串是否为非空等。我还执行一些语义验证,例如检查字段 extra 中的每个字符串存在于 mappings每个source/dest Data


  • 最近几天困扰我的问题是,我使用 Cats Validated 的目的是什么?只是为了收集所有错误(并且在遇到第一个验证错误时不会快速失败)。但是当我到达时validate方法我已经在 parseList 中做了某种验证方法。也就是说,我已经在parseList中验证过了我的 JSON 结构符合我的案例类 Config .但是我的parseList不会像我的 validate 那样累积错误方法。因此,如果我的 json 结构和我的案例类之间存在许多不兼容性 Config在场我只会了解第一个。但我想一次性了解他们。
  • 如果我开始添加 require 会变得更糟条款如 nonEmpty仅在案例类内部(它们将在案例类的构建时被调用,即在解析自身时),例如
    case class Data(location: String, mappings: List[Attribute]) {
      require(location.nonEmpty)
      require(mappings.nonEmpty)
    }
    

  • 所以我无法正确地在解析和验证功能之间划清界限。
  • 我想到的一种解决方案是放弃我正在使用的当前 JSON 库 ( lift-json ) 并使用 play-json反而。它具有累积错误的功能,例如 Cats Validated (我知道它 here ,非常适合 Cats invalidNel )。我以为我会先解析 JSON 到 play-json 的 JSON AST JsValue , 在 JsValue 之间执行结构兼容验证和我的 Config使用 play-jsons validate方法(它会累积错误)。如果它很好读 Config案例类来自 JsValue并使用 Cats 执行我上面给出的示例的后续验证。
  • 但是我需要解析所有配置以查看哪个配置适用于给定日期。即使一个配置无法反序列化,我也不会继续。如果所有反序列化成功,我会选择一个 (startDate, endDate)附上给定的日期。所以如果我按照我上面提到的解决方案,我已经推送了 List[JsValue] 的转换至 List[Config]到验证阶段。现在如果每个 JsValue在列表中成功反序列化为 Config例如,我可以选择适用的一个,对其执行更多验证并返回结果。但如果有些 JsValue无法反序列化我该怎么办?我应该返回他们的错误吗?看起来不直观。这里的问题是我需要解析所有配置以查看哪个配置适用于给定日期。这让我更难区分解析和验证阶段。

  • 如何在我的场景中解析和验证配置之间划清界限?我是否更改了维护版本的方式(版本从开始日期到结束日期都有效)?

    PS:总的来说,我是一个非常新手的程序员。如果我的问题很奇怪,请原谅我。我自己从没想过我会在学习 Scala 的同时花这么多时间在验证上。

    最佳答案

    Checks if exactly one Config in the List matches 
    

    如果所描述的行为是要求,则格式错误的 JSON 文件是一个验证错误。您可以将 Try[List[]] 返回类型更改为 List[Try[]] 并在必要时将其与 Validated 集成。该文档可能有使用 std lib 类的便捷方法。

    如果我们可以取第一个匹配的,那就是早午餐:进行相同的更改,只需在查找配置时在列表中找到匹配的第一个即可。

    关于scala - 在使用 scala 的版本化配置的情况下,如何将解析与验证分开?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54366991/

    相关文章:

    scala - Queue.foreach 是否正确排序?

    scala - Akka actor并发问题

    validation - 在Grails中,如何在电子邮件验证程序约束中允许使用更新的DNS?

    php - 在 Woocommerce 注册表中添加一个字段并在管理员中编辑用户

    serialization - WF 自定义 SQL 跟踪服务停止为旧工作流工作?

    java - Gson 序列化多态对象列表

    scala - 使用 case 类的伴随对象作为类型参数时编译错误

    scala - 为什么 Scala REPL 没有列出使用 TAB 补全时的所有可能性?

    c# - 一个列表中多个对象类型的Xml序列化

    javascript - 屏蔽和 AJAX 请求