Skip to content

Commit 61c5966

Browse files
committed
start
1 parent ea3c396 commit 61c5966

File tree

14 files changed

+113
-44
lines changed

14 files changed

+113
-44
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ final class ContraintReader implements BeanReader {
2727
importTypes.add("java.util.Map");
2828
importTypes.add("io.avaje.validation.adapter.ConstraintAdapter");
2929
importTypes.add("io.avaje.validation.adapter.ValidationAdapter");
30-
importTypes.add("io.avaje.validation.adapter.ValidationContext");
3130
importTypes.add("io.avaje.validation.adapter.ValidationRequest");
31+
importTypes.add("io.avaje.validation.adapter.ValidationContext.AdapterCreateRequest");
3232
importTypes.add("io.avaje.validation.spi.Generated");
3333

3434
this.annotations =
@@ -121,7 +121,9 @@ public void writeConstructor(Append writer) {
121121

122122
writer.append(
123123
"""
124-
final var message = ctx.<Object>message(attributes).template();
124+
final var message = req.message().template();
125+
final var ctx = req.ctx();
126+
final var groups = req.groups();
125127
this.adapter =
126128
""");
127129

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import javax.lang.model.element.Element;
1010
import javax.lang.model.element.ExecutableElement;
11+
import javax.lang.model.element.TypeElement;
1112
import javax.lang.model.element.VariableElement;
1213

1314
// TODO: better name???
@@ -19,7 +20,7 @@ public record ElementAnnotationContainer(
1920
Map<GenericType, String> typeUse2) {
2021

2122
static ElementAnnotationContainer create(Element element) {
22-
final var hasValid = ValidPrism.isPresent(element);
23+
final var hasValid = !(element instanceof TypeElement) && ValidPrism.isPresent(element);
2324
String rawType;
2425
Map<GenericType, String> typeUse1;
2526
Map<GenericType, String> typeUse2;

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import javax.lang.model.element.Element;
77
import javax.lang.model.element.Modifier;
8+
import javax.lang.model.element.TypeElement;
89

910
final class FieldReader {
1011

@@ -22,6 +23,7 @@ final class FieldReader {
2223
private final boolean optionalValidation;
2324
private final Element element;
2425
private final ElementAnnotationContainer elementAnnotations;
26+
private final boolean classLevel;
2527

2628
FieldReader(Element element, List<String> genericTypeParams) {
2729
this.genericTypeParams = genericTypeParams;
@@ -34,6 +36,7 @@ final class FieldReader {
3436
adapterShortType = initAdapterShortType(shortType);
3537
adapterFieldName = initShortName();
3638
this.optionalValidation = Util.isNullable(element);
39+
this.classLevel = element instanceof TypeElement;
3740
}
3841

3942
private String initAdapterShortType(String shortType) {
@@ -120,7 +123,9 @@ void writeField(Append writer) {
120123
}
121124

122125
private void writeGetValue(Append writer, String suffix) {
123-
if (getter != null) {
126+
if (classLevel) {
127+
// don't need a getter
128+
} else if (getter != null) {
124129
writer.append("value.%s()%s", getter.getName(), suffix);
125130
} else if (publicField) {
126131
writer.append("value.%s%s", fieldName, suffix);
@@ -131,6 +136,11 @@ private void writeGetValue(Append writer, String suffix) {
131136
}
132137

133138
void writeValidate(Append writer) {
139+
if (classLevel) {
140+
writer.append(" %s.validate(value, request, field);", adapterFieldName);
141+
writer.eol().eol();
142+
return;
143+
}
134144
writer.append(" var _$%s = ", fieldName);
135145
writeGetValue(writer, ";");
136146
writer.eol();
@@ -161,4 +171,8 @@ public void writeConstructor(Append writer) {
161171
writer, elementAnnotations, " ", PrimitiveUtil.wrap(genericType.shortType()));
162172
writer.append(";").eol().eol();
163173
}
174+
175+
public boolean isClassLvl() {
176+
return classLevel;
177+
}
164178
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ void write() throws IOException {
5050
}
5151

5252
private void writeConstructor() {
53-
writer.append(" public %sValidationAdapter(ValidationContext ctx", adapterShortName);
54-
for (int i = 0; i < genericParamsCount; i++) {
55-
writer.append(", Type param%d", i);
56-
}
5753

58-
if (beanReader instanceof ContraintReader) {
59-
writer.append(", Set<Class<?>> groups, Map<String, Object> attributes");
54+
if (isContraint) {
55+
writer.append(" public %sValidationAdapter(AdapterCreateRequest req", adapterShortName);
56+
} else {
57+
writer.append(" public %sValidationAdapter(ValidationContext ctx", adapterShortName);
58+
for (int i = 0; i < genericParamsCount; i++) {
59+
writer.append(", Type param%d", i);
60+
}
6061
}
61-
6262
writer.append(") {", adapterShortName).eol();
6363
beanReader.writeConstructor(writer);
6464
writer.append(" }").eol();

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ final class TypeReader {
3232
private final Map<String, MethodReader> allGetterMethods = new LinkedHashMap<>();
3333
private final Map<String, MethodReader> maybeGetterMethods = new LinkedHashMap<>();
3434
private final TypeElement baseType;
35-
private final boolean hasJsonAnnotation;
35+
private final boolean hasValidAnnotation;
3636
private final Set<String> seenFields = new HashSet<>();
3737
private boolean nonAccessibleField;
3838
private final List<String> genericTypeParams;
3939

4040
TypeReader(TypeElement baseType) {
4141
this.baseType = baseType;
42-
this.hasJsonAnnotation = Util.isValid(baseType);
42+
this.hasValidAnnotation = Util.isValid(baseType);
4343
this.genericTypeParams = initTypeParams(baseType);
4444
}
4545

@@ -58,6 +58,8 @@ void read(TypeElement type) {
5858
}
5959
}
6060

61+
localFields.add(new FieldReader(type, genericTypeParams));
62+
6163
for (final FieldReader localField : localFields) {
6264
allFields.add(localField);
6365
allFieldMap.put(localField.fieldName(), localField);
@@ -93,10 +95,8 @@ private void readMethod(Element element, TypeElement type, List<FieldReader> loc
9395
final List<? extends VariableElement> parameters = methodElement.getParameters();
9496
final String methodKey = methodElement.getSimpleName().toString();
9597
final MethodReader methodReader = new MethodReader(methodElement, type).read();
96-
if (parameters.size() == 0) {
97-
if (!maybeGetterMethods.containsKey(methodKey)) {
98-
maybeGetterMethods.put(methodKey, methodReader);
99-
}
98+
if (parameters.isEmpty()) {
99+
maybeGetterMethods.putIfAbsent(methodKey, methodReader);
100100
allGetterMethods.put(methodKey.toLowerCase(), methodReader);
101101
}
102102
// for reading methods
@@ -112,6 +112,9 @@ private void readMethod(Element element, TypeElement type, List<FieldReader> loc
112112

113113
private void matchFieldsToGetter() {
114114
for (final FieldReader field : allFields) {
115+
if (field.isClassLvl()) {
116+
continue;
117+
}
115118
matchFieldToGetter(field);
116119
}
117120
}
@@ -121,8 +124,13 @@ private void matchFieldToGetter(FieldReader field) {
121124
&& !matchFieldToGetter2(field, true)
122125
&& !field.isPublicField()) {
123126
nonAccessibleField = true;
124-
if (hasJsonAnnotation) {
125-
logError("Non accessible field " + baseType + " " + field.fieldName() + " with no matching getter?");
127+
if (hasValidAnnotation) {
128+
logError(
129+
"Non accessible field "
130+
+ baseType
131+
+ " "
132+
+ field.fieldName()
133+
+ " with no matching getter?");
126134
} else {
127135
logDebug("Non accessible field " + baseType + " " + field.fieldName());
128136
}

validator-generator/src/test/java/io/avaje/validation/generator/ValidatorProcessorTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ void deleteGeneratedFiles() throws IOException {
4444
}
4545
}
4646

47-
@Disabled
4847
@Test
4948
void testGeneration() throws Exception {
5049
final String source =
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
import io.avaje.validation.adapter.AbstractConstraintAdapter;
44
import io.avaje.validation.adapter.ConstraintAdapter;
5-
import io.avaje.validation.adapter.ValidationContext;
5+
import io.avaje.validation.adapter.ValidationContext.AdapterCreateRequest;
66
import io.avaje.validation.generator.models.valid.CheckCase.CaseMode;
77

88
@ConstraintAdapter(CheckCase.class)
9-
public final class CustomAnnotationAdapter extends AbstractConstraintAdapter<String> {
9+
public final class CheckCaseAdapter extends AbstractConstraintAdapter<String> {
1010

1111
private final CaseMode caseMode;
1212

13-
public CustomAnnotationAdapter(ValidationContext.AdapterCreateRequest request) {
13+
public CheckCaseAdapter(AdapterCreateRequest request) {
1414
super(request);
1515
final var attributes = request.attributes();
1616
caseMode = (CaseMode) attributes.get("caseMode");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.avaje.validation.generator.models.valid.typeconstraint;
2+
3+
import static java.lang.annotation.ElementType.TYPE;
4+
import static java.lang.annotation.RetentionPolicy.SOURCE;
5+
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.Target;
8+
9+
import io.avaje.validation.constraints.Constraint;
10+
11+
@Target(TYPE)
12+
@Retention(SOURCE)
13+
@Constraint
14+
public @interface PassingSkill {
15+
String message() default "put these foolish ambitions to rest"; // default error message
16+
17+
Class<?>[] groups() default {}; // groups
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.avaje.validation.generator.models.valid.typeconstraint;
2+
3+
import io.avaje.validation.adapter.AbstractConstraintAdapter;
4+
import io.avaje.validation.adapter.ConstraintAdapter;
5+
import io.avaje.validation.adapter.ValidationContext.AdapterCreateRequest;
6+
7+
@ConstraintAdapter(PassingSkill.class)
8+
public final class PassingSkillAdapter extends AbstractConstraintAdapter<Tarnished> {
9+
10+
public PassingSkillAdapter(AdapterCreateRequest request) {
11+
super(request);
12+
}
13+
14+
@Override
15+
public boolean isValid(Tarnished lowlyTarnished) {
16+
if (lowlyTarnished == null) {
17+
return true;
18+
}
19+
return lowlyTarnished.vigor() >= 50 && lowlyTarnished.endurance() >= 50;
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package io.avaje.validation.generator.models.valid.typeconstraint;
2+
3+
import io.avaje.validation.constraints.Valid;
4+
5+
@Valid
6+
@PassingSkill
7+
public record Tarnished(int vigor, int endurance) {}

validator/src/main/java/io/avaje/validation/Validator.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
package io.avaje.validation;
22

3-
import io.avaje.lang.Nullable;
4-
import io.avaje.validation.adapter.*;
5-
import io.avaje.validation.core.DefaultBootstrap;
6-
import io.avaje.validation.spi.MessageInterpolator;
7-
import io.avaje.validation.spi.ValidatorCustomizer;
8-
93
import java.lang.annotation.Annotation;
104
import java.lang.reflect.Type;
115
import java.time.Clock;
126
import java.time.Duration;
137
import java.util.Locale;
14-
import java.util.Map;
158
import java.util.ResourceBundle;
16-
import java.util.Set;
179
import java.util.function.Supplier;
1810

11+
import io.avaje.lang.Nullable;
12+
import io.avaje.validation.adapter.ValidationAdapter;
13+
import io.avaje.validation.adapter.ValidationContext;
14+
import io.avaje.validation.adapter.ValidationContext.AdapterCreateRequest;
15+
import io.avaje.validation.core.DefaultBootstrap;
16+
import io.avaje.validation.spi.MessageInterpolator;
17+
import io.avaje.validation.spi.ValidatorCustomizer;
18+
1919
/**
2020
* Validate plain Java objects that have been annotated with validation constraints.
2121
*
@@ -145,8 +145,7 @@ interface AdapterBuilder {
145145
interface AnnotationAdapterBuilder {
146146

147147
/** Create a ValidationAdapter given the Validator instance. */
148-
ValidationAdapter<?> build(
149-
ValidationContext ctx, Set<Class<?>> groups, Map<String, Object> attributes);
148+
ValidationAdapter<?> build(AdapterCreateRequest request);
150149
}
151150

152151
/** Components register ValidationAdapters Validator.Builder */

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
*
2020
* String value;
2121
*
22-
* public CustomAnnotationAdapter(ValidationContext ctx, Set<Class<?>> groups, Map<String, Object> attributes) {
22+
* public CustomAnnotationAdapter(AdapterCreateRequest req) {
2323
* //create a message object for error interpolation and set groups
24-
* super(ctx.message(attributes), groups);
24+
* super(req);
2525
*
2626
* //use the attributes to extract the annotation values
27-
* value = (String) attributes.get("value");
27+
* value = (String) req.attribute("value");
2828
* }
2929
*
3030
*

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ public interface ValidationContext {
4141
<T> ValidationAdapter<T> adapter(Class<? extends Annotation> cls, Map<String, Object> attributes);
4242

4343
/**
44-
* Return the constraint adapter for the given annotation with attributes. Used for adapters that combine
45-
* multiple annotation adapters.
44+
* Return the constraint adapter for the given annotation with attributes. Used for adapters that
45+
* combine multiple annotation adapters.
4646
*
4747
* @param cls The class representing the annotation type
4848
* @param groups The validation groups associated with the annotation

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ private <T> ValidationType<T> type(Class<T> cls) {
8989

9090
@SuppressWarnings("unchecked")
9191
private <T> ValidationType<T> typeWithCache(Type type) {
92-
return (ValidationType<T>) typeCache.computeIfAbsent(type, k -> new ValidationType<>(this, adapter(k)));
92+
return (ValidationType<T>)
93+
typeCache.computeIfAbsent(type, k -> new ValidationType<>(this, adapter(k)));
9394
}
9495

9596
@Override
@@ -116,7 +117,8 @@ public <T> ValidationAdapter<T> adapter(Class<T> cls) {
116117
}
117118

118119
@Override
119-
public <T> ValidationAdapter<T> adapter(Class<? extends Annotation> cls, Map<String, Object> attributes) {
120+
public <T> ValidationAdapter<T> adapter(
121+
Class<? extends Annotation> cls, Map<String, Object> attributes) {
120122
return builder.annotationAdapter(cls, attributes, null);
121123
}
122124

@@ -302,8 +304,7 @@ private static <T> AnnotationFactory newAnnotationAdapterFactory(
302304
Type type, ValidationAdapter<T> adapter) {
303305
requireNonNull(type);
304306
requireNonNull(adapter);
305-
return (request) ->
306-
simpleMatch(type, request.annotationType()) ? adapter : null;
307+
return (request) -> simpleMatch(type, request.annotationType()) ? adapter : null;
307308
}
308309

309310
private static <T> AdapterFactory newAdapterFactory(Type type, ValidationAdapter<T> adapter) {
@@ -322,8 +323,7 @@ private static AnnotationFactory newAdapterFactory(
322323
Class<? extends Annotation> type, AnnotationAdapterBuilder builder) {
323324
requireNonNull(type);
324325
requireNonNull(builder);
325-
return (req) ->
326-
simpleMatch(type, req.annotationType()) ? builder.build(req.ctx(), req.groups(), req.attributes()) : null;
326+
return (req) -> simpleMatch(type, req.annotationType()) ? builder.build(req) : null;
327327
}
328328

329329
private static boolean simpleMatch(Type type, Type targetType) {

0 commit comments

Comments
 (0)