Skip to content

Commit 491d230

Browse files
committed
* Renamed Validator.apply() to Validator.and().
* Added Validator.add() and Validator.or() logical operators. * Removed all type converters from ObjectValidator and StringValidator because the concept does not scale. We can't just keep on adding methods to these centralized classes.
1 parent 4d1b8a9 commit 491d230

File tree

115 files changed

+3071
-3982
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+3071
-3982
lines changed

README.md

Lines changed: 67 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ To get started, add this Maven dependency:
2020
```xml
2121

2222
<dependency>
23-
<groupId>com.github.cowwoc.requirements</groupId>
24-
<artifactId>java</artifactId>
25-
<version>10.0</version>
23+
<groupId>com.github.cowwoc.requirements</groupId>
24+
<artifactId>java</artifactId>
25+
<version>10.0</version>
2626
</dependency>
2727
```
2828

@@ -38,32 +38,32 @@ import static com.github.cowwoc.requirements10.java.DefaultJavaValidators.requir
3838

3939
public final class Cake
4040
{
41-
private byte bitesTaken = 0;
42-
private int piecesLeft;
43-
44-
public Cake(int piecesLeft)
45-
{
46-
requireThat(piecesLeft, "piecesLeft").isPositive();
47-
this.piecesLeft = piecesLeft;
48-
}
49-
50-
public int eat()
51-
{
52-
++bitesTaken;
53-
assert assumeThat(bitesTaken, "bitesTaken").isNotNegative().elseThrow();
54-
55-
piecesLeft -= ThreadLocalRandom.current().nextInt(5);
56-
57-
assert assumeThat(piecesLeft, "piecesLeft").isNotNegative().elseThrow();
58-
return piecesLeft;
59-
}
60-
61-
public List<String> getFailures()
62-
{
63-
return checkIf(bitesTaken, "bitesTaken").isNotNegative().
64-
and(checkIf(piecesLeft, "piecesLeft").isGreaterThan(3)).
65-
elseGetMessages();
66-
}
41+
private byte bitesTaken = 0;
42+
private int piecesLeft;
43+
44+
public Cake(int piecesLeft)
45+
{
46+
requireThat(piecesLeft, "piecesLeft").isPositive();
47+
this.piecesLeft = piecesLeft;
48+
}
49+
50+
public int eat()
51+
{
52+
++bitesTaken;
53+
assert assumeThat(bitesTaken, "bitesTaken").isNotNegative().elseThrow();
54+
55+
piecesLeft -= ThreadLocalRandom.current().nextInt(5);
56+
57+
assert assumeThat(piecesLeft, "piecesLeft").isNotNegative().elseThrow();
58+
return piecesLeft;
59+
}
60+
61+
public List<String> getFailures()
62+
{
63+
return checkIf(bitesTaken, "bitesTaken").isNotNegative().
64+
and(checkIf(piecesLeft, "piecesLeft").isGreaterThan(3)).
65+
elseGetMessages();
66+
}
6767
}
6868
```
6969

@@ -84,8 +84,10 @@ If you violate a **class invariant**:
8484

8585
```java
8686
Cake cake = new Cake(1_000_000);
87-
while (true)
88-
cake.eat();
87+
while(true)
88+
cake.
89+
90+
eat();
8991
```
9092

9193
You'll get:
@@ -99,8 +101,10 @@ If you violate a **postcondition**:
99101

100102
```java
101103
Cake cake = new Cake(100);
102-
while (true)
103-
cake.eat();
104+
while(true)
105+
cake.
106+
107+
eat();
104108
```
105109

106110
You'll get:
@@ -114,12 +118,19 @@ If you violate **multiple** conditions at once:
114118

115119
```java
116120
Cake cake = new Cake(1);
117-
cake.bitesTaken = -1;
118-
cake.piecesLeft = 2;
121+
cake.bitesTaken =-1;
122+
cake.piecesLeft =2;
119123
StringJoiner failures = new StringJoiner("\n\n");
120-
for (String failure : cake.getFailures())
121-
failures.add(failure);
122-
System.out.println(failures);
124+
for(
125+
String failure :cake.
126+
127+
getFailures())
128+
failures.
129+
130+
add(failure);
131+
System.out.
132+
133+
println(failures);
123134
```
124135

125136
You'll get:
@@ -144,6 +155,8 @@ This library offers the following features:
144155
* [Multiple validation failures](docs/Features.md#multiple-validation-failures) that report all the errors at
145156
once
146157
* [Nested validations](docs/Features.md#nested-validations) that allow you to validate complex objects
158+
* [Logical operators](docs/Features.md#logical-operators) that allow you to combine the validation of
159+
unrelated values
147160
* [String diff](docs/Features.md#string-diff) that shows the differences between two strings
148161
* [Performant and robust](docs/Performance.md)
149162

@@ -152,28 +165,35 @@ This library offers the following features:
152165
Designed for discovery using your favorite IDE's auto-complete feature.
153166
The main entry points are:
154167

155-
* [requireThat(value, name)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/DefaultJavaValidators.html#requireThat(T,java.lang.String)) for method preconditions.
156-
* [assumeThat(value, name)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/DefaultJavaValidators.html#assumeThat(T,java.lang.String)) for class invariants, method postconditions and private methods.
157-
* [checkIfThat(value, name)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/DefaultJavaValidators.html#checkIf(T,java.lang.String)) for multiple failures and customized error handling.
158-
* [JavaValidators](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/JavaValidators.html) for custom configurations.
168+
* [requireThat(value, name)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/DefaultJavaValidators.html#requireThat(T,java.lang.String))
169+
for method preconditions.
170+
* [assumeThat(value, name)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/DefaultJavaValidators.html#assumeThat(T,java.lang.String))
171+
for class invariants, method postconditions and private methods.
172+
* [checkIfThat(value, name)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/DefaultJavaValidators.html#checkIf(T,java.lang.String))
173+
for multiple failures and customized error handling.
174+
* [JavaValidators](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/JavaValidators.html)
175+
for custom configurations.
159176

160177
The first three methods use a shared configuration, while `JavaValidators` allows you to create an independent
161178
configuration.
162179

163180
* `requireThat()` and `assumeThat()` throw an exception on the first validation failure.
164-
* `checkIf()` returns multiple validation failures at once. It is more flexible than the others, but its syntax
165-
is more verbose.
181+
* `checkIf()` returns multiple validation failures at once. It is more flexible than the others, but its
182+
syntax
183+
is more verbose.
166184

167-
Thrown exceptions may be configured using [ConfigurationUpdater.exceptionTransformer(Function)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/ConfigurationUpdater.html#exceptionTransformer(java.util.function.Function)).
185+
Thrown exceptions may be configured
186+
using [ConfigurationUpdater.exceptionTransformer(Function)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/ConfigurationUpdater.html#exceptionTransformer(java.util.function.Function)).
168187

169188
See the [API documentation](https://cowwoc.github.io/requirements.java/10.0/docs/api/) for more details.
170189

171190
## Tips
172191

173-
* Use `assert` with `assumeThat().elseThrow()` for sanity checks. When assertions are disabled, the checks will get removed.
192+
* Use `assert` with `assumeThat().elseThrow()` for sanity checks. When assertions are disabled, the checks
193+
will get removed.
174194
* Use `checkIf().elseGetMessages()` to return failure messages without throwing an exception.
175195
This is the fastest validation approach, ideal for web services.
176-
* To enhance the clarity of failure messages, you should provide parameter names, even when they are optional.
196+
* To enhance the clarity of failure messages, you should provide parameter names, even when they are optional.
177197
In other words, favor `assumeThat(value, name)` to `assumeThat(value)`.
178198

179199
## Third-party libraries and tools

docs/Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ See https://github.com/cowwoc/requirements.java/commits/master for a full list.
1212
* Renamed `Configuration.mayDiff()` to `allowDiff()`.
1313
* Parameter names may not contain whitespace (previously only leading or trailing whitespace was
1414
disallowed).
15+
* Moved `com.github.cowwoc.requirements10.java.terminal.TerminalEncoding`
16+
to `com.github.cowwoc.requirements10.java.TerminalEncoding`.
17+
* Renamed `Validator.apply()` to `Validator.validate()`.
1518
* New features:
1619
* Added `GenericType` to represent types with type parameters.
1720
* Added `ClassValidator.isPrimitive()`.

docs/Features.md

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -148,30 +148,46 @@ Actual: [Ontario, Quebec, Nova Scotia, New Brunswick, Manitoba, British Columbia
148148

149149
## Nested validations
150150

151-
Nested validations facilitate checking multiple properties of a value. For example, given
151+
Nested validations facilitate checking multiple properties of a value. For example,
152152

153153
```java
154154
Map<String, Integer> nameToAge = new HashMap<>();
155155
nameToAge.put("Leah", 3);
156156
nameToAge.put("Nathaniel", 1);
157+
158+
requireThat(nameToAge, "nameToAge").
159+
keySet().containsAll(Arrays.asList("Leah", "Nathaniel"));
160+
161+
requireThat(nameToAge, "nameToAge").
162+
values().containsAll(Arrays.asList(3, 1));
157163
```
158164

159-
To validate that `nameToAge` has the keys "Leah" and "Nathaniel" and the values 3 and 1, you can write:
165+
can be converted to:
160166

161167
```java
162168
requireThat(nameToAge, "nameToAge").
163-
apply(v -> v.keySet().containsAll(Arrays.asList("Leah", "Nathaniel"))).
164-
apply(v -> v.values().containsAll(Arrays.asList(3, 1)));
169+
and(v -> v.keySet().containsAll(Arrays.asList("Leah", "Nathaniel"))).
170+
and(v -> v.values().containsAll(Arrays.asList(3, 1)));
165171
```
166172

167-
instead of:
173+
## Logical operators
174+
175+
Logical operators combine the validation of unrelated values. For example,
168176

169177
```java
170-
requireThat(nameToAge, "nameToAge").
171-
keySet().containsAll(Arrays.asList("Leah", "Nathaniel"));
178+
Set<String> activeUsers = Set.of("Alice", "Bob");
179+
Set<String> suspendedUsers = Set.of("Charlie");
172180

