diff --git a/README.md b/README.md
index c314fe75c..f6cecb080 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,12 @@
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.cowwoc.requirements/java/badge.svg)](https://search.maven.org/search?q=g:com.github.cowwoc.requirements)
[![build-status](../../workflows/Build/badge.svg)](../../actions?query=workflow%3ABuild)
-# Fluent API for Design Contracts
+# Requirements API
+## Fluent API for Design Contracts
[![API](https://img.shields.io/badge/api_docs-5B45D5.svg)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/)
[![Changelog](https://img.shields.io/badge/changelog-A345D5.svg)](docs/Changelog.md)
-[![js](https://img.shields.io/badge/other%20languages-js-457FD5.svg)](../../../requirements.js)
+[![javascript, typescript](https://img.shields.io/badge/other%20languages-javascript,%20typescript-457FD5.svg)](../../../requirements.js)
A [fluent API](https://en.m.wikipedia.org/docs/Fluent_interface) for enforcing
[design contracts](https://en.wikipedia.org/docs/Design_by_contract) with
@@ -20,21 +21,21 @@ To get started, add this Maven dependency:
```xml
- com.github.cowwoc.requirements
- java
- 9.0.0
+ com.github.cowwoc.requirements
+ java
+ 9.0.0
```
-You can learn about the API by using your IDE's auto-complete feature.
+`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/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#requireThat(T,java.lang.String))
-* [assumeThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#assumeThat(T,java.lang.String))
-* [checkIfThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#checkIf(T,java.lang.String))
-* [JavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/JavaValidators.html)
+* [requireThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#requireThat(T,java.lang.String)) for preconditions
+* [assumeThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#assumeThat(T,java.lang.String)) for postconditions and class invariants
+* [checkIfThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#checkIf(T,java.lang.String)) for multiple failures and everything else
+* [JavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/JavaValidators.html) for custom configurations
-The first three methods use a global configuration, while `JavaValidators` allows you to create a local
+The first three methods use a shared configuration, while `JavaValidators` allows you to create an independent
configuration.
See the [API documentation](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/) for more details.
@@ -48,23 +49,23 @@ import static com.github.cowwoc.requirements.java.DefaultJavaValidators.requireT
public final class HelloWorldTest
{
- public static void main(String[] args)
- {
- // Preconditions
- requireThat(args, "args").length().isPositive();
-
- // Class invariants or method postconditions
- assert assumeThat("args[0]", args[0]).isEqualTo("world").elseThrow();
-
- // Return multiple validation failures at once
- List messages = checkIf(args, "args").isEmpty().
- and(checkIf("args[0]", args[0]).isEqualTo("planet")).
- elseGetMessages();
- StringJoiner joiner = new StringJoiner("\n\n");
- for (String message : messages)
- joiner.add(message);
- System.out.println("Multiple failures\n" + joiner.toString());
- }
+ public static void main(String[] args)
+ {
+ // Preconditions
+ requireThat(args, "args").length().isPositive();
+
+ // Class invariants or method postconditions
+ assert assumeThat("args[0]", args[0]).isEqualTo("world").elseThrow();
+
+ // Return multiple validation failures at once
+ List messages = checkIf(args, "args").isEmpty().
+ and(checkIf("args[0]", args[0]).isEqualTo("planet")).
+ elseGetMessages();
+ StringJoiner joiner = new StringJoiner("\n\n");
+ for (String message : messages)
+ joiner.add(message);
+ System.out.println("Multiple failures\n" + joiner.toString());
+ }
}
```
@@ -102,7 +103,7 @@ This library offers the following features:
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) compared to other validation libraries
+* [Performant and robust](docs/Performance.md)
## Getting Started
@@ -112,16 +113,12 @@ The main entry points you should be aware of are:
* [requireThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#requireThat(T,java.lang.String))
* [assumeThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#assumeThat(T,java.lang.String))
* [checkIfThat(value, name)](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultJavaValidators.html#checkIf(T,java.lang.String))
-* [JavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/JavaValidators.html)
-The three static methods share a global configuration.
-`JavaValidators` contains a local configuration, which is useful if you want to use different configuration at
-once.
+The three static methods share the same configuration.
+To create an independent configuration, use [JavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/JavaValidators.html).
See the [API documentation](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/) for more details.
-## Performance Tips
-
## Best practices
* Use `requireThat()` to verify the preconditions of public APIs.
@@ -136,7 +133,7 @@ See the [API documentation](https://cowwoc.github.io/requirements.java/9.0.0/doc
## Third-party libraries and tools
-This library supports the following 3rd-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)
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 7f96713c1..de239891a 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -11,20 +11,23 @@ See https://github.com/cowwoc/requirements.java/commits/master for a full list.
* This caused a “split package” error since only one module is allowed to export a package.
3. Removed the use of native binaries. Colored DIFFs are still supported, but Windows requires the use of
Windows Terminal (free download in Windows 10, built-in feature in Windows 11).
- 4. Improved performance by reducing memory usage and the frequency of GC runs.
- 5. Renamed `validateThat()` to `checkIf()`.
- 6. Renamed `assertThat()` to `assumeThat()`.
- 7. Added support for the built-in `assert` mechanism.
+ 4. Renamed `validateThat()` to `checkIf()`.
+ 5. Replaced `assertThat()` with `assert assumeThat().elseThrow()`.
+ 6. Added support for the built-in `assert` mechanism.
- Asserts can be used with any type of validator, but are typically used
with `assumeThat().orElseThrow()` and `checkIf().orElseThrow()`.
- 8. Use consistent parameter ordering across the entire API: `(value, name)`
+ 7. Use consistent parameter ordering across the entire API: `(value, name)`
- Adding contextual information now looks like this: `requireThat().context(value, name)`
- 9. Added `Validator.apply(Consumer)` to nest validations, and `Validator.and(Validator)` to combine
+ 8. Added `Validator.apply(Consumer)` to nest validations, and `Validator.and(Validator)` to combine
validation results.
- 10. Added support for primitive types to avoid boxing when possible.
- 11. Dropped the `isOneOf()` and `isNotOneOf()` functionality yet again. I haven't figured out a good
+ 9. Renamed `Validator.getActual()` to `getValue()`.
+ 10. Replaced `isBetweenClosed(min, max)` with `isBetween(min, true, max, true)`.
+ 11. Renamed `StringValidator.isInteger()` to `isInt()` and `isCharacter()` to `isChar()`.
+ 12. Improved performance by reducing memory usage and the frequency of GC runs.
+ 13. Added support for primitive types to avoid boxing when possible.
+ 14. Dropped the `isOneOf()` and `isNotOneOf()` functionality yet again. I haven't figured out a good
design for this yet.
- 12. Added `ObjectValidator.isX()` methods to downcast to known types.
+ 15. Added `ObjectValidator.isX()` methods to downcast to known types.
* Bugfixes:
* `StringValidator/Verifier.asShort()`, `asInteger()` and `asLong()` were not handling the case where a
string could not be converted to a number.
diff --git a/docs/Supported_Libraries.md b/docs/Supported_Libraries.md
index f238432bb..1508cbbd2 100644
--- a/docs/Supported_Libraries.md
+++ b/docs/Supported_Libraries.md
@@ -1,7 +1,14 @@
-Simply add a dependency for the module you are interested in, rebuild your project, and additional API methods
-will get generated
-inside [DefaultRequirements](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/DefaultRequirements.html)
-and [Requirements](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/Requirements.html):
+Each module uses a separate class pair for validation. For example,
+[DefaultJavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/java/DefaultJavaValidators.html)
+and
+[JavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/java/JavaValidators.html)
+validate the core Java API. Similarly,
+[DefaultGuavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/guava/DefaultGuavaValidators.html)
+and
+[GuavaValidators](https://cowwoc.github.io/requirements.java/9.0.0/docs/api/com.github.cowwoc.requirements/com/github/cowwoc/requirements/guava/GuavaValidators.html)
+validate the Guava API.
+
+The following table lists validators for third-party libraries:
| Library | Dependency |
|---------------------------------------------------------------|------------|
diff --git a/java/src/main/java/com/github/cowwoc/requirements/java/DefaultJavaValidators.java b/java/src/main/java/com/github/cowwoc/requirements/java/DefaultJavaValidators.java
index bf36cd881..2effa2251 100644
--- a/java/src/main/java/com/github/cowwoc/requirements/java/DefaultJavaValidators.java
+++ b/java/src/main/java/com/github/cowwoc/requirements/java/DefaultJavaValidators.java
@@ -63,7 +63,7 @@
/**
* Creates validators for the Java API, using the default configuration.
*
- * @see JavaValidators#newInstance() Creating a new instance with an independent configuration
+ * @see JavaValidators#newInstance() Creating an independent configuration
*/
public final class DefaultJavaValidators
{
@@ -2707,6 +2707,7 @@ public static InetAddressValidator checkIf(InetAddress value)
* Returns the configuration used by new validators.
*
* @return the configuration used by new validators
+ * @see JavaValidators#newInstance() Creating an independent configuration
*/
@CheckReturnValue
public static Configuration configuration()
@@ -2720,6 +2721,7 @@ public static Configuration configuration()
* NOTE: Changes are only applied when {@link ConfigurationUpdater#close()} is invoked.
*
* @return the configuration updater
+ * @see JavaValidators#newInstance() Creating an independent configuration
*/
@CheckReturnValue
public static ConfigurationUpdater updateConfiguration()
diff --git a/java/src/main/java/com/github/cowwoc/requirements/java/internal/util/ReentrantStampedLock.java b/java/src/main/java/com/github/cowwoc/requirements/java/internal/util/ReentrantStampedLock.java
index 7e6537f6a..b4f492e10 100644
--- a/java/src/main/java/com/github/cowwoc/requirements/java/internal/util/ReentrantStampedLock.java
+++ b/java/src/main/java/com/github/cowwoc/requirements/java/internal/util/ReentrantStampedLock.java
@@ -11,9 +11,14 @@
*/
public final class ReentrantStampedLock
{
+ private static void doNotUnlock()
+ {
+ }
+
// Excellent overview of StampedLock:
// https://www.javaspecialists.eu/talks/pdfs/2014%20JavaLand%20in%20Germany%20-%20%22Java%208%20From%20Smile%20To%20Tears%20-%20Emotional%20StampedLock%22%20by%20Heinz%20Kabutz.pdf
private final StampedLock lock = new StampedLock();
+
/**
* The stamp associated with the current thread. {@code null} if none.
*/
@@ -26,8 +31,31 @@ public ReentrantStampedLock()
{
}
- private static void doNotUnlock()
+ /**
+ * @return true if the caller is holding an optimistic read-lock
+ */
+ public boolean isOptimisticRead()
{
+ Long existingStamp = this.stamp.get();
+ return existingStamp != null && StampedLock.isOptimisticReadStamp(existingStamp);
+ }
+
+ /**
+ * @return true if the caller is holding a read-lock
+ */
+ public boolean isRead()
+ {
+ Long existingStamp = this.stamp.get();
+ return existingStamp != null && StampedLock.isReadLockStamp(existingStamp);
+ }
+
+ /**
+ * @return true if the caller is holding a write-lock
+ */
+ public boolean isWrite()
+ {
+ Long existingStamp = this.stamp.get();
+ return existingStamp != null && StampedLock.isWriteLockStamp(existingStamp);
}
/**