Json Scalaz验证的错误累积

Json Scalaz验证的错误累积,json,scala,playframework,scalaz,play-json,Json,Scala,Playframework,Scalaz,Play Json,我有一个复杂的JSON,它保存在数据库中。其复杂性在“块”中“隔离”,如下所示: val block1 = Json.parse(block1).validate[Block1].get val block2 = Json.parse(block2).validate[Block2].get ... 整个JSON: { "block1" : { "param1" : "val1", "param2" : "val2" }, "block2

我有一个复杂的JSON,它保存在数据库中。其复杂性在“块”中“隔离”,如下所示:

val block1 = Json.parse(block1).validate[Block1].get
val block2 = Json.parse(block2).validate[Block2].get
...
整个JSON:

{
    "block1" : {
        "param1" : "val1",
        "param2" : "val2"
    },
    "block2" : {
        "param3" : "val3",
        "param4" : "val4"
    },
    ...
}
在数据库中,每个块都单独存储和处理:

持久化块

"block1" : {
    "param1" : "val1",
    "param2" : "val2"
}

"block2" : {
    "param3" : "val3",
    "param4" : "val4"
}
每个块都有业务含义,因此,每个块都映射到一个case类。 我正在构建一个PlayAPI来存储、更新和检索这个JSON结构,我想验证是否有人为了完整性而修改了它的数据

我对每个块进行检索(解析和验证),如下所示:

val block1 = Json.parse(block1).validate[Block1].get
val block2 = Json.parse(block2).validate[Block2].get
...
案例类别:

trait Block
sealed case class Block1 (param1: String, param2: String, ...) extends Block
sealed case class Block2 (param3: String, param4: String, ...) extends Block
sealed case class Request (block1: Block1, block2: Block2, ...)
在当前结构中,如果某个字段被更改,并且与为其定义的类型不匹配,则Play会引发此异常:

[NoSuchElementException:JsError.get]

因此,我想用Scalaz和验证构建一个累积错误结构,以捕获所有可能的解析和验证错误。我已经看过了,所以我将验证编码为:

def build(block1: String, block2: String, ...): Validation[NonEmptyList[String], Request] = {
    val block1 = Option(Json.parse(block1).validate[Block1].get).toSuccess("Error").toValidationNel
    val block2 = Option(Json.parse(block2).validate[Block2].get).toSuccess("Error").toValidationNel
    ...

    val request = (Request.apply _).curried

    blockn <*> (... <*> (... <*> (...<*> (block2 <*> (block1 map request)))))   
}
def构建(block1:String,block2:String,…):验证[NonEmptyList[String],请求]={
val block1=Option(Json.parse(block1).validate[block1].get.toSuccess(“Error”).toValidationNel
val block2=Option(Json.parse(block2).validate[block2].get.toSuccess(“Error”).toValidationNel
...
val request=(request.apply 41;.curried
blockn(…(…(…(block2(block1映射请求‘‘)’))
}
请注意,我使用的是applicative functor
,因为
请求
有20个字段(构建的语法中有一个括号),
@
applicative functor只适用于最多12个参数的case类

这段代码适用于快乐路径,但是,当我修改一些field Play时,会抛出后面描述的执行异常

问题:我想积累Play在解析每个块时可以检测到的所有可能的结构错误。我该怎么做


<强>注< <强>:如果在某种程度上与此有关,我将开放使用它(我已经使用它)。

如果多验证是向项目添加Salasz的唯一原因,那么为什么不考虑一个替代方案,这将不需要使您的播放项目适应Salasz强迫您解决问题的单向方式。(这可能是一件好事,但如果唯一的原因是多重验证,则未必如此)

而应考虑使用标准Scala方法,使用代码> Scala。UTI.Test< /C> >:

val block1 = Try(Json.parse(block1).validate[Block1].get)
val block2 = Try(Json.parse(block2).validate[Block2].get)
...

val allBlocks : List[Try[Block]] = List(block1, block2, ...)
val failures : List[Failure[Block]] = allBlocks.collect { case f : Failure[Block] => f }

通过这种方式,您仍然可以对标准scala集合进行操作,以检索要进一步处理的故障列表。此外,这种方法不会在块数方面限制您。

为什么是否定的?这难道不是对“问题:我想累积在解析每个blo时播放可以检测到的所有可能的结构故障”的回答吗ck.我该怎么做?“?我不是那个对你的答案投反对票的人。事实上,我认为你关于使用标准Try而不是Scalaz验证的想法是完全正确的,但我有一个问题:你为什么说“…如果唯一的原因是多重验证”?是否存在“潜在的误用”如果我只使用验证,Scalaz会怎么样?我见过很多项目,其中Scalaz主要用于验证功能,所以我想不能将其归类为“误用”。这里的问题是学习曲线陡峭,缺乏良好的文档。Scalaz规模庞大,功能强大,决定将其嵌入到系统中考虑到未来的代码维护和新开发人员的加入是多么容易,应该是有意识的。同时,它促进了某种编码和构造风格,而这不一定是标准Scala中所要做的。因此,我的回答提供了另一种选择:)嗯,我认为我“设计过度”那么,我的问题的解决方案。我试试你的方法