https://github.com/cowwoc/requirements.java
Fluent Design Contracts for Java Projects
https://github.com/cowwoc/requirements.java
design-by-contract invariants java postconditions preconditions requirements
Last synced: 9 months ago
JSON representation
Fluent Design Contracts for Java Projects
- Host: GitHub
- URL: https://github.com/cowwoc/requirements.java
- Owner: cowwoc
- License: apache-2.0
- Created: 2020-03-22T15:21:23.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2025-08-28T03:48:56.000Z (10 months ago)
- Last Synced: 2025-08-28T10:32:47.167Z (10 months ago)
- Topics: design-by-contract, invariants, java, postconditions, preconditions, requirements
- Language: Java
- Homepage:
- Size: 9.78 MB
- Stars: 27
- Watchers: 1
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Support: docs/supported_libraries.md
Awesome Lists containing this project
README
#
Requirements API
[](../../actions?query=workflow%3ABuild)
[](https://central.sonatype.com/search?q=g:io.github.cowwoc.requirements)
[](https://cowwoc.github.io/requirements.java/12.0/)
[](docs/changelog.md)
[](../../../requirements.js)
A [fluent API](https://en.wikipedia.org/wiki/Fluent_interface) for
enforcing [design contracts](https://en.wikipedia.org/docs/Design_by_contract) with
[automatic message generation](docs/features.md#automatic-message-generation):
✔️ Easy to use
✔️ Fast
✔️ Production-ready
To get started, add this Maven dependency:
```xml
io.github.cowwoc.requirements
requirements-java
12.0
```
## Usage Example
```java
import java.util.List;
import java.util.StringJoiner;
import static io.github.cowwoc.requirements12.java.DefaultJavaValidators.checkIf;
import static io.github.cowwoc.requirements12.java.DefaultJavaValidators.requireThat;
import static io.github.cowwoc.requirements12.java.DefaultJavaValidators.that;
public final class Cake
{
private byte bitesTaken = 0;
private int piecesLeft;
public Cake(int piecesLeft)
{
requireThat(piecesLeft, "piecesLeft").isPositive();
this.piecesLeft = piecesLeft;
}
public int eat()
{
++bitesTaken;
assert that(bitesTaken, "bitesTaken").isNotNegative().elseThrow();
piecesLeft -= ThreadLocalRandom.current().nextInt(5);
assert that(piecesLeft, "piecesLeft").isNotNegative().elseThrow();
return piecesLeft;
}
public List getFailures()
{
return checkIf(bitesTaken, "bitesTaken").isNotNegative().
and(checkIf(piecesLeft, "piecesLeft").isGreaterThan(3)).
elseGetFailures();
}
}
```
If you violate a **precondition**:
```java
Cake cake = new Cake(-1000);
```
You'll get:
```
java.lang.IllegalArgumentException: "piecesLeft" must be positive.
actual: -1000
```
If you violate a **class invariant**:
```java
Cake cake = new Cake(1_000_000);
while (true)
cake.eat();
```
You'll get:
```
java.lang.AssertionError: "bitesTaken" may not be negative.
actual: -128
```
If you violate a **postcondition**:
```java
Cake cake = new Cake(100);
while (true)
cake.eat();
```
You'll get:
```
java.lang.AssertionError: "piecesLeft" may not be negative.
actual: -4
```
If you violate **multiple** conditions at once:
```java
Cake cake = new Cake(1);
cake.bitesTaken = -1;
cake.piecesLeft = 2;
StringJoiner failures = new StringJoiner("\n\n");
for (String failure : cake.getFailures())
failures.add(failure);
System.out.println(failures);
```
You'll get:
```
"bitesTaken" may not be negative.
actual: -1
"piecesLeft" must be greater than 3.
actual: 2
```
## Features
This library offers the following features:
* [Automatic message generation](docs/features.md#automatic-message-generation) for validation failures
* [Diffs provided whenever possible](docs/features.md#diffs-provided-whenever-possible) to highlight the
differences between expected and actual values
* [Clean stack-traces](docs/features.md#clean-stack-traces) that remove unnecessary frames
* [Zero overhead when assertions are disabled](docs/features.md#assertion-support) for better performance
* [Multiple validation failures](docs/features.md#multiple-validation-failures) that report all the errors at
once
* [Nested validations](docs/features.md#nested-validations) that allow you to validate complex objects
* [String diff](docs/features.md#string-diff) that shows the differences between two strings
* [Performant and robust](docs/performance.md)
## Entry Points
Designed for discovery using your favorite IDE's auto-complete feature.
The main entry points are:
* [requireThat(value, name)](https://cowwoc.github.io/requirements.java/12.0/io.github.cowwoc.requirements.java/com/github/cowwoc/requirements12/java/DefaultJavaValidators.html#requireThat(T,java.lang.String))
for method preconditions.
* [that(value, name)](https://cowwoc.github.io/requirements.java/12.0/io.github.cowwoc.requirements.java/com/github/cowwoc/requirements12/java/DefaultJavaValidators.html#that(T,java.lang.String))
for [class invariants, method postconditions and private methods](docs/features.md#assertion-support).
* [checkIf(value, name)](https://cowwoc.github.io/requirements.java/12.0/io.github.cowwoc.requirements.java/com/github/cowwoc/requirements12/java/DefaultJavaValidators.html#checkIf(T,java.lang.String))
for multiple failures and customized error handling.
See the [API documentation](https://cowwoc.github.io/requirements.java/12.0/) for more details.
## Best practices
* Use `checkIf().elseGetFailures()` to return failure messages without throwing an exception.
This is the fastest validation approach, ideal for web services.
* To enhance the clarity of failure messages, you should provide parameter names, even when they are optional.
In other words, favor `assert that(value, name)` over `assert that(value)`.
## Third-party libraries and tools
This library supports the following third-party libraries and tools:
* [guava](docs/supported_libraries.md)
* [IntelliJ IDEA](docs/supported_tools.md)
## Licenses
* This library is licensed under the [Apache License, Version 2.0](LICENSE)
* See [Third party licenses](LICENSE-3RD-PARTY.md) for the licenses of the dependencies
* Icons made by Flat Icons from www.flaticon.com are licensed by CC 3.0 BY