Skip to content

Commit 36150ce

Browse files
committed
Added field to Validator to allow more advanced validation
1 parent d3d72e3 commit 36150ce

File tree

13 files changed

+90
-47
lines changed

13 files changed

+90
-47
lines changed

src/main/java/org/javawebstack/validator/Validator.java

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public static Validator getValidator(Class<?> type){
9797
Validator validator = validators.get(type);
9898
if(validator == null){
9999
validator = new Validator();
100-
getClassRules(type).forEach(validator::rule);
100+
getClassRules(null, type).forEach(validator::rule);
101101
validators.put(type, validator);
102102
}
103103
return validator;
@@ -115,14 +115,19 @@ public static <T> T map(Class<T> type, AbstractElement element){
115115
return map(type, element, new AbstractMapper());
116116
}
117117

118-
private final Map<String[], List<ValidationRule>> rules = new HashMap<>();
118+
private final Map<String[], ValidationConfig> rules = new HashMap<>();
119119

120120
public Validator rule(String[] key, ValidationRule... rules){
121121
return rule(key, Arrays.asList(rules));
122122
}
123123

124124
public Validator rule(String[] key, List<ValidationRule> rules){
125-
this.rules.put(key, rules);
125+
this.rules.put(key, new ValidationConfig(null, rules));
126+
return this;
127+
}
128+
129+
private Validator rule(String[] key, ValidationConfig config){
130+
this.rules.put(key, config);
126131
return this;
127132
}
128133

@@ -142,11 +147,12 @@ public ValidationResult validate(AbstractElement rootElement){
142147
return new ValidationResult(errors);
143148
}
144149

145-
private Map<String[], List<String>> check(Map<String[], List<ValidationRule>> rules, String[] keyPrefix, String[] resolvedKeyPrefix, String[] key, AbstractElement element){
150+
private Map<String[], List<String>> check(Map<String[], ValidationConfig> rules, String[] keyPrefix, String[] resolvedKeyPrefix, String[] key, AbstractElement element){
146151
if(key.length == 0){
147152
Map<String[], List<String>> errors = new HashMap<>();
148-
for(ValidationRule rule : getMapValue(rules, keyPrefix)){
149-
String error = rule.validate(this, element);
153+
ValidationConfig config = getMapValue(rules, keyPrefix);
154+
for(ValidationRule rule : config.rules){
155+
String error = rule.validate(this, config.field, element);
150156
if(error != null){
151157
if(!errors.containsKey(resolvedKeyPrefix))
152158
errors.put(resolvedKeyPrefix, new ArrayList<>());
@@ -220,7 +226,7 @@ private static <V> V getMapValue(Map<String[], V> map, String[] key){
220226
return null;
221227
}
222228

223-
private static <V> void putMapValue(Map<String[], Object> map, String[] key, Object value){
229+
private static <V> void putValidationConfigMapValue(Map<String[], ValidationConfig> map, String[] key, ValidationConfig value) {
224230
for(String[] k : map.keySet()){
225231
if(stringArrayEqual(k, key)){
226232
map.put(k, value);
@@ -230,12 +236,12 @@ private static <V> void putMapValue(Map<String[], Object> map, String[] key, Obj
230236
map.put(key, value);
231237
}
232238

233-
private static <V> void addMapListEntryValue(Map map, String[] key, List values){
234-
List<Object> list = (List<Object>) getMapValue(map, key);
235-
if(list == null)
236-
list = new ArrayList<>();
237-
list.addAll(values);
238-
putMapValue(map, key, list);
239+
private static void addMapRules(Field field, Map<String[], ValidationConfig> map, String[] key, List<ValidationRule> rules) {
240+
ValidationConfig config = getMapValue(map, key);
241+
if(config == null)
242+
config = new ValidationConfig(field, new ArrayList<>());
243+
config.rules.addAll(rules);
244+
putValidationConfigMapValue(map, key, config);
239245
}
240246

241247
private static String toSnakeCase(String source){
@@ -260,55 +266,64 @@ private static String getFieldName(Field field){
260266
return toSnakeCase(field.getName());
261267
}
262268

263-
private static Map<String[], List<ValidationRule>> getClassRules(Class<?> type){
264-
Map<String[], List<ValidationRule>> rules = new HashMap<>();
269+
private static class ValidationConfig {
270+
private final Field field;
271+
private final List<ValidationRule> rules;
272+
public ValidationConfig(Field field, List<ValidationRule> rules) {
273+
this.field = field;
274+
this.rules = rules;
275+
}
276+
}
277+
278+
private static Map<String[], ValidationConfig> getClassRules(Field field, Class<?> type){
279+
Map<String[], ValidationConfig> rules = new HashMap<>();
265280
if(type.isAnnotation())
266281
return rules;
267282
if(type.equals(String.class))
268283
return rules;
269284
if(type.equals(Timestamp.class) || type.equals(java.util.Date.class)){
270-
rules.put(new String[0], Collections.singletonList(new DateRule(new String[]{})));
285+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new DateRule(new String[]{}))));
271286
return rules;
272287
}
273288
if(type.equals(Date.class)){
274-
rules.put(new String[0], Collections.singletonList(new DateRule(new String[]{"date"})));
289+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new DateRule(new String[]{"date"}))));
275290
return rules;
276291
}
277292
if(type.equals(Boolean.class)){
278-
rules.put(new String[0], Collections.singletonList(new BooleanRule()));
293+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new BooleanRule())));
279294
return rules;
280295
}
281296
if(type.equals(Integer.class)){
282-
rules.put(new String[0], Collections.singletonList(new IntegerRule(Integer.MIN_VALUE, Integer.MAX_VALUE)));
297+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new IntegerRule(Integer.MIN_VALUE, Integer.MAX_VALUE))));
283298
return rules;
284299
}
285300
if(type.equals(UUID.class)){
286-
rules.put(new String[0], Collections.singletonList(new UUIDRule()));
301+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new UUIDRule())));
287302
return rules;
288303
}
289304
if(type.isEnum()){
290-
rules.put(new String[0], Collections.singletonList(new EnumRule((Class<? extends Enum<?>>) type)));
305+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new EnumRule((Class<? extends Enum<?>>) type))));
291306
return rules;
292307
}
293308
if(type.isArray()){
294-
getClassRules(type.getComponentType()).forEach((key, validators) -> {
309+
getClassRules(null, type.getComponentType()).forEach((key, validators) -> {
295310
String[] actualKey = new String[key.length+1];
296311
actualKey[0] = "*";
297312
System.arraycopy(key, 0, actualKey, 1, key.length);
298-
addMapListEntryValue(rules, actualKey, validators);
313+
addMapRules(null, rules, actualKey, validators.rules);
299314
});
300315
return rules;
301316
}
302-
for(Field field : getFieldsRecursive(type)){
303-
String name = getFieldName(field);
304-
getClassRules(field.getType()).forEach((key, validators) -> {
317+
for(Field f : getFieldsRecursive(type)){
318+
String name = getFieldName(f);
319+
getClassRules(f, f.getType()).forEach((key, validators) -> {
305320
String[] actualKey = new String[key.length+1];
306321
actualKey[0] = name;
307322
System.arraycopy(key, 0, actualKey, 1, key.length);
308-
addMapListEntryValue(rules, actualKey, validators);
323+
addMapRules(f, rules, actualKey, validators.rules);
309324
});
310-
field.setAccessible(true);
311-
Rule[] ruleAnnotations = field.getDeclaredAnnotationsByType(Rule.class);
325+
f.setAccessible(true);
326+
Rule[] ruleAnnotations = f.getDeclaredAnnotationsByType(Rule.class);
312327
if(ruleAnnotations.length > 0){
313328
List<ValidationRule> r = new ArrayList<>();
314329
for(String source : ruleAnnotations[0].value()){
@@ -317,7 +332,7 @@ private static Map<String[], List<ValidationRule>> getClassRules(Class<?> type){
317332
r.add(rule);
318333
}
319334
if(r.size() > 0)
320-
addMapListEntryValue(rules, new String[]{name}, r);
335+
addMapRules(f, rules, new String[]{name}, r);
321336
}
322337
}
323338
return rules;

src/main/java/org/javawebstack/validator/rule/ArrayRule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
7+
68
public class ArrayRule implements ValidationRule {
79

810
private final int min;
@@ -24,7 +26,7 @@ public ArrayRule(String[] params){
2426
this.max = max;
2527
}
2628

27-
public String validate(Validator validator, AbstractElement value) {
29+
public String validate(Validator validator, Field field, AbstractElement value) {
2830
if(value == null)
2931
return null;
3032
if(!value.isArray())

src/main/java/org/javawebstack/validator/rule/BooleanRule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
7+
68
public class BooleanRule implements ValidationRule {
7-
public String validate(Validator validator, AbstractElement value) {
9+
public String validate(Validator validator, Field field, AbstractElement value) {
810
if(value == null)
911
return null;
1012
if(value.isBoolean())

src/main/java/org/javawebstack/validator/rule/DateRule.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package org.javawebstack.validator.rule;
22

33
import org.javawebstack.abstractdata.AbstractElement;
4-
import org.javawebstack.abstractdata.AbstractMapper;
54
import org.javawebstack.validator.Validator;
65

6+
import java.lang.reflect.Field;
77
import java.text.DateFormat;
88
import java.text.SimpleDateFormat;
99

1010
public class DateRule implements ValidationRule {
11-
private DateFormat dateFormat;
11+
12+
private final DateFormat dateFormat;
1213

1314
public DateRule(DateFormat dateFormat){
1415
this.dateFormat = dateFormat;
@@ -28,8 +29,16 @@ public DateRule(String[] params){
2829
}
2930
}
3031

31-
public String validate(Validator validator, AbstractElement value) {
32-
32+
public String validate(Validator validator, Field field, AbstractElement value) {
33+
if(value == null || value.isNull())
34+
return null;
35+
if(!value.isString())
36+
return "Not a valid date";
37+
try {
38+
dateFormat.parse(value.string());
39+
} catch (Exception ex) {
40+
return "Not a valid date";
41+
}
3342
return null;
3443
}
3544
}

src/main/java/org/javawebstack/validator/rule/EnumRule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
67
import java.util.Arrays;
78
import java.util.List;
89
import java.util.stream.Collectors;
@@ -18,7 +19,7 @@ public EnumRule(String... values){
1819
public EnumRule(Class<? extends Enum<?>> enumType){
1920
this(Arrays.stream(enumType.getEnumConstants()).map(Enum::name).collect(Collectors.toList()));
2021
}
21-
public String validate(Validator validator, AbstractElement value) {
22+
public String validate(Validator validator, Field field, AbstractElement value) {
2223
if(value == null)
2324
return null;
2425
return value.isString() && values.contains(value.string()) ? null : String.format("Not an element of [%s]", String.join(",", values));

src/main/java/org/javawebstack/validator/rule/IPv4AddressRule.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
7+
68
public class IPv4AddressRule extends RegexRule {
79

810
public IPv4AddressRule() {
911
super("((([01][0-9]{0,2})|(2[0-4][0-9])|(25[0-5])))(\\.(?1)){3}");
1012
}
1113

12-
public String validate(Validator validator, AbstractElement value) {
13-
return super.validate(validator, value) == null ? null : "Not a valid IPv4 Address";
14+
public String validate(Validator validator, Field field, AbstractElement value) {
15+
return super.validate(validator, field, value) == null ? null : "Not a valid IPv4 Address";
1416
}
1517
}

src/main/java/org/javawebstack/validator/rule/IPv6AddressRule.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
7+
68
public class IPv6AddressRule extends RegexRule {
79
public IPv6AddressRule() {
810
super("([0-9a-fA-F]{1,4})(:(?1)){7}");
911
}
1012

11-
public String validate(Validator validator, AbstractElement value) {
12-
return super.validate(validator, value) == null ? null : "Not a valid IPv6 Address";
13+
public String validate(Validator validator, Field field, AbstractElement value) {
14+
return super.validate(validator, field, value) == null ? null : "Not a valid IPv6 Address";
1315
}
1416
}

src/main/java/org/javawebstack/validator/rule/IntegerRule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
7+
68
public class IntegerRule implements ValidationRule {
79

810
private final int min;
@@ -34,7 +36,7 @@ public IntegerRule(String[] params){
3436
this.step = step;
3537
}
3638

37-
public String validate(Validator validator, AbstractElement value) {
39+
public String validate(Validator validator, Field field, AbstractElement value) {
3840
if(value == null)
3941
return null;
4042
int v;

src/main/java/org/javawebstack/validator/rule/RegexRule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
67
import java.util.regex.Pattern;
78

89
public class RegexRule implements ValidationRule {
@@ -12,7 +13,7 @@ public RegexRule(String regex){
1213
this.regex = regex;
1314
this.pattern = Pattern.compile(regex);
1415
}
15-
public String validate(Validator validator, AbstractElement value) {
16+
public String validate(Validator validator, Field field, AbstractElement value) {
1617
if(value == null)
1718
return null;
1819
return value.isString() && pattern.matcher(value.string()).matches() ? null : "Doesn't match the expected pattern";

src/main/java/org/javawebstack/validator/rule/RequiredRule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.Validator;
55

6+
import java.lang.reflect.Field;
7+
68
public class RequiredRule implements ValidationRule {
7-
public String validate(Validator validator, AbstractElement value) {
9+
public String validate(Validator validator, Field field, AbstractElement value) {
810
return value != null ? null : "Missing required field";
911
}
1012
}

0 commit comments

Comments
 (0)