Skip to content

Commit e96fe03

Browse files
authored
Merge pull request #5 from JavaWebStack/feature/annotations
Add annotations, so you don't have to use the ugly @rule syntax thing
2 parents 92742eb + ef287dc commit e96fe03

20 files changed

+527
-290
lines changed

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

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.javawebstack.abstractdata.AbstractNull;
88
import org.javawebstack.validator.rule.*;
99

10+
import java.lang.annotation.Annotation;
1011
import java.lang.reflect.Constructor;
1112
import java.lang.reflect.Field;
1213
import java.lang.reflect.InvocationTargetException;
@@ -19,30 +20,35 @@ public class Validator {
1920
private static final Map<String, Constructor<? extends ValidationRule>> validationRules = new HashMap<>();
2021
private static final Map<Class<?>, Validator> validators = new HashMap<>();
2122

23+
private static final Map<Class<? extends ValidationRule>, Class<? extends Annotation>> ruleAnnotationClasses = new HashMap<>();
24+
2225
static {
23-
registerRuleType("string", StringRule.class);
24-
registerRuleType("boolean", BooleanRule.class);
25-
registerRuleType("bool", BooleanRule.class);
26-
registerRuleType("enum", EnumRule.class);
27-
registerRuleType("required", RequiredRule.class);
28-
registerRuleType("req", RequiredRule.class);
29-
registerRuleType("ipv4", IPv4AddressRule.class);
30-
registerRuleType("ipv6", IPv6AddressRule.class);
31-
registerRuleType("int", IntegerRule.class);
32-
registerRuleType("integer", IntegerRule.class);
33-
registerRuleType("numeric", NumericRule.class);
34-
registerRuleType("num", NumericRule.class);
35-
registerRuleType("date", DateRule.class);
36-
registerRuleType("array", ArrayRule.class);
37-
registerRuleType("list", ArrayRule.class);
38-
registerRuleType("alpha", AlphaRule.class);
39-
registerRuleType("alpha_num", AlphaNumRule.class);
40-
registerRuleType("alpha_dash", AlphaDashRule.class);
41-
registerRuleType("email", EmailRule.class);
42-
registerRuleType("regex", RegexRule.class);
26+
registerRuleType("string", StringRule.Validator.class, StringRule.class);
27+
registerRuleType("boolean", BooleanRule.Validator.class, BooleanRule.class);
28+
registerRuleType("bool", BooleanRule.Validator.class, BooleanRule.class);
29+
registerRuleType("enum", EnumRule.Validator.class, EnumRule.class);
30+
registerRuleType("required", RequiredRule.Validator.class, RequiredRule.class);
31+
registerRuleType("req", RequiredRule.Validator.class, RequiredRule.class);
32+
registerRuleType("ipv4", IPv4AddressRule.Validator.class, IPv4AddressRule.class);
33+
registerRuleType("ipv6", IPv6AddressRule.Validator.class, IPv6AddressRule.class);
34+
registerRuleType("int", IntegerRule.Validator.class, IntegerRule.class);
35+
registerRuleType("integer", IntegerRule.Validator.class, IntegerRule.class);
36+
registerRuleType("numeric", NumericRule.Validator.class, NumericRule.class);
37+
registerRuleType("num", NumericRule.Validator.class, NumericRule.class);
38+
registerRuleType("date", DateRule.Validator.class, DateRule.class);
39+
registerRuleType("array", ArrayRule.Validator.class, ArrayRule.class);
40+
registerRuleType("list", ArrayRule.Validator.class, ArrayRule.class);
41+
registerRuleType("alpha", AlphaRule.Validator.class, AlphaRule.class);
42+
registerRuleType("alpha_num", AlphaNumRule.Validator.class, AlphaNumRule.class);
43+
registerRuleType("alpha_dash", AlphaDashRule.Validator.class, AlphaDashRule.class);
44+
registerRuleType("email", EmailRule.Validator.class, EmailRule.class);
45+
registerRuleType("regex", RegexRule.Validator.class, RegexRule.class);
46+
registerRuleType("uuid", UUIDRule.Validator.class, UUIDRule.class);
4347
}
4448

45-
public static void registerRuleType(String name, Class<? extends ValidationRule> type) {
49+
public static void registerRuleType(String name, Class<? extends ValidationRule> type, Class<? extends Annotation> annotationClass) {
50+
if (!ruleAnnotationClasses.containsKey(type) && annotationClass != null)
51+
ruleAnnotationClasses.put(type, annotationClass);
4652
try {
4753
Constructor<? extends ValidationRule> constructor = type.getDeclaredConstructor(String[].class);
4854
constructor.setAccessible(true);
@@ -296,31 +302,31 @@ private static Map<String[], ValidationConfig> getClassRules(Field field, Class<
296302
if (type.equals(Long.class))
297303
return rules;
298304
if (type.equals(Timestamp.class) || type.equals(java.util.Date.class)) {
299-
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new DateRule(new String[]{}))));
305+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new DateRule.Validator(new String[]{}))));
300306
return rules;
301307
}
302308
if (type.equals(Date.class)) {
303-
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new DateRule(new String[]{"date"}))));
309+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new DateRule.Validator(new String[]{"date"}))));
304310
return rules;
305311
}
306312
if (type.equals(Boolean.class)) {
307-
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new BooleanRule())));
313+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new BooleanRule.Validator())));
308314
return rules;
309315
}
310316
if (type.equals(Integer.class)) {
311-
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new IntegerRule(Integer.MIN_VALUE, Integer.MAX_VALUE))));
317+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new IntegerRule.Validator(Integer.MIN_VALUE, Integer.MAX_VALUE))));
312318
return rules;
313319
}
314320
if (type.equals(Double.class) || type.equals(Float.class)) {
315-
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new NumericRule())));
321+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new NumericRule.Validator())));
316322
return rules;
317323
}
318324
if (type.equals(UUID.class)) {
319-
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new UUIDRule())));
325+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new UUIDRule.Validator())));
320326
return rules;
321327
}
322328
if (type.isEnum()) {
323-
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new EnumRule((Class<? extends Enum<?>>) type))));
329+
rules.put(new String[0], new ValidationConfig(field, Collections.singletonList(new EnumRule.Validator((Class<? extends Enum<?>>) type))));
324330
return rules;
325331
}
326332
if (type.isArray()) {
@@ -352,6 +358,19 @@ private static Map<String[], ValidationConfig> getClassRules(Field field, Class<
352358
if (r.size() > 0)
353359
addMapRules(f, rules, new String[]{name}, r);
354360
}
361+
ruleAnnotationClasses.entrySet().stream().distinct().forEach(annotation -> {
362+
Annotation a = f.getDeclaredAnnotation(annotation.getValue());
363+
if (a != null) {
364+
List<ValidationRule> r = new ArrayList<>();
365+
try {
366+
Constructor<ValidationRule> constructor = (Constructor<ValidationRule>) annotation.getKey().getDeclaredConstructor(annotation.getValue());
367+
constructor.setAccessible(true);
368+
r.add(constructor.newInstance(a));
369+
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ignored) {}
370+
if (r.size() > 0)
371+
addMapRules(f, rules, new String[]{name}, r);
372+
}
373+
});
355374
}
356375
return rules;
357376
}

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,32 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.ValidationContext;
55

