Skip to content

Commit a8fd507

Browse files
committed
Use MaxAdapter + separate adapters for BigDecimal and BigInteger
1 parent 140353a commit a8fd507

File tree

7 files changed

+160
-172
lines changed

7 files changed

+160
-172
lines changed

validator/src/main/java/io/avaje/validation/adapter/ValidationContext.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,12 @@ interface AdapterCreateRequest {
160160

161161
Map<String, Object> attributes();
162162

163+
Object attribute(String key);
164+
163165
Message message();
164166

165167
String targetType();
168+
169+
AdapterCreateRequest withValue(long value);
166170
}
167171
}

validator/src/main/java/io/avaje/validation/core/CoreAdapterBuilder.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
import java.lang.reflect.Type;
55
import java.time.Clock;
66
import java.time.Duration;
7-
import java.util.ArrayList;
8-
import java.util.List;
9-
import java.util.Map;
10-
import java.util.Set;
7+
import java.util.*;
118
import java.util.concurrent.ConcurrentHashMap;
129
import java.util.function.Supplier;
1310

@@ -116,7 +113,19 @@ record Request(
116113

117114
@Override
118115
public String targetType() {
119-
return (String)attributes.get("_type");
116+
return (String)attribute("_type");
117+
}
118+
119+
@Override
120+
public Object attribute(String key) {
121+
return attributes.get(key);
122+
}
123+
124+
@Override
125+
public Request withValue(long value) {
126+
Map<String, Object> newAttributes = new HashMap<>(attributes);
127+
newAttributes.put("value", value);
128+
return new Request(ctx, annotationType, groups, newAttributes);
120129
}
121130

122131
@Override

validator/src/main/java/io/avaje/validation/core/adapters/BasicAdapters.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,15 @@ static sealed class PatternAdapter extends AbstractConstraintAdapter<CharSequenc
3838
protected final Predicate<String> pattern;
3939

4040
PatternAdapter(AdapterCreateRequest request) {
41-
this(request, (String) request.attributes().get("regexp"));
41+
this(request, (String) request.attribute("regexp"));
4242
}
4343

4444
@SuppressWarnings("unchecked")
4545
PatternAdapter(AdapterCreateRequest request, String regex) {
4646
super(request);
4747
int flags = 0;
4848

49-
final var attributes = request.attributes();
50-
final List<RegexFlag> flags1 = (List<RegexFlag>) attributes.get("flags");
49+
final List<RegexFlag> flags1 = (List<RegexFlag>) request.attribute("flags");
5150
if (flags1 != null) {
5251
for (final var flag : flags1) {
5352
flags |= flag.getValue();
@@ -73,9 +72,8 @@ private static final class SizeAdapter implements ValidationAdapter<Object> {
7372
SizeAdapter(AdapterCreateRequest request) {
7473
this.message = request.message();
7574
this.groups = request.groups();
76-
final var attributes = request.attributes();
77-
this.min = (int) attributes.get("min");
78-
this.max = (int) attributes.get("max");
75+
this.min = (int) request.attribute("min");
76+
this.max = (int) request.attribute("max");
7977
}
8078

8179
@Override

validator/src/main/java/io/avaje/validation/core/adapters/NumMax.java

Lines changed: 0 additions & 79 deletions
This file was deleted.

validator/src/main/java/io/avaje/validation/core/adapters/NumberAdapters.java

Lines changed: 73 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import static io.avaje.validation.core.adapters.InfinityNumberComparatorHelper.GREATER_THAN;
44
import static io.avaje.validation.core.adapters.InfinityNumberComparatorHelper.LESS_THAN;
5+
import static io.avaje.validation.core.adapters.NumberComparatorHelper.compareDouble;
6+
import static io.avaje.validation.core.adapters.NumberComparatorHelper.compareFloat;
57

68
import java.math.BigDecimal;
9+
import java.math.BigInteger;
710
import java.util.Optional;
811

912
import io.avaje.validation.adapter.AbstractConstraintAdapter;
10-
import io.avaje.validation.adapter.ValidationAdapter;
1113
import io.avaje.validation.adapter.ValidationContext;
1214
import io.avaje.validation.adapter.ValidationContext.AdapterCreateRequest;
1315

@@ -29,19 +31,26 @@ private NumberAdapters() {}
2931
default -> null;
3032
};
3133

32-
private static ValidationAdapter<?> forMax(AdapterCreateRequest request) {
34+
private static AbstractConstraintAdapter<? extends Number> forMax(AdapterCreateRequest request) {
3335
final String targetType = request.targetType();
34-
if (targetType == null) {
35-
return new MaxAdapter(request);
36-
}
3736
return switch (targetType) {
38-
case "Integer" -> new NumMax.IntegerAdapter(request);
39-
case "Long" -> new NumMax.LongAdapter(request);
40-
case "BigDecimal" -> new NumMax.BigDecimalAdapter(request);
37+
case "BigDecimal" -> new MaxBigDecimal(request);
38+
case "BigInteger" -> new MaxBigInteger(request);
4139
default -> new MaxAdapter(request);
4240
};
4341
}
4442

43+
private static AbstractConstraintAdapter<? extends Number> forMin(AdapterCreateRequest request) {
44+
// final String targetType = request.targetType();
45+
// return switch (targetType) {
46+
// case "BigDecimal" -> new MinBigDecimal(request);
47+
// case "BigInteger" -> new MinBigInteger(request);
48+
// default -> new MinAdapter(request);
49+
// };
50+
return new MinAdapter(request);
51+
}
52+
53+
4554
private static final class DecimalMaxAdapter extends AbstractConstraintAdapter<Number> {
4655

4756
private final BigDecimal value;
@@ -62,7 +71,6 @@ public boolean isValid(Number number) {
6271
}
6372

6473
final int comparisonResult = NumberComparatorHelper.compareDecimal(number, value, LESS_THAN);
65-
6674
return !(inclusive ? comparisonResult > 0 : comparisonResult >= 0);
6775
}
6876
}
@@ -87,53 +95,82 @@ public boolean isValid(Number number) {
8795
}
8896

8997
final int comparisonResult = NumberComparatorHelper.compareDecimal(number, value, LESS_THAN);
90-
9198
return !(inclusive ? comparisonResult < 0 : comparisonResult <= 0);
9299
}
93100
}
94101

95-
private static final class MaxAdapter extends AbstractConstraintAdapter<Number> {
102+
public interface NumberAdapter<T extends Number> {
103+
boolean isValid(T number);
104+
}
105+
106+
private static final class MaxAdapter extends AbstractConstraintAdapter<Number> implements NumberAdapter<Number> {
96107

97108
private final long value;
109+
private final String targetType;
98110

99111
MaxAdapter(AdapterCreateRequest request) {
100112
super(request);
101-
final var attributes = request.attributes();
102-
this.value = (long) attributes.get("value");
103-
}
104-
105-
MaxAdapter(AdapterCreateRequest request, long value) {
106-
super(request);
107-
this.value = value;
113+
this.targetType = request.targetType();
114+
this.value = (long) request.attribute("value");
108115
}
109116

110117
@Override
111118
public boolean isValid(Number number) {
112119
// null values are valid
120+
if (number == null) {
121+
return true;
122+
}
123+
return switch (targetType) {
124+
case "Integer", "Long", "Short", "Byte" -> number.longValue() <= value;
125+
case "Double" -> compareDouble(number.doubleValue(), value, GREATER_THAN) <= 0;
126+
case "Float" -> compareFloat((Float)number, value, GREATER_THAN) <= 0;
127+
default -> throw new IllegalStateException();
128+
};
129+
}
130+
}
131+
132+
static final class MaxBigDecimal extends AbstractConstraintAdapter<BigDecimal> implements NumberAdapter<BigDecimal> {
133+
134+
private final BigDecimal max;
113135

114-
return number == null || NumberComparatorHelper.compare(number, value, GREATER_THAN) <= 0;
136+
MaxBigDecimal(AdapterCreateRequest request) {
137+
super(request);
138+
this.max = new BigDecimal(String.valueOf(request.attribute("value")));
139+
}
140+
141+
@Override
142+
public boolean isValid(BigDecimal number) {
143+
return number == null || number.compareTo(max) <= 0;
115144
}
116145
}
117146

118-
private static final class MinAdapter extends AbstractConstraintAdapter<Number> {
147+
static final class MaxBigInteger extends AbstractConstraintAdapter<BigInteger> implements NumberAdapter<BigInteger> {
119148

120-
private final long value;
149+
private final BigInteger max;
121150

122-
MinAdapter(AdapterCreateRequest request) {
151+
MaxBigInteger(AdapterCreateRequest request) {
123152
super(request);
124-
final var attributes = request.attributes();
125-
this.value = (long) attributes.get("value");
153+
this.max = new BigInteger(String.valueOf(request.attribute("value")));
126154
}
127155

128-
MinAdapter(AdapterCreateRequest request, long value) {
156+
@Override
157+
public boolean isValid(BigInteger number) {
158+
return number == null || number.compareTo(max) <= 0;
159+
}
160+
}
161+
162+
private static final class MinAdapter extends AbstractConstraintAdapter<Number> implements NumberAdapter<Number> {
163+
164+
private final long value;
165+
166+
MinAdapter(AdapterCreateRequest request) {
129167
super(request);
130-
this.value = value;
168+
this.value = (long) request.attribute("value");
131169
}
132170

133171
@Override
134172
public boolean isValid(Number number) {
135173
// null values are valid
136-
137174
return number == null || NumberComparatorHelper.compare(number, value, LESS_THAN) >= 0;
138175
}
139176
}
@@ -145,9 +182,8 @@ private static final class DigitsAdapter extends AbstractConstraintAdapter<Objec
145182

146183
DigitsAdapter(AdapterCreateRequest request) {
147184
super(request);
148-
final var attributes = request.attributes();
149-
this.integer = (int) attributes.get("integer");
150-
this.fraction = (int) attributes.get("fraction");
185+
this.integer = (int) request.attribute("integer");
186+
this.fraction = (int) request.attribute("fraction");
151187
}
152188

153189
@Override
@@ -166,7 +202,6 @@ public boolean isValid(Object value) {
166202

167203
final int integerPartLength = bigNum.precision() - bigNum.scale();
168204
final int fractionPartLength = Math.max(bigNum.scale(), 0);
169-
170205
return (integer >= integerPartLength) && (fraction >= fractionPartLength);
171206
}
172207
}
@@ -188,7 +223,6 @@ public boolean isValid(Object value) {
188223
}
189224

190225
final int sign = NumberSignHelper.signum(value, LESS_THAN);
191-
192226
return !(inclusive ? sign < 0 : sign <= 0);
193227
}
194228
}
@@ -210,28 +244,26 @@ public boolean isValid(Object value) {
210244
}
211245

212246
final int sign = NumberSignHelper.signum(value, GREATER_THAN);
213-
214247
return !(inclusive ? sign > 0 : sign >= 0);
215248
}
216249
}
217250

218251
private static final class RangeAdapter extends AbstractConstraintAdapter<Object> {
219252

220-
private final MaxAdapter maxAdapter;
221-
private final MinAdapter minAdapter;
253+
private final NumberAdapter<Number> maxAdapter;
254+
private final NumberAdapter<Number> minAdapter;
222255

256+
@SuppressWarnings("unchecked")
223257
RangeAdapter(AdapterCreateRequest request) {
224258
super(request);
225-
final var attributes = request.attributes();
226-
final var min = (long) attributes.get("min");
227-
final var max = (long) attributes.get("max");
228-
this.maxAdapter = new MaxAdapter(request, max);
229-
this.minAdapter = new MinAdapter(request, min);
259+
final var min = (long) request.attribute("min");
260+
final var max = (long) request.attribute("max");
261+
this.maxAdapter = (NumberAdapter<Number>)forMax(request.withValue(max));
262+
this.minAdapter = (NumberAdapter<Number>)forMin(request.withValue(min));
230263
}
231264

232265
@Override
233266
public boolean isValid(Object value) {
234-
235267
if (value instanceof final String s) {
236268
value = Long.parseLong(s);
237269
}

validator/src/main/java/io/avaje/validation/core/adapters/NumberComparatorHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ static int compareDecimal(Number number, BigDecimal value, OptionalInt treatNanA
4747
return compare(number.doubleValue(), value, treatNanAs);
4848
}
4949

50-
private static int compareDouble(Double number, long value, OptionalInt treatNanAs) {
50+
static int compareDouble(Double number, long value, OptionalInt treatNanAs) {
5151
final OptionalInt infinity = InfinityNumberComparatorHelper.infinityCheck(number, treatNanAs);
5252
if (infinity.isPresent()) {
5353
return infinity.getAsInt();
5454
}
5555
return Double.compare(number, value);
5656
}
5757

58-
private static int compareFloat(Float number, long value, OptionalInt treatNanAs) {
58+
static int compareFloat(Float number, long value, OptionalInt treatNanAs) {
5959
final OptionalInt infinity = InfinityNumberComparatorHelper.infinityCheck(number, treatNanAs);
6060
if (infinity.isPresent()) {
6161
return infinity.getAsInt();

0 commit comments

Comments
 (0)