校验与分解
JSR 303不处理数据的整理与分解。 他只是对类实例的校验。出于测试目的,我使用Jackson来将Json数据分解为类实例。但问题是,校验时分解的一部分。我们很难在没有检查JSon结构前提下将JSON树转化为类实例。 "age"属性存在吗?它是Integer类型的吗? 考虑到这点,Java 工作流看起来很奇怪。当处理Json时你实际上需要处理3中类型的错误:
JSR-303仅仅帮助你处理后者。
这个AIP同样强制你直接使用不合法的实例。我认为如果一个类实例不合法,你最初就不应该创建它。
难以扩展API
Hibernate校验程序需要手动添加一些列校验规则(如邮件,长度,非空等)。那如果你需要创建新的校验约束条件(比如从hibernate文档中的例子),你该怎么办? 01 | @Target ( { METHOD, FIELD, ANNOTATION_TYPE }) |
03 | @Constraint (validatedBy = CheckCaseValidator. class ) |
05 | public @interface CheckCase { |
06 | String message() default "{com.mycompany.constraints.checkcase}" ; |
07 | Class<?>[] groups() default {}; |
08 | Class<? extends Payload>[] payload() default {}; |
12 | public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> { |
14 | private CaseMode caseMode; |
16 | public void initialize(CheckCase constraintAnnotation) { |
17 | this .caseMode = constraintAnnotation.value(); |
20 | public boolean isValid(String object, ConstraintValidatorContext constraintContext) { |
24 | if (caseMode == CaseMode.UPPER) |
25 | return object.equals(object.toUpperCase()); |
27 | return object.equals(object.toLowerCase()); |
那是大约 25 行代码。21 行基本上是固定的,所谓纯“仪式性”的。有趣的部分仅仅是:
1 | if (caseMode == CaseMode.UPPER) |
2 | return object.equals(object.toUpperCase()); |
4 | return object.equals(object.toLowerCase()); |
我们如何使用统一的校验API进行扩展相同的内容呢? 1 | def checkCase(caseMode: CaseMode) = validateWith( "constraints.checkcase" ) { (s: String) => |
2 | if (caseMode == CaseMode.UPPER) |
是的,这里只有6行代码。我有自信任何人都可以理解它。
Scala福利: 易于并行 作为一个小福利,既然Scala API只是用不可变的数据结构,那么它就是线程安全的。Scala 提供并行集合。让我们花5分钟改一些最初的代码,我提出了一个发挥我多核处理器最大性能的版本。
时间校验API测定Hibernate validator的基准点 - invalids Hibernate validator Unified - invalids Unified Unified w/ par - invalids Unified w/ par 5000 6000 7000 8000 9000 10000 0k 1k 2k 3k 4k 5k Highcharts.com
这一版本比Java的快了5倍。
结论
我认为这篇文章的观点相当明显。当提到选择一个库或者一门语言时,基准测试毫无用处。一个正确实现的算法总是能被优化。一个失败的实现就是失败了。
这一特殊的实例证明即使Scala有一些开销,但是它优秀的设计使得创建一些相比Java不仅简单而且高效的库称为可能。
你可以阅读 这篇文章 来了解更多关于unified API或者从这里检出代码.
现在,如果你有一个min规则,一个max规则,我想创建一个between规则,该怎么做?这很简单,规则组合。
1 | def between(lower: Int, upper: Int) = min(lower) |+| max(upper) |
然而在Java中呢?好吧,我连写这些代码都不想写。这肯定会冗长并且乏味。 |