Skip to content

Commit 5be51f0

Browse files
committed
add basic validators
1 parent 77c076d commit 5be51f0

6 files changed

Lines changed: 185 additions & 0 deletions

File tree

.idea/encodings.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pom.xml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,56 @@
33
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55

6+
<parent>
7+
<groupId>org.springframework.boot</groupId>
8+
<artifactId>spring-boot-starter-parent</artifactId>
9+
<version>3.3.2</version>
10+
<relativePath/> <!-- lookup parent from repository -->
11+
</parent>
12+
613
<groupId>it.aboutbits</groupId>
714
<artifactId>spring-boot-toolbox</artifactId>
815
<version>BUILD-SNAPSHOT</version>
916
<description>Utility library for Spring Boot projects.</description>
17+
<packaging>jar</packaging>
1018

1119
<properties>
1220
<java.version>21</java.version>
1321
</properties>
1422

1523
<dependencies>
24+
<dependency>
25+
<groupId>org.springframework.boot</groupId>
26+
<artifactId>spring-boot-starter-validation</artifactId>
27+
</dependency>
28+
29+
<!-- Utilities -->
30+
<dependency>
31+
<groupId>org.projectlombok</groupId>
32+
<artifactId>lombok</artifactId>
33+
<optional>true</optional>
34+
</dependency>
35+
36+
<!-- Password validation -->
37+
<!-- https://mvnrepository.com/artifact/org.passay/passay -->
38+
<dependency>
39+
<groupId>org.passay</groupId>
40+
<artifactId>passay</artifactId>
41+
<version>1.6.5</version>
42+
</dependency>
43+
44+
<!-- https://mvnrepository.com/artifact/org.jetbrains/annotations -->
45+
<dependency>
46+
<groupId>org.jetbrains</groupId>
47+
<artifactId>annotations</artifactId>
48+
<version>24.1.0</version>
49+
</dependency>
1650

51+
<!-- Testing -->
52+
<dependency>
53+
<groupId>org.springframework.boot</groupId>
54+
<artifactId>spring-boot-starter-test</artifactId>
55+
</dependency>
1756
</dependencies>
1857

1958
<build>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package it.aboutbits.springboot.toolbox.validation.enumeration;
2+
3+
import jakarta.validation.Constraint;
4+
import jakarta.validation.Payload;
5+
6+
import java.lang.annotation.Documented;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.Target;
9+
10+
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
11+
import static java.lang.annotation.ElementType.FIELD;
12+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
13+
14+
@Documented
15+
@Constraint(validatedBy = ValidEnumValidator.class)
16+
@Target({FIELD, ANNOTATION_TYPE})
17+
@Retention(RUNTIME)
18+
public @interface ValidEnum {
19+
20+
String message() default "{shared.error.validation.invalidEnum}";
21+
22+
Class<?>[] groups() default {};
23+
24+
Class<? extends Payload>[] payload() default {};
25+
26+
Class<? extends Enum<?>> enumClass();
27+
28+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package it.aboutbits.springboot.toolbox.validation.enumeration;
2+
3+
import jakarta.validation.ConstraintValidator;
4+
import jakarta.validation.ConstraintValidatorContext;
5+
6+
import java.util.HashSet;
7+
import java.util.Set;
8+
9+
public class ValidEnumValidator implements ConstraintValidator<ValidEnum, String> {
10+
private Set<String> enumValues;
11+
12+
@Override
13+
public void initialize(ValidEnum validEnum) {
14+
var enumClass = validEnum.enumClass();
15+
16+
enumValues = new HashSet<>();
17+
for (Enum<?> anEnum : enumClass.getEnumConstants()) {
18+
enumValues.add(anEnum.name());
19+
}
20+
}
21+
22+
@Override
23+
public boolean isValid(String value, ConstraintValidatorContext context) {
24+
if (value == null) {
25+
return true;
26+
}
27+
28+
return enumValues.contains(value);
29+
}
30+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package it.aboutbits.springboot.toolbox.validation.password;
2+
3+
import jakarta.validation.Constraint;
4+
import jakarta.validation.Payload;
5+
6+
import java.lang.annotation.Documented;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.Target;
9+
10+
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
11+
import static java.lang.annotation.ElementType.FIELD;
12+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
13+
14+
@Documented
15+
@Constraint(validatedBy = ValidPasswordValidator.class)
16+
@Target({FIELD, ANNOTATION_TYPE})
17+
@Retention(RUNTIME)
18+
public @interface ValidPassword {
19+
String message() default "{shared.error.validation.invalidPassword}";
20+
21+
String lengthMessage() default "{shared.error.validation.invalidPassword.length}";
22+
23+
Class<?>[] groups() default {};
24+
25+
Class<? extends Payload>[] payload() default {};
26+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package it.aboutbits.springboot.toolbox.validation.password;
2+
3+
import jakarta.validation.ConstraintValidator;
4+
import jakarta.validation.ConstraintValidatorContext;
5+
import org.passay.LengthRule;
6+
import org.passay.PasswordData;
7+
import org.passay.PasswordValidator;
8+
import org.passay.RuleResultDetail;
9+
10+
import java.util.List;
11+
12+
public class ValidPasswordValidator implements ConstraintValidator<ValidPassword, String> {
13+
private String message;
14+
private String lengthMessage;
15+
16+
@Override
17+
public void initialize(ValidPassword constraintAnnotation) {
18+
this.message = constraintAnnotation.message();
19+
this.lengthMessage = constraintAnnotation.lengthMessage();
20+
}
21+
22+
@Override
23+
public boolean isValid(String password, ConstraintValidatorContext context) {
24+
if (password == null) {
25+
return true;
26+
}
27+
28+
var validator = new PasswordValidator(List.of(
29+
// at least 8 characters
30+
new LengthRule(8, 50)
31+
));
32+
33+
var result = validator.validate(new PasswordData(password));
34+
35+
if (!password.isBlank() && result.isValid()) {
36+
return true;
37+
}
38+
context.disableDefaultConstraintViolation();
39+
context.buildConstraintViolationWithTemplate(getMessageTemplate(result.getDetails()))
40+
.addConstraintViolation();
41+
42+
return false;
43+
}
44+
45+
private String getMessageTemplate(List<RuleResultDetail> ruleResultDetails) {
46+
if (ruleResultDetails.isEmpty()) {
47+
return message;
48+
}
49+
50+
return switch (ruleResultDetails.getFirst().getErrorCode()) {
51+
case "TOO_SHORT" -> lengthMessage;
52+
case "TOO_LONG" -> lengthMessage;
53+
default -> message;
54+
};
55+
}
56+
}

0 commit comments

Comments
 (0)