Java有哪些好用的设计契约库?

47

几年前,我曾对Java的设计按契约编程(DbC)软件包进行了调查,但是我对它们中的任何一个都不太满意。不幸的是,我没有记录下详细的研究结果,而且我认为现在情况已经发生了变化。是否有人愿意比较和对比Java中的不同DbC软件包呢?

10个回答

24

维基百科关于设计契约的概述中,有一个关于第三方支持库语言的部分,其中包括了一系列不错的Java库。这些Java库大多基于Java断言。

如果您只需要前置条件检查,那么也有一个轻量级的验证方法参数解决方案,可在SourceForge下的Java参数验证(普通Java实现)找到。

根据您的问题,也许对于字段/属性约束验证来说,OVal框架是个不错的选择。该框架使您可以以各种不同形式(注释、POJO、XML)放置约束。通过POJO或脚本语言(JavaScript、Groovy、BeanShell、OGNL、MVEL)创建自定义约束。它还部分实现了编程契约


OVal看起来很不错。我敢说它是Java中最好的DbC实现。 - Chris Jones
9
我不确定在这里发表评论是最好的方式,但只是为了让下一个阅读者知道:Contracts for Java - cofoja 是直接来自 Google 的 20% 时间研究的最新补充。 - superjos

6

谷歌有一个名为Java合约的开源库。

Contracts for Java is our new open source tool. Preconditions, postconditions, and invariants are added as Java boolean expressions inside annotations. By default these do nothing, but enabled via a JVM argument, they’re checked at runtime.

@Requires, @Ensures, @ThrowEnsures and @Invariant specify contracts as Java boolean expressions
• Contracts are inherited from both interfaces and classes and can be selectively enabled at runtime

Java 合约


2

我强烈建议您考虑使用Java建模语言(JML)。


2
有一个Groovy扩展可以在Groovy / Java代码中启用按合同设计(Design by Contract) - GContracts。它使用所谓的闭包注释来指定类不变量、前置条件和后置条件。示例可以在项目的Github维基上找到。
主要优点:它只是一个单独的JAR文件,没有外部依赖项,并且可以通过符合Maven的存储库解决,因为它已被放置在中央Maven存储库中。

我认为我们不能在Java项目中使用GContracts,因为GContracts大量使用Groovy闭包。 - Sudarshan
没错,这是一个仅限Groovy的库。 - Andre Steingress

2
我曾经测试过contract4J,发现它可用但不完美。你需要为方法的调用前和调用后以及整个类中的不变量创建合约。 合约被创建为方法断言。问题在于合约本身是以字符串形式编写的,因此你无法获得IDE支持合约或编译时检查合约是否仍然有效。 这里是链接到库的地址

2

我已经很久没有看过这些东西了,但是找到了一些旧链接。其中一个是关于JASS的。

另一个我曾经使用并喜欢的是可靠系统的iContract。它有一个ant任务,你可以将其作为预处理器运行。然而,通过一些谷歌搜索,我似乎找不到它,看起来它已经消失了。原始网站现在是一个链接农场。请查看此链接以获取可能访问它的方法。


JASS最新版本是2005年7月发布的。我不会猜测它支持哪些JDK版本。不过,JASS有一个指向JML的链接,看起来正在积极开发中。 - Chris Jones

1
我建议使用几种工具的组合:
  • 如果你只需要在“主”或“测试”代码中进行简单检查,那么可以使用Java的assert condition...,或者更先进的Groovy版本Guava的Preconditions.checkXXXX(condition...)Verify.verify(condition...),或者像AssertJ这样的库。

  • 如果您需要更多功能,则可以使用OVal等工具;它可以检查对象以及方法参数和结果,您还可以手动触发检查(例如,在调用方法之前显示验证错误)。它可以理解现有的注释,例如来自JPA或javax.validation(如@NotNull@Pattern@Column),或者您可以编写内联约束,例如@Pre(expr="x >= 0 && x <= y")。如果注释是@Documented,则检查也将在Javadocs中可见(您不必在那里描述它们)。

  • OVal使用反射,这可能会在某些环境(如Android)中导致性能问题和其他问题;那么您应该考虑使用Google's Cofoja这样的工具,它具有较少的功能,但依赖于编译时注释处理工具而不是反射。


1
如果您想要一个简单明了的基本支持来表达您的合同,请查看valid4j(在Maven Central上找到为org.valid4j:valid4j)。它允许您使用普通代码中的正则hamcrest-matchers表达您的合同(没有注释或评论)。
对于前置条件和后置条件(基本上是断言 -> 抛出AssertionError):
import static org.valid4j.Assertive.*;

require(inputList, hasSize(greaterThan(0)));
...
ensure(result, lessThan(4.0));

如果您不满意默认的全局策略(抛出AssertionError),valid4j提供了一种自定义机制,让您提供自己的org.valid4j.AssertiveProvider实现。
链接:

有人有这个比较的电子表格吗?一个功能矩阵会很棒。 - Rıfat Erdem Sahin
valid4j看起来更像是一个断言库(就像Java流行的AssertJ或Groovy的高级assert),而不是像OVal或Cofoja这样的完整DBC工具。 - iirekm

0

我个人认为目前可用的 DbC 库还有很多需要改进的地方,我查看过的库中没有一个能够很好地与 Bean Validation API 兼容。

我查看过的库的文档在 这里

Bean Validation API 与 DbC 的概念有很多重叠。在某些情况下,Bean Validation API 不能像简单的 POJO(非 CDI 管理的代码)那样使用。在我看来,围绕 Bean Validation API 的简单包装器就足够了。

我发现现有的库有点棘手,因为它们是通过 AOP 或字节码插装实现的,难以添加到现有的 Web 项目中。也许随着 Bean Validation API 的出现,实现 DbC 的这种复杂性是不必要的。

我还在 这篇文章 中记录了我的抱怨,并希望构建一个利用 Bean Validation API 的小型库。


0

我认为自从Java 1.4引入了内置的assert关键字后,许多DbC库都被超越了:

  • 它是内置的,不需要其他库
  • 它可以与继承一起使用
  • 您可以按包基础激活/停用
  • 易于重构(例如,注释中没有断言)

4
在http://java.sun.com/javase/6/docs/technotes/guides/language/assert.html中,SUN写道:“不要使用断言来检查公共方法的参数”。 - user85421
5
更重要的是,DbC应该使向代码添加契约变得容易。如果不容易,大多数开发者都不会这样做。可以使用断言和调用类不变式方法来实现类不变式,但这样做略显笨拙。 - Chris Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接