Repository navigation
Expand file tree
/
Copy pathExpValidation.java
More file actions
135 lines (113 loc) · 5.58 KB
/
Copy pathExpValidation.java
File metadata and controls
135 lines (113 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
// Simula @Validated en @ConfigurationProperties.
// Spring Boot usa Hibernate Validator (JSR-380) para validar el POJO al arrancar.
// Si hay violaciones, lanza BindValidationException antes de que la app inicie.
public class ExpValidation {
// ── Anotaciones de validación JSR-380 (simuladas) ─────────────────────────
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotBlank {
String message() default "no debe estar vacío";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Min {
int value();
String message() default "debe ser >= {value}";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Max {
int value();
String message() default "debe ser <= {value}";
}
// ── Excepción de binding ──────────────────────────────────────────────────
static class BindException extends RuntimeException {
private final List<String> violations;
BindException(List<String> violations) {
super("Configuración inválida: " + violations.size() + " violación(es)");
this.violations = violations;
}
List<String> getViolations() { return violations; }
}
// ── POJO de configuración ─────────────────────────────────────────────────
// @ConfigurationProperties(prefix = "server")
// @Validated
static class ServerProperties {
@NotBlank
String host;
@Min(1) @Max(65535)
int port;
@NotBlank
String contextPath;
@Min(1) @Max(200)
int maxConnections;
ServerProperties(String host, int port, String contextPath, int maxConnections) {
this.host = host;
this.port = port;
this.contextPath = contextPath;
this.maxConnections = maxConnections;
}
}
// ── Validador ─────────────────────────────────────────────────────────────
static class ConfigValidator {
static List<String> validate(Object config) throws IllegalAccessException {
List<String> violations = new ArrayList<>();
for (Field field : config.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object value = field.get(config);
String fieldName = field.getName();
if (field.isAnnotationPresent(NotBlank.class)) {
if (value == null || value.toString().isBlank()) {
violations.add(fieldName + ": " + field.getAnnotation(NotBlank.class).message());
}
}
if (field.isAnnotationPresent(Min.class)) {
int min = field.getAnnotation(Min.class).value();
int actual = value instanceof Number ? ((Number) value).intValue() : 0;
if (actual < min) {
violations.add(fieldName + ": debe ser >= " + min + " (actual: " + actual + ")");
}
}
if (field.isAnnotationPresent(Max.class)) {
int max = field.getAnnotation(Max.class).value();
int actual = value instanceof Number ? ((Number) value).intValue() : 0;
if (actual > max) {
violations.add(fieldName + ": debe ser <= " + max + " (actual: " + actual + ")");
}
}
}
return violations;
}
// Lanza BindException si hay violaciones — Spring lo hace al arrancar
static void validateAndThrow(Object config) throws IllegalAccessException {
List<String> violations = validate(config);
if (!violations.isEmpty()) throw new BindException(violations);
}
}
public static void main(String[] args) throws Exception {
System.out.println("=== Configuración válida ===");
ServerProperties valid = new ServerProperties("localhost", 8080, "/api", 50);
ConfigValidator.validateAndThrow(valid);
System.out.println(" Sin violaciones — bean registrado correctamente");
System.out.println("\n=== Configuración con múltiples violaciones ===");
// port=0 viola @Min(1), contextPath="" viola @NotBlank, maxConnections=999 viola @Max(200)
ServerProperties invalid = new ServerProperties("", 0, "", 999);
try {
ConfigValidator.validateAndThrow(invalid);
} catch (BindException e) {
System.out.println(" " + e.getMessage());
e.getViolations().forEach(v -> System.out.println(" - " + v));
}
System.out.println("\n=== En Spring Boot ===");
System.out.println(" @Validated + @ConfigurationProperties → todas las violaciones");
System.out.println(" se reportan juntas antes del inicio, no una a una.");
System.out.println(" Añadir spring-boot-starter-validation al pom.xml activa JSR-380.");
}
}