commit d6ea3c61dc4f077b81a9885b9ea0661e8a16bc90 Author: Hua Date: Sat Jul 20 14:34:56 2024 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/git_toolbox_blame.xml b/.idea/git_toolbox_blame.xml new file mode 100644 index 0000000..7dc1249 --- /dev/null +++ b/.idea/git_toolbox_blame.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..cd717f9 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d59bbc2 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f04a10f --- /dev/null +++ b/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.hua + utils + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + 5.2.1.RELEASE + 5.8.26 + 0.9.10 + 2.0.1.Final + + + + + + org.springframework + spring-context + ${springContext.version} + + + cn.hutool + hutool-all + ${hutool.version} + + + org.reflections + reflections + ${reflections.version} + + + javax.validation + validation-api + ${validation.version} + + + + \ No newline at end of file diff --git a/src/main/java/com/hua/annotation/Handles.java b/src/main/java/com/hua/annotation/Handles.java new file mode 100644 index 0000000..a07725f --- /dev/null +++ b/src/main/java/com/hua/annotation/Handles.java @@ -0,0 +1,13 @@ +package com.hua.annotation; + +import java.lang.annotation.*; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Handles { + Class value(); +} diff --git a/src/main/java/com/hua/test/valid/Student.java b/src/main/java/com/hua/test/valid/Student.java new file mode 100644 index 0000000..62e5a1d --- /dev/null +++ b/src/main/java/com/hua/test/valid/Student.java @@ -0,0 +1,42 @@ +package com.hua.test.valid; + +import com.hua.valid.annotation.ConditionNotNull; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +public class Student { + + @ConditionNotNull(test = "teaName == '王老师' and teaAge == 28 and teaSex == 1", message = "老师名字为王老师,年龄为18,性别为1的时候 name不能为null") + private String name; + + private int age; + + private int sex; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public int getSex() { + return sex; + } + + public void setSex(int sex) { + this.sex = sex; + } +} diff --git a/src/main/java/com/hua/test/valid/Teach.java b/src/main/java/com/hua/test/valid/Teach.java new file mode 100644 index 0000000..51b9943 --- /dev/null +++ b/src/main/java/com/hua/test/valid/Teach.java @@ -0,0 +1,56 @@ +package com.hua.test.valid; + +import com.hua.valid.annotation.ValidPlus; + +import javax.validation.Valid; +import java.util.List; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +@ValidPlus +public class Teach { + + private String teaName; + private int teaAge; + + + private int teaSex; + + @Valid + private List listStu; + + + public String getTeaName() { + return teaName; + } + + public void setTeaName(String teaName) { + this.teaName = teaName; + } + + public int getTeaAge() { + return teaAge; + } + + public void setTeaAge(int teaAge) { + this.teaAge = teaAge; + } + + public int getTeaSex() { + return teaSex; + } + + public void setTeaSex(int teaSex) { + this.teaSex = teaSex; + } + + public List getListStu() { + return listStu; + } + + public void setListStu(List listStu) { + this.listStu = listStu; + } +} diff --git a/src/main/java/com/hua/test/valid/Test.java b/src/main/java/com/hua/test/valid/Test.java new file mode 100644 index 0000000..51d3c3d --- /dev/null +++ b/src/main/java/com/hua/test/valid/Test.java @@ -0,0 +1,49 @@ +package com.hua.test.valid; + +import com.hua.valid.AnnotationHandleFactory; +import com.hua.valid.ErrorMessage; +import com.hua.valid.HandleDTO; + +import java.util.List; + +public class Test { + public static void main(String[] args) { + Teach teach = init(); + + ErrorMessage errorMessage = new ErrorMessage(); + if (!AnnotationHandleFactory.handle(new HandleDTO.HandleDTOBuilder() + .setOriginObj(teach) + .setAnnotations(teach.getListStu().get(0).getClass().getDeclaredFields()[0].getAnnotations()) + .setField(teach.getListStu().get(0).getClass().getDeclaredFields()[0]) + .setFieldValue(teach.getListStu().get(0).getName()) + .setErrorMessage(errorMessage) + .build())) { + System.out.println("验证失败: " + errorMessage.getErrorMessage()); + } else { + System.out.println("验证成功"); + } + } + + + public static Teach init() { + Student student = new Student(); + student.setName("张同学"); + student.setAge(18); + student.setSex(1); + + Student student1 = new Student(); + student1.setName(null); + student1.setAge(19); + student1.setSex(2); + Teach teach = new Teach(); + teach.setTeaAge(28); + teach.setTeaName("王老师"); + teach.setTeaSex(1); + + List student11 = List.of(student1, student); + teach.setListStu(student11); + return teach; + } + + +} diff --git a/src/main/java/com/hua/valid/AnnotationHandleFactory.java b/src/main/java/com/hua/valid/AnnotationHandleFactory.java new file mode 100644 index 0000000..44d2ca4 --- /dev/null +++ b/src/main/java/com/hua/valid/AnnotationHandleFactory.java @@ -0,0 +1,147 @@ +package com.hua.valid; + +import cn.hutool.core.util.ArrayUtil; +import com.hua.annotation.Handles; +import com.hua.valid.annotation.PackageScanConfig; +import org.reflections.Reflections; +import org.reflections.scanners.SubTypesScanner; +import org.reflections.scanners.TypeAnnotationsScanner; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.function.Consumer; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +public class AnnotationHandleFactory { + + // 缓存已加载的注解处理器 + private static final Map, AnnotationHandler> cache = new HashMap<>(); + private static boolean useSPI = true; // 是否使用SPI加载处理器 + private static boolean useReflection = false; // 是否使用反射加载处理器 + private static String[] packagesToScan = {"com.hua.valid"}; // 反射扫描的包路径 + + // 静态初始化块,在类加载时进行处理器初始化 + static { + resolvePackageConfig(); + initializeHandlers(); + } + + /** + * 配置处理器加载方式和扫描路径。 + * + * @param useSpi 是否使用SPI加载处理器。 + * @param useRef 是否使用反射加载处理器。 + * @param packages 反射扫描的包路径。 + */ + public static void configure(boolean useSpi, boolean useRef, String[] packages) { + useSPI = useSpi; + useReflection = useRef; + packagesToScan = packages; + cache.clear(); // 清除缓存 + initializeHandlers(); // 重新初始化处理器 + } + + private static void resolvePackageConfig() { + Reflections reflections = new Reflections(new ConfigurationBuilder() + .setUrls(ClasspathHelper.forJavaClassPath()) + .setScanners(new TypeAnnotationsScanner(), new SubTypesScanner())); + + // 查找所有应用了PackageScanConfig注解的类 + Set> configClasses = reflections.getTypesAnnotatedWith(PackageScanConfig.class); + if (configClasses.isEmpty()) { + return; + } + PackageScanConfig config = configClasses.stream().findFirst().get().getAnnotation(PackageScanConfig.class); + useSPI = config.useSPI(); + useReflection = config.useReflection(); + packagesToScan = config.packages(); + } + + // 初始化处理器,根据配置决定使用SPI或反射加载 + private static void initializeHandlers() { + if (useSPI) { + loadHandlersViaSPI(); + } + if (useReflection) { + loadHandlersViaReflection(); + } + } + + // 通过SPI加载注解处理器 + private static void loadHandlersViaSPI() { + ServiceLoader loadedHandlers = ServiceLoader.load(AnnotationHandler.class); + loadedHandlers.forEach(handler -> { + Handles handles = handler.getClass().getAnnotation(Handles.class); + if (handles != null) { + cache.put(handles.value(), handler); + } + }); + } + + // 通过反射加载注解处理器 + private static void loadHandlersViaReflection() { + // 单独的方法用于加载处理器 + Consumer loadHandlers = (reflections) -> { + reflections.getTypesAnnotatedWith(Handles.class).forEach(cls -> { + try { + AnnotationHandler handler = (AnnotationHandler) cls.getDeclaredConstructor().newInstance(); + Handles handlesAnnotation = cls.getAnnotation(Handles.class); + cache.put(handlesAnnotation.value(), handler); + } catch (ReflectiveOperationException e) { + // 推荐使用日志记录异常,而非仅仅打印堆栈信息 + e.printStackTrace(); + } + }); + }; + + if (ArrayUtil.isEmpty(packagesToScan)) { + Reflections reflections = new Reflections(new ConfigurationBuilder() + .setUrls(ClasspathHelper.forJavaClassPath()) + .setScanners(new TypeAnnotationsScanner(), new SubTypesScanner())); + loadHandlers.accept(reflections); + } else { + for (String pkg : packagesToScan) { + Reflections reflections = new Reflections(new ConfigurationBuilder() + .forPackages(pkg) + .setScanners(new SubTypesScanner(), new TypeAnnotationsScanner())); + loadHandlers.accept(reflections); + } + } + } + + + /** + * 根据注解类型获取对应的处理器。 + * + * @param annotation 注解实例。 + * @return 对应的注解处理器,如果未找到返回null。 + */ + public static AnnotationHandler getHandler(Annotation annotation) { + return cache.get(annotation.annotationType()); + } + + /** + * 处理给定的注解数据对象。 + * + * @param handleDTO 包含注解信息的数据传输对象。 + * @return 处理结果,成功或失败。 + */ + public static boolean handle(HandleDTO handleDTO) { + for (Annotation annotation : handleDTO.getAnnotations()) { + AnnotationHandler handler = getHandler(annotation); + if (handler != null) { + handleDTO.setCurrentAnnotation(annotation); + return handler.handle(handleDTO); + } + } + return true; + } +} diff --git a/src/main/java/com/hua/valid/AnnotationHandler.java b/src/main/java/com/hua/valid/AnnotationHandler.java new file mode 100644 index 0000000..bddfa16 --- /dev/null +++ b/src/main/java/com/hua/valid/AnnotationHandler.java @@ -0,0 +1,5 @@ +package com.hua.valid; + +public interface AnnotationHandler { + boolean handle(HandleDTO handleDTO); +} \ No newline at end of file diff --git a/src/main/java/com/hua/valid/ConditionNotNullHandler.java b/src/main/java/com/hua/valid/ConditionNotNullHandler.java new file mode 100644 index 0000000..4f8e2f9 --- /dev/null +++ b/src/main/java/com/hua/valid/ConditionNotNullHandler.java @@ -0,0 +1,32 @@ +package com.hua.valid; + +import cn.hutool.core.util.StrUtil; +import com.hua.annotation.Handles; +import com.hua.valid.annotation.ConditionNotNull; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +@Handles(ConditionNotNull.class) +public class ConditionNotNullHandler implements AnnotationHandler { + @Override + public boolean handle(HandleDTO handleDTO) { + ConditionNotNull conditionValidate = (ConditionNotNull) handleDTO.getCurrentAnnotation(); + String test = conditionValidate.test(); + if (StrUtil.isEmpty(test)) { + return true; + } + ExpressionParser parser = new SpelExpressionParser(); + + Boolean value = parser.parseExpression(test).getValue(handleDTO.getOriginObj(), Boolean.class); + if (Boolean.TRUE.equals(value) && handleDTO.getFieldValue() == null) { + handleDTO.getErrorMessage().addErrorObj(conditionValidate.message(), handleDTO.getField()); + return false; + } + + return true; + } +} diff --git a/src/main/java/com/hua/valid/ConditionValidateImpl.java b/src/main/java/com/hua/valid/ConditionValidateImpl.java new file mode 100644 index 0000000..f0a3280 --- /dev/null +++ b/src/main/java/com/hua/valid/ConditionValidateImpl.java @@ -0,0 +1,69 @@ +package com.hua.valid; + +import cn.hutool.core.util.ReflectUtil; +import com.hua.valid.annotation.ValidPlus; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Valid; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.List; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +public class ConditionValidateImpl implements ConstraintValidator { + + @Override + public void initialize(ValidPlus constraintAnnotation) { + + } + + @Override + public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) { + ErrorMessage errorMessage = new ErrorMessage(); + validObj(o, errorMessage, o); + if(errorMessage.isError()) { + constraintValidatorContext.disableDefaultConstraintViolation(); + constraintValidatorContext.buildConstraintViolationWithTemplate(errorMessage.getErrorMessage()).addConstraintViolation(); + return false; + } + + return true; + } + + private void validObj(Object o, ErrorMessage errorMessage, Object originObj) { + + if (o instanceof List list) { + for (Object obj : list) { + validObj(obj, errorMessage,originObj); + } + return; + } + Field[] fields = ReflectUtil.getFields(o.getClass()); + for (Field field : fields) { + Valid annotation = field.getAnnotation(Valid.class); + if (annotation != null) { + validObj(ReflectUtil.getFieldValue(o,field),errorMessage, originObj); + } + Annotation[] annotations = field.getAnnotations(); + if (annotations == null || annotations.length == 0) { + continue; + } + Object fieldValue = ReflectUtil.getFieldValue(o, field); + Annotation formatAnnotation = field.getAnnotation(ValidPlus.class); + if (formatAnnotation == null) { + throw new RuntimeException("Format annotation is missing on the field."); + } + HandleDTO handleDTO = new HandleDTO.HandleDTOBuilder().setOriginObj(originObj) + .setAnnotations(annotations) + .setAnnotations(annotations) + .setField(field) + .setErrorMessage(errorMessage) + .setFieldValue(fieldValue).build(); + AnnotationHandleFactory.handle(handleDTO); + } + } +} diff --git a/src/main/java/com/hua/valid/ErrorMessage.java b/src/main/java/com/hua/valid/ErrorMessage.java new file mode 100644 index 0000000..993a75e --- /dev/null +++ b/src/main/java/com/hua/valid/ErrorMessage.java @@ -0,0 +1,57 @@ +package com.hua.valid; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +public class ErrorMessage { + + private final List listErrorObj = new ArrayList<>(); + + public void addErrorObj(String errorMessage, Field errorField){ + ErrorObj errorObj = new ErrorObj(errorMessage, errorField); + listErrorObj.add(errorObj); + + } + + public boolean isError() { + return listErrorObj.size() > 0; + } + + public String getErrorMessage(){ + return listErrorObj.stream().map(ErrorObj::getErrorMessage).collect(Collectors.joining(",")); + } + + + public static class ErrorObj{ + private String errorMessage; + + private Field errorField; + + public ErrorObj(String errorMessage, Field errorField) { + this.errorMessage = errorMessage; + this.errorField = errorField; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public Field getErrorField() { + return errorField; + } + + public void setErrorField(Field errorField) { + this.errorField = errorField; + } + } +} diff --git a/src/main/java/com/hua/valid/HandleDTO.java b/src/main/java/com/hua/valid/HandleDTO.java new file mode 100644 index 0000000..7715a18 --- /dev/null +++ b/src/main/java/com/hua/valid/HandleDTO.java @@ -0,0 +1,128 @@ +package com.hua.valid; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +public class HandleDTO { + + /** + * 要验证的实体类的原始值(有可能 实体类里面嵌套实体的情况) + */ + private Object originObj; + + /** + * 属性上加的所有的注解 + */ + private Annotation[] annotations; + + /** + * 当前要处理的注解 + */ + private Annotation currentAnnotation; + /** + * 加注解的那个字段 + */ + private Field field; + /** + * 错误信息 + */ + private ErrorMessage errorMessage; + /** + * 加注解的那个字段值 + */ + private Object fieldValue; + + public Object getOriginObj() { + return originObj; + } + + public void setOriginObj(Object originObj) { + this.originObj = originObj; + } + + public Annotation[] getAnnotations() { + return annotations; + } + + public void setAnnotations(Annotation[] annotations) { + this.annotations = annotations; + } + + public Field getField() { + return field; + } + + public void setField(Field field) { + this.field = field; + } + + public ErrorMessage getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(ErrorMessage errorMessage) { + this.errorMessage = errorMessage; + } + + public Object getFieldValue() { + return fieldValue; + } + + public void setFieldValue(Object fieldValue) { + this.fieldValue = fieldValue; + } + + public Annotation getCurrentAnnotation() { + return currentAnnotation; + } + + public void setCurrentAnnotation(Annotation currentAnnotation) { + this.currentAnnotation = currentAnnotation; + } + + public static class HandleDTOBuilder { + private final HandleDTO handleDTO; + + public HandleDTOBuilder() { + handleDTO = new HandleDTO(); + } + + public HandleDTOBuilder setOriginObj(Object originObj) { + handleDTO.setOriginObj(originObj); + return this; + } + + public HandleDTOBuilder setAnnotations(Annotation[] annotations) { + handleDTO.setAnnotations(annotations); + return this; + } + + public HandleDTOBuilder setField(Field field) { + handleDTO.setField(field); + return this; + } + + public HandleDTOBuilder setErrorMessage(ErrorMessage errorMessage) { + handleDTO.setErrorMessage(errorMessage); + return this; + } + + public HandleDTOBuilder setFieldValue(Object fieldValue) { + handleDTO.setFieldValue(fieldValue); + return this; + } + + public HandleDTOBuilder setCurrentAnnotation(Annotation currentAnnotation) { + handleDTO.setCurrentAnnotation(currentAnnotation); + return this; + } + + public HandleDTO build() { + return handleDTO; + } + } +} diff --git a/src/main/java/com/hua/valid/annotation/ConditionNotNull.java b/src/main/java/com/hua/valid/annotation/ConditionNotNull.java new file mode 100644 index 0000000..7be7d09 --- /dev/null +++ b/src/main/java/com/hua/valid/annotation/ConditionNotNull.java @@ -0,0 +1,16 @@ +package com.hua.valid.annotation; + +import java.lang.annotation.*; + +/** + * @author Hua + * @since 2024/7/18 下午2:42 + */ +@Documented +@Target({ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ConditionNotNull { + String test() default ""; + + String message() default ""; +} diff --git a/src/main/java/com/hua/valid/annotation/PackageScanConfig.java b/src/main/java/com/hua/valid/annotation/PackageScanConfig.java new file mode 100644 index 0000000..a5499a2 --- /dev/null +++ b/src/main/java/com/hua/valid/annotation/PackageScanConfig.java @@ -0,0 +1,14 @@ +package com.hua.valid.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) // 类或接口上使用 +@Retention(RetentionPolicy.RUNTIME) // 在运行时可见 +public @interface PackageScanConfig { + boolean useSPI() default false; // 默认为空数组 + boolean useReflection() default false; // 默认为空数组 + String[] packages() default {}; // 默认为空数组 +} diff --git a/src/main/java/com/hua/valid/annotation/ValidPlus.java b/src/main/java/com/hua/valid/annotation/ValidPlus.java new file mode 100644 index 0000000..33e3098 --- /dev/null +++ b/src/main/java/com/hua/valid/annotation/ValidPlus.java @@ -0,0 +1,21 @@ +package com.hua.valid.annotation; + +import com.hua.valid.ConditionValidateImpl; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +/** + * @author Hua + * @since 2024/7/18 下午2:43 + */ +@Documented +@Target({ElementType.PARAMETER, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ConditionValidateImpl.class) +public @interface ValidPlus { + String message() default ""; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/resources/META-INF/services/com.hua.valid.AnnotationHandler b/src/main/resources/META-INF/services/com.hua.valid.AnnotationHandler new file mode 100644 index 0000000..7d98d89 --- /dev/null +++ b/src/main/resources/META-INF/services/com.hua.valid.AnnotationHandler @@ -0,0 +1 @@ +com.hua.valid.ConditionNotNullHandler