Skip to content

Commit 8a4cfd0

Browse files
authored
Merge pull request #98 from avaje/feature_attribute_type
Generate a _type attribute with the target class for min, max, range etc
2 parents 799ea8e + ff60b87 commit 8a4cfd0

File tree

15 files changed

+533
-219
lines changed

15 files changed

+533
-219
lines changed

validator-generator/src/main/java/io/avaje/validation/generator/AnnotationUtil.java

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package io.avaje.validation.generator;
22

3+
import static io.avaje.validation.generator.ProcessingContext.isAssignable2Interface;
4+
import static io.avaje.validation.generator.Util.trimAnnotations;
35
import static java.util.function.Predicate.not;
46
import static java.util.stream.Collectors.joining;
57
import static java.util.stream.Collectors.toMap;
68

7-
import java.util.Arrays;
8-
import java.util.HashMap;
9-
import java.util.List;
10-
import java.util.Map;
11-
import java.util.Objects;
9+
import java.util.*;
1210
import java.util.regex.Pattern;
1311

1412
import javax.lang.model.element.AnnotationMirror;
@@ -19,12 +17,13 @@
1917
import javax.lang.model.element.TypeElement;
2018
import javax.lang.model.element.VariableElement;
2119
import javax.lang.model.type.ArrayType;
20+
import javax.lang.model.type.TypeMirror;
2221
import javax.lang.model.util.ElementFilter;
2322

