Skip to content

Commit d790ed0

Browse files
committed
Merge branch 'feature-validator'
2 parents 5991317 + d53a4c0 commit d790ed0

File tree

12 files changed

+482
-15
lines changed

12 files changed

+482
-15
lines changed

summer-validator/src/main/java/com/dianpoint/summer/validator/ValidationRules.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.dianpoint.summer.validator;
22

3+
import java.util.*;
4+
35
/**
46
* @author: congccoder
57
* @email: congccoder@gmail.com | <a href="https://github.com/ccoderJava">github-homepage</a>
@@ -42,4 +44,45 @@ public static ValidationRule<Integer> max(int value) {
4244
ValidationResult.failure("不能大于" + value, "integer");
4345
}
4446

47+
//设置collections相关的校验规则
48+
public static <C extends Collection<?>> ValidationRule<C> minsize(int min) {
49+
return collection -> collection != null && collection.size() >= min ?
50+
ValidationResult.success() :
51+
ValidationResult.failure("集合大小不能小于" + min, "collection");
52+
}
53+
54+
public static <C extends Collection<?>> ValidationRule<C> maxSize(int max) {
55+
return collection -> collection != null && collection.size() <= max ?
56+
ValidationResult.success() :
57+
ValidationResult.failure("集合大小不能大于" + max, "collection");
58+
}
59+
60+
public static <C extends Collection<?>> ValidationRule<C> range(int min, int max) {
61+
return collection -> collection != null && collection.size() >= min && collection.size() <= max ?
62+
ValidationResult.success() :
63+
ValidationResult.failure(String.format("集合大小必须在[%s,%s]之间", min, max), "collection");
64+
}
65+
66+
public static <E, C extends Collection<E>> ValidationRule<C> uniqueElements() {
67+
return collection -> {
68+
if (collection == null) {
69+
return ValidationResult.success();
70+
}
71+
Set<E> uniqueSet = new LinkedHashSet<>();
72+
List<E> duplicates = new ArrayList<>();
73+
74+
for (E element : collection) {
75+
if (!uniqueSet.add(element)) {
76+
//set中添加失败代表元素element已经存在
77+
duplicates.add(element);
78+
}
79+
}
80+
return duplicates.isEmpty() ?
81+
ValidationResult.success() :
82+
ValidationResult.failure("集合中包含重复元素" + duplicates, "collection");
83+
84+
};
85+
}
86+
87+
4588
}

summer-validator/src/main/java/com/dianpoint/summer/validator/Validators.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import com.dianpoint.summer.validator.validator.AnnotationValidatorAdapter;
44
import com.dianpoint.summer.validator.validator.GenericValidator;
55
import com.dianpoint.summer.validator.validator.Validator;
6+
import com.dianpoint.summer.validator.validator.collection.CollectionValidator;
7+
import com.dianpoint.summer.validator.validator.collection.DefaultCollectionValidator;
68

9+
import java.util.Collection;
10+
import java.util.List;
711
import java.util.Objects;
812
import java.util.function.Predicate;
913

@@ -44,5 +48,12 @@ public static <T> Validator<T> annotated(Class<T> targetClass) {
4448
return AnnotationValidatorAdapter.create(targetClass);
4549
}
4650

51+
//针对collection创建校验器
52+
53+
public static <E, C extends Collection<E>> CollectionValidator<E, C> collection(Class<C> collectionType, Class<E> elementType) {
54+
return new DefaultCollectionValidator<>(collectionType, elementType);
55+
}
56+
57+
//重载一下list 和set两种collection的校验器
4758

4859
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.dianpoint.summer.validator.annotations;
2+
3+
import java.lang.annotation.*;
4+
5+
/**
6+
* @author: congccoder
7+
* @email: congccoder@gmail.com | <a href="https://github.com/ccoderJava">github-homepage</a>
8+
* @date: 2025/5/22 21:30
9+
*/
10+
@Target(ElementType.TYPE)
11+
@Retention(RetentionPolicy.RUNTIME)
12+
public @interface HandlesAnnotation {
13+
14+
Class<? extends Annotation> value();
15+
}

summer-validator/src/main/java/com/dianpoint/summer/validator/annotations/NotNull.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
* @date: 2025/5/20 21:10
1212
*/
1313

