Skip to content

Commit a470d9b

Browse files
resolve discussions
1 parent 229b584 commit a470d9b

11 files changed

Lines changed: 100 additions & 93 deletions

File tree

modules/jooby-hbv/src/main/java/io/jooby/hbv/package-info.java

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111

1212
<modelVersion>4.0.0</modelVersion>
13-
<artifactId>jooby-hbv</artifactId>
13+
<artifactId>jooby-hibernate-validator</artifactId>
1414

1515
<dependencies>
1616
<dependency>

modules/jooby-hbv/src/main/java/io/jooby/hbv/HbvModule.java renamed to modules/jooby-hibernate-validator/src/main/java/io/jooby/hibernate/validator/HibernateValidatorModule.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
44
* Copyright 2014 Edgar Espina
55
*/
6-
package io.jooby.hbv;
7-
6+
package io.jooby.hibernate.validator;
87

98
import edu.umd.cs.findbugs.annotations.NonNull;
109
import io.jooby.Extension;
@@ -21,7 +20,7 @@
2120

2221
import static jakarta.validation.Validation.byProvider;
2322

24-
public class HbvModule implements Extension {
23+
public class HibernateValidatorModule implements Extension {
2524

2625
private Consumer<HibernateValidatorConfiguration> configurer;
2726
private StatusCode statusCode = StatusCode.UNPROCESSABLE_ENTITY;
@@ -34,7 +33,7 @@ public class HbvModule implements Extension {
3433
* @param configurer Configurer callback.
3534
* @return This module.
3635
*/
37-
public HbvModule doWith(@NonNull final Consumer<HibernateValidatorConfiguration> configurer) {
36+
public HibernateValidatorModule doWith(@NonNull final Consumer<HibernateValidatorConfiguration> configurer) {
3837
this.configurer = configurer;
3938
return this;
4039
}
@@ -46,7 +45,7 @@ public HbvModule doWith(@NonNull final Consumer<HibernateValidatorConfiguration>
4645
* @param statusCode new status code
4746
* @return This module.
4847
*/
49-
public HbvModule statusCode(@NonNull StatusCode statusCode) {
48+
public HibernateValidatorModule statusCode(@NonNull StatusCode statusCode) {
5049
this.statusCode = statusCode;
5150
return this;
5251
}
@@ -58,20 +57,21 @@ public HbvModule statusCode(@NonNull StatusCode statusCode) {
5857
* @param title new title
5958
* @return This module.
6059
*/
61-
public HbvModule validationTitle(@NonNull String title) {
60+
public HibernateValidatorModule validationTitle(@NonNull String title) {
6261
this.title = title;
6362
return this;
6463
}
6564

6665
/**
6766
* Disables default constraint violation handler.
68-
* By default {@link HbvModule} provide built-in error handler for the {@link ConstraintViolationException}
67+
* By default {@link HibernateValidatorModule} provides
68+
* built-in error handler for the {@link ConstraintViolationException}
6969
* Such exceptions are transformed into response of {@link io.jooby.validation.ValidationResult}
7070
* Use this flag to disable default error handler and provide your custom.
7171
*
7272
* @return This module.
7373
*/
74-
public HbvModule disableViolationHandler() {
74+
public HibernateValidatorModule disableViolationHandler() {
7575
this.disableDefaultViolationHandler = true;
7676
return this;
7777
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package io.jooby.hibernate.validator;

modules/jooby-hbv/src/main/java/module-info.java renamed to modules/jooby-hibernate-validator/src/main/java/module-info.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
* Copyright 2014 Edgar Espina
55
*/
66
/**
7-
* Hbv module.
7+
* Hibernate Validator Module.
88
*/
9-
module io.jooby.hbv {
10-
exports io.jooby.hbv;
9+
module io.jooby.hibernate.validator {
10+
exports io.jooby.hibernate.validator;
1111

1212
requires transitive io.jooby;
1313
requires static com.github.spotbugs.annotations;

modules/jooby-jakarta-validation/src/main/java/io/jooby/validation/ConstraintViolationHandler.java

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,40 @@
1212
import java.util.Map;
1313
import java.util.Set;
1414

15+
import static io.jooby.validation.ValidationResult.ErrorType.FIELD;
16+
import static io.jooby.validation.ValidationResult.ErrorType.GLOBAL;
1517
import static java.util.stream.Collectors.groupingBy;
1618

1719
/**
1820
* Catches and transform {@link ConstraintViolationException} into {@link ValidationResult}
19-
*
21+
* <p>
2022
* Payload example:
21-
* <code>
23+
* <pre>{@code
2224
* {
23-
* "title": "Validation failed",
24-
* "status": 422,
25-
* "errors": {
26-
* "objectErrors": [
27-
* "Passwords should match"
28-
* ],
29-
* "fieldErrors": [
30-
* {
31-
* "field": "firstName",
32-
* "messages": [
33-
* "must not be empty",
34-
* "must not be null"
35-
* ]
36-
* }
37-
* ]
38-
* }
25+
* "title": "Validation failed",
26+
* "status": 422,
27+
* "errors": [
28+
* {
29+
* "field": null,
30+
* "messages": [
31+
* "Passwords should match"
32+
* ],
33+
* "type": "GLOBAL"
34+
* },
35+
* {
36+
* "field": "firstName",
37+
* "messages": [
38+
* "must not be empty",
39+
* "must not be null"
40+
* ],
41+
* "type": "FIELD"
42+
* }
43+
* ]
3944
* }
40-
* </code>
45+
* }</pre>
46+
*
47+
* @author kliushnichenko
48+
* @since 3.2.10
4149
*/
4250
public class ConstraintViolationHandler implements ErrorHandler {
4351

@@ -60,31 +68,23 @@ public void apply(@NonNull Context ctx, @NonNull Throwable cause, @NonNull Statu
6068
Map<String, List<ConstraintViolation<?>>> groupedByPath = violations.stream()
6169
.collect(groupingBy(violation -> violation.getPropertyPath().toString()));
6270

63-
List<FieldError> fieldErrors = collectFieldErrors(groupedByPath);
64-
List<String> objectErrors = collectObjectErrors(groupedByPath);
71+
List<ValidationResult.Error> errors = collectErrors(groupedByPath);
6572

66-
Errors errors = new Errors(objectErrors, fieldErrors);
6773
ValidationResult result = new ValidationResult(title, statusCode.value(), errors);
6874
ctx.setResponseCode(statusCode).render(result);
6975
}
7076

71-
private List<FieldError> collectFieldErrors(Map<String, List<ConstraintViolation<?>>> groupedViolations) {
72-
List<FieldError> fieldErrors = new ArrayList<>();
77+
private List<ValidationResult.Error> collectErrors(Map<String, List<ConstraintViolation<?>>> groupedViolations) {
78+
List<ValidationResult.Error> errors = new ArrayList<>();
7379
for (Map.Entry<String, List<ConstraintViolation<?>>> entry : groupedViolations.entrySet()) {
74-
var field = entry.getKey();
75-
if (!ROOT_VIOLATIONS_PATH.equals(field)) {
76-
fieldErrors.add(new FieldError(field, extractMessages(entry.getValue())));
80+
var path = entry.getKey();
81+
if (ROOT_VIOLATIONS_PATH.equals(path)) {
82+
errors.add(new ValidationResult.Error(null, extractMessages(entry.getValue()), GLOBAL));
83+
} else {
84+
errors.add(new ValidationResult.Error(path, extractMessages(entry.getValue()), FIELD));
7785
}
7886
}
79-
return fieldErrors;
80-
}
81-
82-
private List<String> collectObjectErrors(Map<String, List<ConstraintViolation<?>>> groupedViolations) {
83-
List<ConstraintViolation<?>> violations = groupedViolations.get(ROOT_VIOLATIONS_PATH);
84-
if (violations != null) {
85-
return extractMessages(violations);
86-
}
87-
return List.of();
87+
return errors;
8888
}
8989

9090
private List<String> extractMessages(List<ConstraintViolation<?>> violations) {

modules/jooby-jakarta-validation/src/main/java/io/jooby/validation/Errors.java

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

modules/jooby-jakarta-validation/src/main/java/io/jooby/validation/FieldError.java

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
package io.jooby.validation;
22

3-
public record ValidationResult(String title, int status, Errors errors) {
3+
import java.util.List;
4+
5+
public record ValidationResult(String title, int status, List<Error> errors) {
6+
public record Error(String field, List<String> messages, ErrorType type) {
7+
}
8+
9+
public enum ErrorType {
10+
FIELD, GLOBAL
11+
}
412
}

modules/jooby-jakarta-validation/src/test/java/io/jooby/validation/BeanValidatorTest.java

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,16 @@ public void validate_personBean_shouldDetect2Violations() {
4545
.statusCode(UNPROCESSABLE_ENTITY_CODE)
4646
.extract().as(ValidationResult.class);
4747

48-
var fieldError = new FieldError(
48+
var fieldError = new ValidationResult.Error(
4949
"firstName",
50-
List.of("must not be empty", "must not be null")
50+
List.of("must not be empty", "must not be null"),
51+
ValidationResult.ErrorType.FIELD
5152
);
52-
ValidationResult expectedResult = buildResult(new Errors(List.of(), List.of(fieldError)));
53+
ValidationResult expectedResult = buildResult(List.of(fieldError));
5354

5455
Assertions.assertThat(expectedResult)
5556
.usingRecursiveComparison()
56-
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.fieldErrors\\.messages")
57+
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.messages")
5758
.isEqualTo(actualResult);
5859
}
5960

@@ -71,15 +72,16 @@ public void validate_arrayOfPerson_shouldDetect2Violations() {
7172
.statusCode(UNPROCESSABLE_ENTITY_CODE)
7273
.extract().as(ValidationResult.class);
7374

74-
var fieldError = new FieldError(
75+
var fieldError = new ValidationResult.Error(
7576
"firstName",
76-
List.of("must not be empty", "must not be null")
77+
List.of("must not be empty", "must not be null"),
78+
ValidationResult.ErrorType.FIELD
7779
);
78-
ValidationResult expectedResult = buildResult(new Errors(List.of(), List.of(fieldError)));
80+
ValidationResult expectedResult = buildResult(List.of(fieldError));
7981

8082
Assertions.assertThat(expectedResult)
8183
.usingRecursiveComparison()
82-
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.fieldErrors\\.messages")
84+
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.messages")
8385
.isEqualTo(actualResult);
8486
}
8587

@@ -97,15 +99,16 @@ public void validate_listOfPerson_shouldDetect2Violations() {
9799
.statusCode(UNPROCESSABLE_ENTITY_CODE)
98100
.extract().as(ValidationResult.class);
99101

100-
var fieldError = new FieldError(
102+
var fieldError = new ValidationResult.Error(
101103
"firstName",
102-
List.of("must not be empty", "must not be null")
104+
List.of("must not be empty", "must not be null"),
105+
ValidationResult.ErrorType.FIELD
103106
);
104-
ValidationResult expectedResult = buildResult(new Errors(List.of(), List.of(fieldError)));
107+
ValidationResult expectedResult = buildResult( List.of(fieldError));
105108

106109
Assertions.assertThat(expectedResult)
107110
.usingRecursiveComparison()
108-
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.fieldErrors\\.messages")
111+
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.messages")
109112
.isEqualTo(actualResult);
110113
}
111114

@@ -123,15 +126,16 @@ public void validate_mapOfPerson_shouldDetect2Violations() {
123126
.statusCode(UNPROCESSABLE_ENTITY_CODE)
124127
.extract().as(ValidationResult.class);
125128

126-
var fieldError = new FieldError(
129+
var fieldError = new ValidationResult.Error(
127130
"firstName",
128-
List.of("must not be empty", "must not be null")
131+
List.of("must not be empty", "must not be null"),
132+
ValidationResult.ErrorType.FIELD
129133
);
130-
ValidationResult expectedResult = buildResult(new Errors(List.of(), List.of(fieldError)));
134+
ValidationResult expectedResult = buildResult(List.of(fieldError));
131135

132136
Assertions.assertThat(expectedResult)
133137
.usingRecursiveComparison()
134-
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.fieldErrors\\.messages")
138+
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.messages")
135139
.isEqualTo(actualResult);
136140
}
137141

@@ -152,37 +156,44 @@ public void validate_newAccountBean_shouldDetect6Violations() {
152156
.statusCode(UNPROCESSABLE_ENTITY_CODE)
153157
.extract().as(ValidationResult.class);
154158

155-
List<FieldError> fieldErrors = new ArrayList<>() {{
156-
add(new FieldError(
159+
List<ValidationResult.Error> errors = new ArrayList<>() {{
160+
add(new ValidationResult.Error(
161+
null,
162+
List.of("Passwords should match"),
163+
ValidationResult.ErrorType.GLOBAL)
164+
);
165+
add(new ValidationResult.Error(
157166
"person.firstName",
158-
List.of("must not be empty", "must not be null"))
167+
List.of("must not be empty", "must not be null"),
168+
ValidationResult.ErrorType.FIELD)
159169
);
160-
add(new FieldError(
170+
add(new ValidationResult.Error(
161171
"login",
162-
List.of("size must be between 3 and 16"))
172+
List.of("size must be between 3 and 16"),
173+
ValidationResult.ErrorType.FIELD)
163174
);
164-
add(new FieldError(
175+
add(new ValidationResult.Error(
165176
"password",
166-
List.of("size must be between 8 and 24"))
177+
List.of("size must be between 8 and 24"),
178+
ValidationResult.ErrorType.FIELD)
167179
);
168-
add(new FieldError(
180+
add(new ValidationResult.Error(
169181
"confirmPassword",
170-
List.of("size must be between 8 and 24"))
182+
List.of("size must be between 8 and 24"),
183+
ValidationResult.ErrorType.FIELD)
171184
);
172185
}};
173186

174-
String objectErrors = "Passwords should match";
175-
Errors errors = new Errors(List.of(objectErrors), fieldErrors);
176187
ValidationResult expectedResult = buildResult(errors);
177188

178189
Assertions.assertThat(expectedResult)
179190
.usingRecursiveComparison()
180-
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.fieldErrors")
181-
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.fieldErrors\\.messages")
191+
.ignoringCollectionOrderInFieldsMatchingRegexes("errors")
192+
.ignoringCollectionOrderInFieldsMatchingRegexes("errors\\.messages")
182193
.isEqualTo(actualResult);
183194
}
184195

185-
private ValidationResult buildResult(Errors errors) {
196+
private ValidationResult buildResult(List<ValidationResult.Error> errors) {
186197
return new ValidationResult(DEFAULT_TITLE, UNPROCESSABLE_ENTITY_CODE, errors);
187198
}
188199
}

0 commit comments

Comments
 (0)