2423
final class AnnotationUtil {
2524

2625
interface Handler {
27-
String attributes(AnnotationMirror annotationMirror, Element element);
26+
String attributes(AnnotationMirror annotationMirror, Element element, Element target);
2827

2928
String attributes(Map<String, Object> attributeMap);
3029
}
@@ -51,8 +50,12 @@ interface Handler {
5150
"NotNull",
5251
"NotBlank",
5352
"NotEmpty",
54-
"Size",
5553
"Email",
54+
"Length",
55+
"Range",
56+
"Max",
57+
"Min",
58+
"Size",
5659
"Past",
5760
"PastOrPresent",
5861
"Future",
@@ -62,22 +65,64 @@ interface Handler {
6265
"PositiveOrZero",
6366
"Negative",
6467
"NegativeOrZero",
65-
"Max",
66-
"Min"
6768
};
6869
for (final String key : keys) {
6970
handlers.put("io.avaje.validation.constraints." + key, commonHandler);
7071
handlers.put("jakarta.validation.constraints." + key, commonHandler);
7172
}
7273
}
7374

75+
static Map<String,String> KNOWN_TYPES = new HashMap<>();
76+
static {
77+
KNOWN_TYPES.put("byte", "Byte");
78+
KNOWN_TYPES.put("java.lang.Byte", "Byte");
79+
KNOWN_TYPES.put("short", "Short");
80+
KNOWN_TYPES.put("java.lang.Short", "Short");
81+
KNOWN_TYPES.put("int", "Integer");
82+
KNOWN_TYPES.put("java.lang.Integer", "Integer");
83+
KNOWN_TYPES.put("java.util.OptionalInt", "Integer");
84+
KNOWN_TYPES.put("long", "Long");
85+
KNOWN_TYPES.put("java.lang.Long", "Long");
86+
KNOWN_TYPES.put("java.util.OptionalLong", "Long");
87+
KNOWN_TYPES.put("float", "Float");
88+
KNOWN_TYPES.put("java.lang.Float", "Float");
89+
KNOWN_TYPES.put("double", "Double");
90+
KNOWN_TYPES.put("java.lang.Double", "Double");
91+
KNOWN_TYPES.put("java.util.OptionalDouble", "Double");
92+
KNOWN_TYPES.put("java.math.BigDecimal", "BigDecimal");
93+
KNOWN_TYPES.put("java.math.BigInteger", "BigInteger");
94+
KNOWN_TYPES.put("java.lang.String", "String");
95+
//TODO; Consider java.time types
96+
}
97+
98+
static String lookupType(TypeMirror typeMirror) {
99+
String rawType = trimAnnotations(typeMirror.toString());
100+
final String val = KNOWN_TYPES.get(rawType);
101+
if (val != null) {
102+
return val;
103+
}
104+
if (isAssignable2Interface(rawType, "java.math.BigDecimal")) {
105+
return "BigDecimal";
106+
}
107+
if (isAssignable2Interface(rawType, "java.math.BigInteger")) {
108+
return "BigInteger";
109+
}
110+
if (isAssignable2Interface(rawType, "java.lang.Number")) {
111+
return "Number";
112+
}
113+
if (isAssignable2Interface(rawType, "java.lang.CharSequence")) {
114+
return "CharSequence";
115+
}
116+
return null;
117+
}
118+
74119
private AnnotationUtil() {}
75120

76-
static String annotationAttributeMap(AnnotationMirror annotationMirror) {
121+
static String annotationAttributeMap(AnnotationMirror annotationMirror, Element target) {
77122
final Element element = annotationMirror.getAnnotationType().asElement();
78123
final Handler handler = handlers.get(element.toString());
79124
return Objects.requireNonNullElse(handler, defaultHandler)
80-
.attributes(annotationMirror, element);
125+
.attributes(annotationMirror, element, target);
81126
}
82127

83128
static String annotationAttributeMap(String annotationStr) {
@@ -100,7 +145,6 @@ static String annotationAttributeMap(String annotationStr) {
100145
convertTypeUse(element, attributeMap);
101146

102147
final Handler handler = handlers.get(result);
103-
104148
return Objects.requireNonNullElse(handler, defaultHandler).attributes(attributeMap);
105149
}
106150

@@ -221,7 +265,7 @@ private static String avajeKey(String messageKey) {
221265
static class PatternHandler extends BaseHandler {
222266

223267
@Override
224-
public String attributes(AnnotationMirror annotationMirror, Element element) {
268+
public String attributes(AnnotationMirror annotationMirror, Element element, Element target) {
225269
return new PatternHandler().writeAttributes(annotationMirror);
226270
}
227271

@@ -289,21 +333,24 @@ static class StandardHandler extends BaseHandler {
289333

290334
protected final AnnotationMirror annotationMirror;
291335
protected final Element element;
336+
protected final Element target;
292337

293338
/** Prototype factory */
294339
StandardHandler() {
295340
this.annotationMirror = null;
296341
this.element = null;
342+
this.target = null;
297343
}
298344

299-
StandardHandler(AnnotationMirror annotationMirror, Element element) {
345+
StandardHandler(AnnotationMirror annotationMirror, Element element, Element target) {
300346
this.annotationMirror = annotationMirror;
301347
this.element = element;
348+
this.target = target;
302349
}
303350

304351
@Override
305-
public String attributes(AnnotationMirror annotationMirror, Element element) {
306-
return new StandardHandler(annotationMirror, element).writeAttributes();
352+
public String attributes(AnnotationMirror annotationMirror, Element element, Element target) {
353+
return new StandardHandler(annotationMirror, element, target).writeAttributes();
307354
}
308355

309356
String writeAttributes() {
@@ -316,10 +363,19 @@ String writeAttributes() {
316363
}
317364
writeAttribute(member.getSimpleName(), value, defaultValue);
318365
}
366+
writeTypeAttribute(target.asType());
319367
sb.append(")");
320368
return sb.toString();
321369
}
322370

371+
protected void writeTypeAttribute(TypeMirror typeMirror) {
372+
String _type = lookupType(typeMirror);
373+
if (_type != null) {
374+
writeAttributeKey("_type");
375+
sb.append('"').append(_type).append('"');
376+
}
377+
}
378+
323379
void writeAttribute(Name simpleName, AnnotationValue value, AnnotationValue defaultValue) {
324380
writeAttributeKey(simpleName.toString());
325381
if (value != null) {
@@ -370,13 +426,13 @@ static class CommonHandler extends StandardHandler {
370426
/** Prototype factory only */
371427
CommonHandler() {}
372428

373-
CommonHandler(AnnotationMirror annotationMirror, Element element) {
374-
super(annotationMirror, element);
429+
CommonHandler(AnnotationMirror annotationMirror, Element element, Element target) {
430+
super(annotationMirror, element, target);
375431
}
376432

377433
@Override
378-
public String attributes(AnnotationMirror annotationMirror, Element element) {
379-
return new CommonHandler(annotationMirror, element).writeAttributes();
434+
public String attributes(AnnotationMirror annotationMirror, Element element, Element target) {
435+
return new CommonHandler(annotationMirror, element, target).writeAttributes();
380436
}
381437

382438
@Override
@@ -405,12 +461,12 @@ static class DecimalHandler extends CommonHandler {
405461
DecimalHandler() {}
406462

407463
@Override
408-
public String attributes(AnnotationMirror annotationMirror, Element element) {
409-
return new DecimalHandler(annotationMirror, element).writeAttributes();
464+
public String attributes(AnnotationMirror annotationMirror, Element element, Element target) {
465+
return new DecimalHandler(annotationMirror, element, target).writeAttributes();
410466
}
411467

412-
DecimalHandler(AnnotationMirror annotationMirror, Element element) {
413-
super(annotationMirror, element);
468+
DecimalHandler(AnnotationMirror annotationMirror, Element element, Element target) {
469+
super(annotationMirror, element, target);
414470
}
415471

416472
@Override

validator-generator/src/main/java/io/avaje/validation/generator/ContraintReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ final class ContraintReader implements BeanReader {
3838
.collect(
3939
toMap(
4040
a -> GenericType.parse(a.getAnnotationType().toString()),
41-
AnnotationUtil::annotationAttributeMap));
41+
a -> AnnotationUtil.annotationAttributeMap(a, element)));
4242
}
4343

4444
private List<AnnotationMirror> expand(AnnotationMirror m, List<AnnotationMirror> mirrors) {

validator-generator/src/main/java/io/avaje/validation/generator/ElementAnnotationContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static ElementAnnotationContainer create(Element element) {
5252
.collect(
5353
toMap(
5454
a -> GenericType.parse(a.getAnnotationType().toString()),
55-
AnnotationUtil::annotationAttributeMap));
55+
a -> AnnotationUtil.annotationAttributeMap(a, element)));
5656

5757
return new ElementAnnotationContainer(genericType, hasValid, annotations, typeUse1, typeUse2);
5858
}

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

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

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

163+
Object attribute(String key);
164+
163165
Message message();
166+
167+
String targetType();
168+
169+
AdapterCreateRequest withValue(long value);
164170
}
165171
}

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

Lines changed: 18 additions & 4 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

@@ -114,6 +111,23 @@ record Request(
114111

115112
) implements ValidationContext.AdapterCreateRequest {
116113

114+
@Override
115+
public String targetType() {
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);
129+
}
130+
117131
@Override
118132
public ValidationContext.Message message() {
119133
return ctx.message(attributes);

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

0 commit comments

Comments
 (0)