14-
@Retention(RetentionPolicy.RUNTIME)
15-
@Target({ElementType.FIELD, ElementType.TYPE})
14+
@HandlesAnnotation(value = NotNull.class)
1615
public @interface NotNull {
1716

1817
String message() default "不能为空";

summer-validator/src/main/java/com/dianpoint/summer/validator/annotations/Pattern.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
* @date: 2025/5/20 21:11
1212
*/
1313

14-
@Retention(RetentionPolicy.RUNTIME)
15-
@Target({ElementType.FIELD, ElementType.TYPE})
14+
@HandlesAnnotation(value = Pattern.class)
1615
public @interface Pattern {
1716

1817
String regex();

summer-validator/src/main/java/com/dianpoint/summer/validator/processor/AnnotationProcessorRegister.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package com.dianpoint.summer.validator.processor;
22

3+
import com.dianpoint.summer.validator.annotations.HandlesAnnotation;
34
import com.dianpoint.summer.validator.annotations.NotNull;
45
import com.dianpoint.summer.validator.annotations.Pattern;
56
import com.dianpoint.summer.validator.constraintvalidators.NotNullProcessor;
67
import com.dianpoint.summer.validator.constraintvalidators.PatternProcessor;
8+
import com.dianpoint.summer.validator.utils.ClassScanner;
79

810
import java.lang.annotation.Annotation;
11+
import java.lang.reflect.Modifier;
912
import java.util.HashMap;
1013
import java.util.Map;
14+
import java.util.Set;
1115

1216
/**
1317
* @author: congccoder
@@ -19,11 +23,6 @@ public class AnnotationProcessorRegister {
1923

2024
private static final Map<Class<? extends Annotation>, AnnotationProcessor> PROCESSORS = new HashMap<>();
2125

22-
static {
23-
PROCESSORS.put(NotNull.class, new NotNullProcessor());
24-
PROCESSORS.put(Pattern.class, new PatternProcessor());
25-
}
26-
2726
public static void register(Class<? extends Annotation> annotationType, AnnotationProcessor annotationProcessor) {
2827
PROCESSORS.put(annotationType, annotationProcessor);
2928
}
@@ -36,5 +35,26 @@ public static boolean hasProcessor(Class<? extends Annotation> annotationType) {
3635
return PROCESSORS.containsKey(annotationType);
3736
}
3837

38+
public static void scanAndRegisterAnnotationProcessor(String packageName) {
39+
try {
40+
ClassScanner classScanner = new ClassScanner();
41+
Set<Class<?>> classes = classScanner.scan(packageName);
42+
for (Class<?> clazz : classes) {
43+
if (AnnotationProcessor.class.isAssignableFrom(clazz) &&
44+
!Modifier.isAbstract(clazz.getModifiers())) {
45+
46+
HandlesAnnotation annotation = clazz.getAnnotation(HandlesAnnotation.class);
47+
if (annotation != null) {
48+
AnnotationProcessor handler = (AnnotationProcessor) clazz.getDeclaredConstructor().newInstance();
49+
register(annotation.value(), handler);
50+
}
51+
}
52+
}
53+
} catch (Exception e) {
54+
throw new RuntimeException("扫描注解处理器失败", e);
55+
56+
}
57+
}
58+
3959

4060
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.dianpoint.summer.validator.utils;
2+
3+
import com.dianpoint.summer.validator.ValidationResult;
4+
import com.dianpoint.summer.validator.processor.AnnotationProcessor;
5+
import com.dianpoint.summer.validator.processor.AnnotationProcessorRegister;
6+
7+
import java.lang.annotation.Annotation;
8+
import java.lang.reflect.Field;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
/**
13+
* @author: congccoder
14+
* @email: congccoder@gmail.com | <a href="https://github.com/ccoderJava">github-homepage</a>
15+
* @date: 2025/5/22 21:18
16+
*/
17+
18+
public class AnnotationProcessingUtils {
19+
20+
static {
21+
// 初始化时扫描并注册所有处理器
22+
AnnotationProcessorRegister.scanAndRegisterAnnotationProcessor("com.dianpoint.summer.validator");
23+
}
24+
25+
// 处理对象上的校验注解
26+
public static <T> List<ValidationResult> processAnnotations(T object) {
27+
if (object == null) {
28+
return java.util.Collections.singletonList(
29+
ValidationResult.failure("校验对象不能为null", "object"));
30+
}
31+
32+
List<ValidationResult> results = new ArrayList<>();
33+
Class<?> clazz = object.getClass();
34+
35+
// 处理类上的所有字段
36+
for (Field field : clazz.getDeclaredFields()) {
37+
field.setAccessible(true);
38+
results.addAll(processAnnotationsOnField(object, field));
39+
}
40+
41+
return results;
42+
}
43+
44+
private static List<ValidationResult> processAnnotationsOnField(Object target, Field field) {
45+
List<ValidationResult> results = new ArrayList<>();
46+
47+
for (Annotation annotation : field.getAnnotations()) {
48+
// 处理直接注解
49+
results.addAll(processAnnotation(target, field, annotation));
50+
51+
// 处理组合注解(注解上的注解)
52+
results.addAll(processMetaAnnotations(target, field, annotation));
53+
}
54+
55+
return results;
56+
}
57+
58+
private static List<ValidationResult> processAnnotation(Object target, Field field, Annotation annotation) {
59+
Class<? extends Annotation> annotationType = annotation.annotationType();
60+
AnnotationProcessor handler = AnnotationProcessorRegister.getProcessor(annotationType);
61+
62+
if (handler != null) {
63+
return handler.process(target, field, annotation);
64+
}
65+
66+
return java.util.Collections.emptyList();
67+
}
68+
69+
private static List<ValidationResult> processMetaAnnotations(Object target, Field field, Annotation annotation) {
70+
List<ValidationResult> results = new ArrayList<>();
71+
72+
// 获取注解上的元注解
73+
for (Annotation metaAnnotation : annotation.annotationType().getAnnotations()) {
74+
if (metaAnnotation.annotationType().getPackage().getName().startsWith("java.lang")) {
75+
continue; // 跳过Java内置注解
76+
}
77+
78+
results.addAll(processAnnotation(target, field, metaAnnotation));
79+
results.addAll(processMetaAnnotations(target, field, metaAnnotation));
80+
}
81+
82+
return results;
83+
}
84+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.dianpoint.summer.validator.utils;
2+
3+
import java.io.File;
4+
import java.net.URL;
5+
import java.util.HashSet;
6+
import java.util.Set;
7+
8+
/**
9+
* @author: congccoder
10+
* @email: congccoder@gmail.com | <a href="https://github.com/ccoderJava">github-homepage</a>
11+
* @date: 2025/5/22 21:21
12+
*/
13+
14+
public class ClassScanner {
15+
16+
public Set<Class<?>> scan(String packageName) {
17+
18+
Set<Class<?>> classes = new HashSet<>();
19+
String path = packageName.replace('.', '/');
20+
try {
21+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
22+
URL resource = classLoader.getResource(path);
23+
if (resource == null) {
24+
return classes;
25+
}
26+
File directory = new File(resource.getFile());
27+
if (directory.exists()) {
28+
for (File file : directory.listFiles()) {
29+
if (file.isDirectory()) {
30+
classes.addAll(scan(packageName + "." + file.getName()));
31+
} else if (file.getName().endsWith(".class")) {
32+
String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
33+
classes.add(Class.forName(className));
34+
}
35+
}
36+
}
37+
} catch (Exception e) {
38+
throw new RuntimeException("扫描失败", e);
39+
}
40+
return classes;
41+
}
42+
}

summer-validator/src/main/java/com/dianpoint/summer/validator/validator/AnnotationValidatorAdapter.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import com.dianpoint.summer.validator.ValidationResult;
55
import com.dianpoint.summer.validator.ValidationRule;
6+
import com.dianpoint.summer.validator.utils.AnnotationProcessingUtils;
67

78
import java.util.Collections;
89
import java.util.List;
@@ -44,8 +45,17 @@ public Validator<T> addRule(Predicate<T> condition, String errorMessage, String
4445

4546
@Override
4647
public List<ValidationResult> validate(T target) {
47-
//TODO 处理注解类校验
48-
return Collections.emptyList();
48+
if (target == null) {
49+
return java.util.Collections.singletonList(
50+
ValidationResult.failure("校验对象不能为null", "object"));
51+
}
52+
List<ValidationResult> results = AnnotationProcessingUtils.processAnnotations(target);
53+
54+
if (skipOnFirstFailure && !results.isEmpty()) {
55+
return java.util.Collections.singletonList(results.get(0));
56+
}
57+
58+
return results;
4959
}
5060

5161
@Override

0 commit comments

Comments
 (0)