173-
requireThat(nameToAge, "nameToAge").
174-
values().containsAll(Arrays.asList(3, 1));
181+
String currentUser = "Alice";
182+
var userCheck = checkIf(currentUser, "currentUser");
183+
for (String user : activeUsers)
184+
{
185+
var yetAnotherUserCheck = checkIf(currentUser, "currentUser").isEqualTo(user);
186+
userCheck.or(yetAnotherUserCheck);
187+
}
188+
var userNotSuspended = checkIf(suspendedUsers, "suspendedUsers").
189+
doesNotContain(currentUser, "currentUser");
190+
userCheck.and(userNotSuspended).elseThrow();
175191
```
176192

177193
## String diff
@@ -191,7 +207,7 @@ terminal.
191207

192208
The use of colors is disabled by default if stdin or stdout are redirected, even if ANSI colors are supported.
193209
To enable colors,
194-
invoke [GlobalConfiguration.terminalEncoding(TerminalEncoding)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/GlobalConfiguration.html#terminalEncoding(com.github.cowwoc.requirements10.java.terminal.TerminalEncoding)).
210+
invoke [GlobalConfiguration.terminalEncoding(TerminalEncoding)](https://cowwoc.github.io/requirements.java/10.0/docs/api/com.github.cowwoc.requirements.java/com/github/cowwoc/requirements10/java/GlobalConfiguration.html#terminalEncoding(com.github.cowwoc.requirements10.java.TerminalEncoding)).
195211

196212
## Returning the value after validation
197213

guava/src/main/java/com/github/cowwoc/requirements10/guava/internal/validator/GuavaValidatorsImpl.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import com.github.cowwoc.requirements10.java.ValidationFailure;
77
import com.github.cowwoc.requirements10.java.internal.scope.ApplicationScope;
88
import com.github.cowwoc.requirements10.java.internal.util.MaybeUndefined;
9-
import com.github.cowwoc.requirements10.java.internal.validator.AbstractValidator;
109
import com.github.cowwoc.requirements10.java.internal.validator.AbstractValidators;
1110
import com.google.common.collect.Multimap;
1211

@@ -15,6 +14,8 @@
1514
import java.util.List;
1615
import java.util.Map;
1716

17+
import static com.github.cowwoc.requirements10.java.internal.validator.JavaValidatorsImpl.DEFAULT_NAME;
18+
1819
public class GuavaValidatorsImpl extends AbstractValidators<GuavaValidators>
1920
implements GuavaValidators
2021
{
@@ -57,7 +58,7 @@ public <K, V, T extends Multimap<K, V>> MultimapValidator<T, K, V> assumeThat(T
5758
@Override
5859
public <K, V, T extends Multimap<K, V>> MultimapValidator<T, K, V> assumeThat(T value)
5960
{
60-
return assumeThat(value, AbstractValidator.DEFAULT_NAME);
61+
return assumeThat(value, DEFAULT_NAME);
6162
}
6263

6364
@Override
@@ -69,7 +70,7 @@ public <K, V, T extends Multimap<K, V>> MultimapValidator<T, K, V> checkIf(T val
6970
@Override
7071
public <K, V, T extends Multimap<K, V>> MultimapValidator<T, K, V> checkIf(T value)
7172
{
72-
return checkIf(value, AbstractValidator.DEFAULT_NAME);
73+
return checkIf(value, DEFAULT_NAME);
7374
}
7475

7576
private <K, V, T extends Multimap<K, V>> MultimapValidator<T, K, V> newInstance(T value, String name,

guava/src/main/java/com/github/cowwoc/requirements10/guava/internal/validator/MultimapValidatorImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public MultimapValidator<T, K, V> isEmpty()
6060
switch (value.test(Multimap::isEmpty))
6161
{
6262
case UNDEFINED, FALSE -> addIllegalArgumentException(
63-
ObjectMessages.isEmpty(scope, this).toString());
63+
ObjectMessages.isEmpty(this).toString());
6464
}
6565
return self();
6666
}
@@ -73,7 +73,7 @@ public MultimapValidator<T, K, V> isNotEmpty()
7373
switch (value.test(value -> !value.isEmpty()))
7474
{
7575
case UNDEFINED, FALSE -> addIllegalArgumentException(
76-
ObjectMessages.isNotEmpty(scope, this).toString());
76+
ObjectMessages.isNotEmpty(this).toString());
7777
}
7878
return self();
7979
}

jackson/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
<option>summary</option>
5757
</additionalOptions>
5858
<links>
59-
<link>https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/2.17.1/</link>
59+
<link>https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/2.17.2/</link>
6060
</links>
6161
<offlineLinks>
6262
<!--

jackson/src/main/java/com/github/cowwoc/requirements10/jackson/internal/message/JsonNodeMessages.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66

77
import com.fasterxml.jackson.databind.JsonNode;
88
import com.github.cowwoc.requirements10.java.internal.message.section.MessageBuilder;
9-
import com.github.cowwoc.requirements10.java.internal.scope.ApplicationScope;
109
import com.github.cowwoc.requirements10.java.internal.util.MaybeUndefined;
11-
import com.github.cowwoc.requirements10.java.validator.component.ValidatorComponent;
10+
import com.github.cowwoc.requirements10.java.internal.validator.AbstractValidator;
1211

1312
import static com.github.cowwoc.requirements10.java.internal.message.section.MessageBuilder.quoteName;
1413

@@ -22,32 +21,28 @@ private JsonNodeMessages()
2221
}
2322

2423
/**
25-
* @param scope the application configuration
2624
* @param validator the validator
2725
* @param name the name of a property
2826
* @return a message for the validation failure
2927
*/
30-
public static MessageBuilder property(ApplicationScope scope,
31-
ValidatorComponent<?, ? extends JsonNode> validator, MaybeUndefined<? extends JsonNode> value,
32-
String name)
28+
public static MessageBuilder property(AbstractValidator<?, ? extends JsonNode> validator,
29+
MaybeUndefined<? extends JsonNode> value, String name)
3330
{
34-
MessageBuilder messageBuilder = new MessageBuilder(scope, validator,
31+
MessageBuilder messageBuilder = new MessageBuilder(validator,
3532
quoteName(validator.getName()) + " must contain a property named " + quoteName(name) + ".");
3633
value.ifDefined(v -> messageBuilder.withContext(v, name));
3734
return messageBuilder;
3835
}
3936

4037
/**
41-
* @param scope the application configuration
4238
* @param validator the validator
4339
* @param type a description of the expected type (e.g. "a string")
4440
* @return a message for the validation failure
4541
*/
46-
public static MessageBuilder isType(ApplicationScope scope,
47-
ValidatorComponent<?, ? extends JsonNode> validator, MaybeUndefined<? extends JsonNode> value,
48-
String type)
42+
public static MessageBuilder isType(AbstractValidator<?, ? extends JsonNode> validator,
43+
MaybeUndefined<? extends JsonNode> value, String type)
4944
{
50-
MessageBuilder messageBuilder = new MessageBuilder(scope, validator,
45+
MessageBuilder messageBuilder = new MessageBuilder(validator,
5146
quoteName(validator.getName()) + " must contain " + type + ".");
5247
value.ifDefined(v -> messageBuilder.withContext(v, "actual"));
5348
return messageBuilder;

jackson/src/main/java/com/github/cowwoc/requirements10/jackson/internal/validator/JacksonValidatorsImpl.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
import com.github.cowwoc.requirements10.java.ValidationFailure;
88
import com.github.cowwoc.requirements10.java.internal.scope.ApplicationScope;
99
import com.github.cowwoc.requirements10.java.internal.util.MaybeUndefined;
10-
import com.github.cowwoc.requirements10.java.internal.validator.AbstractValidator;
1110
import com.github.cowwoc.requirements10.java.internal.validator.AbstractValidators;
1211

1312
import java.util.ArrayList;
1413
import java.util.HashMap;
1514
import java.util.List;
1615
import java.util.Map;
1716

17+
import static com.github.cowwoc.requirements10.java.internal.validator.JavaValidatorsImpl.DEFAULT_NAME;
18+
1819
public class JacksonValidatorsImpl extends AbstractValidators<JacksonValidators>
1920
implements JacksonValidators
2021
{
@@ -57,7 +58,7 @@ public <T extends JsonNode> JsonNodeValidator<T> assumeThat(T value, String name
5758
@Override
5859
public <T extends JsonNode> JsonNodeValidator<T> assumeThat(T value)
5960
{
60-
return assumeThat(value, AbstractValidator.DEFAULT_NAME);
61+
return assumeThat(value, DEFAULT_NAME);
6162
}
6263

6364
@Override
@@ -69,7 +70,7 @@ public <T extends JsonNode> JsonNodeValidator<T> checkIf(T value, String name)
6970
@Override
7071
public <T extends JsonNode> JsonNodeValidator<T> checkIf(T value)
7172
{
72-
return checkIf(value, AbstractValidator.DEFAULT_NAME);
73+
return checkIf(value, DEFAULT_NAME);
7374
}
7475

7576
private <T extends JsonNode> JsonNodeValidator<T> newInstance(T value, String name,

0 commit comments

Comments
 (0)