From 987fc5ebf425f45e749ded3b38368550b31c01ca Mon Sep 17 00:00:00 2001 From: Gili Tzabari Date: Thu, 15 Feb 2024 10:24:08 -0500 Subject: [PATCH] Cosmetic changes --- README.md | 69 +++++++++---------- docs/Changelog.md | 21 +++--- docs/Supported_Libraries.md | 15 ++-- .../java/DefaultJavaValidators.java | 4 +- .../internal/util/ReentrantStampedLock.java | 30 +++++++- 5 files changed, 88 insertions(+), 51 deletions(-) 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) -# checklist Fluent API for Design Contracts +# checklist 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); } /**