Skip to content

cowwoc/requirements.java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

f889201 · Mar 10, 2025
Mar 2, 2025
Mar 2, 2025
Feb 18, 2025
Feb 18, 2025
Dec 8, 2024
Feb 14, 2025
Feb 18, 2025
Feb 18, 2025
Feb 18, 2025
Feb 18, 2025
Feb 12, 2024
Feb 18, 2025
Mar 26, 2020
Oct 26, 2021
Feb 18, 2025
Mar 10, 2025
Mar 2, 2025
Mar 2, 2025
Mar 2, 2025

Repository files navigation

checklist Requirements API

build-status Maven Central
API Changelog javascript, typescript

A fluent API for enforcing design contracts with automatic message generation:

✔️ Easy to use
✔️ Fast
✔️ Production-ready

To get started, add this Maven dependency:

<dependency>
  <groupId>com.github.cowwoc.requirements</groupId>
  <artifactId>requirements-java</artifactId>
  <version>11.0</version>
</dependency>

Usage Example

import java.util.List;
import java.util.StringJoiner;

import static com.github.cowwoc.requirements10.java.DefaultJavaValidators.checkIf;
import static com.github.cowwoc.requirements10.java.DefaultJavaValidators.requireThat;
import static com.github.cowwoc.requirements10.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<String> getFailures()
  {
    return checkIf(bitesTaken, "bitesTaken").isNotNegative().
      and(checkIf(piecesLeft, "piecesLeft").isGreaterThan(3)).
      elseGetMessages();
  }
}

If you violate a precondition:

Cake cake = new Cake(-1000);

You'll get:

java.lang.IllegalArgumentException: "piecesLeft" must be positive.
actual: -1000

If you violate a class invariant:

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:

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:

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:

Entry Points

Designed for discovery using your favorite IDE's auto-complete feature. The main entry points are:

See the API documentation for more details.

Best practices

  • Use checkIf().elseGetMessages() 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:

Licenses