6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
610
import java.lang.reflect.Field;
711

812
/**
913
* Rule: alpha_dash
1014
*/
11-
public class AlphaDashRule implements ValidationRule {
12-
@Override
13-
public String validate(ValidationContext context, Field field, AbstractElement value) {
14-
if (value == null || value.isNull())
15-
return null;
15+
@Target(ElementType.FIELD)
16+
@Retention(RetentionPolicy.RUNTIME)
17+
public @interface AlphaDashRule {
18+
class Validator implements ValidationRule {
19+
public Validator(AlphaDashRule rule) {}
20+
public Validator() {}
21+
22+
@Override
23+
public String validate(ValidationContext context, Field field, AbstractElement value) {
24+
if (value == null || value.isNull())
25+
return null;
1626

17-
String pattern = "[A-Za-z0-9-_]*";
18-
if (!value.string().matches(pattern))
19-
return "Value must only contain alpha-numeric characters as well as dashes and underscores.";
27+
String pattern = "[A-Za-z0-9-_]*";
28+
if (!value.string().matches(pattern))
29+
return "Value must only contain alpha-numeric characters as well as dashes and underscores.";
2030

21-
return null;
31+
return null;
32+
}
2233
}
2334
}

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,32 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.ValidationContext;
55

6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
610
import java.lang.reflect.Field;
711

812
/**
913
* Rule: alpha_num
1014
*/
11-
public class AlphaNumRule implements ValidationRule {
12-
@Override
13-
public String validate(ValidationContext context, Field field, AbstractElement value) {
14-
if (value == null || value.isNull())
15-
return null;
15+
@Target(ElementType.FIELD)
16+
@Retention(RetentionPolicy.RUNTIME)
17+
public @interface AlphaNumRule {
18+
class Validator implements ValidationRule {
19+
public Validator(AlphaNumRule rule) {}
20+
public Validator() {}
21+
22+
@Override
23+
public String validate(ValidationContext context, Field field, AbstractElement value) {
24+
if (value == null || value.isNull())
25+
return null;
1626

17-
String pattern = "[A-Za-z0-9]*";
18-
if (!value.string().matches(pattern))
19-
return "Value must only contain alpha-numeric characters.";
27+
String pattern = "[A-Za-z0-9]*";
28+
if (!value.string().matches(pattern))
29+
return "Value must only contain alpha-numeric characters.";
2030

21-
return null;
31+
return null;
32+
}
2233
}
2334
}

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,32 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.ValidationContext;
55

6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
610
import java.lang.reflect.Field;
711

812
/**
913
* Rule: alpha
1014
*/
11-
public class AlphaRule implements ValidationRule {
12-
@Override
13-
public String validate(ValidationContext context, Field field, AbstractElement value) {
14-
if (value == null || value.isNull())
15-
return null;
15+
@Target(ElementType.FIELD)
16+
@Retention(RetentionPolicy.RUNTIME)
17+
public @interface AlphaRule {
18+
class Validator implements ValidationRule {
19+
public Validator(AlphaRule rule) {}
20+
public Validator() {}
21+
22+
@Override
23+
public String validate(ValidationContext context, Field field, AbstractElement value) {
24+
if (value == null || value.isNull())
25+
return null;
1626

17-
String pattern = "[A-Za-z]*";
18-
if (!value.string().matches(pattern))
19-
return "Value must only contain alphabetic characters.";
27+
String pattern = "[A-Za-z]*";
28+
if (!value.string().matches(pattern))
29+
return "Value must only contain alphabetic characters.";
2030

21-
return null;
31+
return null;
32+
}
2233
}
2334
}

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

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,55 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.ValidationContext;
55

6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
610
import java.lang.reflect.Field;
711

812
/**
913
* Rule: array, list
1014
*/
11-
public class ArrayRule implements ValidationRule {
12-
13-
private final int min;
14-
private final int max;
15-
16-
public ArrayRule(int min, int max) {
17-
this.min = min;
18-
this.max = max;
19-
}
20-
21-
public ArrayRule(String[] params) {
22-
int min = 0;
23-
int max = Integer.MAX_VALUE;
24-
if (params.length > 0)
25-
min = Integer.parseInt(params[0]);
26-
if (params.length > 1)
27-
max = Integer.parseInt(params[1]);
28-
this.min = min;
29-
this.max = max;
30-
}
31-
32-
public String validate(ValidationContext context, Field field, AbstractElement value) {
33-
if (value == null || value.isNull())
15+
@Target(ElementType.FIELD)
16+
@Retention(RetentionPolicy.RUNTIME)
17+
public @interface ArrayRule {
18+
int min();
19+
int max();
20+
21+
class Validator implements ValidationRule {
22+
private final int min;
23+
private final int max;
24+
25+
public Validator(ArrayRule rule) {
26+
this(rule.min(), rule.max());
27+
}
28+
29+
public Validator(int min, int max) {
30+
this.min = min;
31+
this.max = max;
32+
}
33+
34+
public Validator(String[] params) {
35+
int min = 0;
36+
int max = Integer.MAX_VALUE;
37+
if (params.length > 0)
38+
min = Integer.parseInt(params[0]);
39+
if (params.length > 1)
40+
max = Integer.parseInt(params[1]);
41+
this.min = min;
42+
this.max = max;
43+
}
44+
45+
public String validate(ValidationContext context, Field field, AbstractElement value) {
46+
if (value == null || value.isNull())
47+
return null;
48+
if (!value.isArray())
49+
return "Not an array";
50+
if (value.array().size() < min)
51+
return String.format("Shorter than minimum array length (%d < %d)", value.array().size(), min);
52+
if (value.array().size() > max)
53+
return String.format("Longer than maximum array length (%d > %d)", value.array().size(), max);
3454
return null;
35-
if (!value.isArray())
36-
return "Not an array";
37-
if (value.array().size() < min)
38-
return String.format("Shorter than minimum array length (%d < %d)", value.array().size(), min);
39-
if (value.array().size() > max)
40-
return String.format("Longer than maximum array length (%d > %d)", value.array().size(), max);
41-
return null;
55+
}
4256
}
43-
4457
}

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

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,31 @@
33
import org.javawebstack.abstractdata.AbstractElement;
44
import org.javawebstack.validator.ValidationContext;
55

6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
610
import java.lang.reflect.Field;
711

812
/**
913
* Rule: boolean, bool
1014
*/
11-
public class BooleanRule implements ValidationRule {
12-
public String validate(ValidationContext context, Field field, AbstractElement value) {
13-
if (value == null || value.isNull())
14-
return null;
15-
if (value.isBoolean())
16-
return null;
17-
if (value.isString() && (value.string().equals("true") || value.string().equals("false")))
18-
return null;
19-
return "Not a boolean value";
15+
@Target(ElementType.FIELD)
16+
@Retention(RetentionPolicy.RUNTIME)
17+
public @interface BooleanRule {
18+
class Validator implements ValidationRule {
19+
public Validator(BooleanRule rule) {}
20+
21+
public Validator() {}
22+
23+
public String validate(ValidationContext context, Field field, AbstractElement value) {
24+
if (value == null || value.isNull())
25+
return null;
26+
if (value.isBoolean())
27+
return null;
28+
if (value.isString() && (value.string().equals("true") || value.string().equals("false")))
29+
return null;
30+
return "Not a boolean value";
31+
}
2032
}
2133
}

0 commit comments

Comments
 (0)