Skip to content

Commit 23fa528

Browse files
committed
Fix for class level validation (recursive adapter creation)
Specifically we don't want the .andThen(..) for the class level validation as then its recursive
1 parent f3f6a80 commit 23fa528

File tree

6 files changed

+119
-4
lines changed

6 files changed

+119
-4
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package example.avaje.crossfield;
2+
3+
import io.avaje.validation.constraints.Constraint;
4+
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.Target;
7+
8+
import static java.lang.annotation.ElementType.TYPE;
9+
import static java.lang.annotation.RetentionPolicy.SOURCE;
10+
11+
@Target(TYPE)
12+
@Retention(SOURCE)
13+
@Constraint
14+
public @interface APassingSkill {
15+
String message() default "put these foolish ambitions to rest"; // default error message
16+
17+
Class<?>[] groups() default {}; // groups
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package example.avaje.crossfield;
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(APassingSkill.class)
8+
public final class APassingSkillAdapter extends AbstractConstraintAdapter<ATarnished> {
9+
10+
public APassingSkillAdapter(AdapterCreateRequest request) {
11+
super(request);
12+
}
13+
14+
@Override
15+
public boolean isValid(ATarnished lowlyTarnished) {
16+
if (lowlyTarnished == null) {
17+
return true;
18+
}
19+
return lowlyTarnished.vigor() >= 50 && lowlyTarnished.endurance() >= 50;
20+
}
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package example.avaje.crossfield;
2+
3+
import io.avaje.validation.constraints.NotBlank;
4+
import io.avaje.validation.constraints.Positive;
5+
import io.avaje.validation.constraints.Valid;
6+
7+
@Valid
8+
@APassingSkill
9+
public record ATarnished(
10+
@NotBlank String name,
11+
@Positive int vigor,
12+
@Positive int endurance) {
13+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package example.avaje.crossfield;
2+
3+
import io.avaje.validation.ConstraintViolation;
4+
import io.avaje.validation.ConstraintViolationException;
5+
import io.avaje.validation.Validator;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.util.ArrayList;
9+
10+
import static org.assertj.core.api.Assertions.assertThat;
11+
import static org.assertj.core.api.Assertions.fail;
12+
13+
class ATarnishedTest {
14+
15+
Validator validator = Validator.builder().build();
16+
17+
@Test
18+
void valid() {
19+
validator.validate(new ATarnished("ok", 50, 50));
20+
}
21+
22+
@Test
23+
void invalid_classLevelValidation() {
24+
var violation = one(new ATarnished("ok", 49, 50));
25+
assertThat(violation.message()).isEqualTo("put these foolish ambitions to rest");
26+
assertThat(violation.path()).isEqualTo("null");
27+
assertThat(violation.field()).isNull();
28+
}
29+
30+
31+
@Test
32+
void invalidField_expect_classValidationToNotRun() {
33+
var violation = one(new ATarnished(" ", 49, 50));
34+
assertThat(violation.message()).isEqualTo("must not be blank");
35+
assertThat(violation.path()).isEqualTo("name");
36+
assertThat(violation.field()).isEqualTo("name");
37+
}
38+
39+
@Test
40+
void invalidField2_expect_classValidationToNotRun() {
41+
var violation = one(new ATarnished("ok", -1, 50));
42+
assertThat(violation.message()).isEqualTo("must be greater than 0");
43+
assertThat(violation.path()).isEqualTo("vigor");
44+
assertThat(violation.field()).isEqualTo("vigor");
45+
}
46+
47+
ConstraintViolation one(Object any) {
48+
try {
49+
validator.validate(any);
50+
fail("not expected");
51+
return null;
52+
} catch (ConstraintViolationException e) {
53+
var violations = new ArrayList<>(e.violations());
54+
assertThat(violations).hasSize(1);
55+
return violations.get(0);
56+
}
57+
}
58+
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,20 @@ class AdapterHelper {
1212
private final String type;
1313
private final GenericType topType;
1414
private final GenericType genericType;
15+
private final boolean classLevel;
1516

1617
AdapterHelper(Append writer, ElementAnnotationContainer elementAnnotations, String indent) {
17-
this(writer, elementAnnotations, indent,"Object", null);
18+
this(writer, elementAnnotations, indent,"Object", null, false);
1819
}
1920

20-
AdapterHelper(Append writer, ElementAnnotationContainer elementAnnotations, String indent, String type, GenericType topType) {
21+
AdapterHelper(Append writer, ElementAnnotationContainer elementAnnotations, String indent, String type, GenericType topType, boolean classLevel) {
2122
this.writer = writer;
2223
this.elementAnnotations = elementAnnotations;
2324
this.indent = indent;
2425
this.type = type;
2526
this.topType = topType;
2627
this.genericType = elementAnnotations.genericType();
28+
this.classLevel = classLevel;
2729
}
2830

2931
void write() {
@@ -70,7 +72,9 @@ void write() {
7072
writeTypeUse(genericType.firstParamType(), typeUse1);
7173

7274
} else if (hasValid) {
73-
writer.eol().append("%s .andThen(ctx.adapter(%s.class))", indent, Util.shortName(genericType.topType()));
75+
if (!classLevel) {
76+
writer.eol().append("%s .andThen(ctx.adapter(%s.class))", indent, Util.shortName(genericType.topType()));
77+
}
7478

7579
} else if (genericType.topType().contains("java.util.Optional")) {
7680
writer.eol().append("%s .optional()", indent);

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ public void writeConstructor(Append writer) {
182182
elementAnnotations,
183183
" ",
184184
PrimitiveUtil.wrap(genericType.shortType()),
185-
genericType)
185+
genericType,
186+
classLevel)
186187
.write();
187188
writer.append(";").eol().eol();
188189
}

0 commit comments

Comments
 (0)